Merge branch 'master' into cfg_tmp_dir
Conflicts: src/etc/rustup.sh
This commit is contained in:
commit
0128159c95
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -11,3 +11,6 @@
|
||||
[submodule "src/jemalloc"]
|
||||
path = src/jemalloc
|
||||
url = https://github.com/rust-lang/jemalloc.git
|
||||
[submodule "src/rust-installer"]
|
||||
path = src/rust-installer
|
||||
url = https://github.com/rust-lang/rust-installer
|
||||
|
@ -498,6 +498,7 @@ Robert Irelan <rirelan@gmail.com>
|
||||
Robert Knight <robertknight@gmail.com>
|
||||
Robert Millar <robert.millar@cantab.net>
|
||||
Roland Tanglao <roland@rolandtanglao.com>
|
||||
Rolf Timmermans <r.w.timmermans@gmail.com>
|
||||
Ron Dahlgren <ronald.dahlgren@gmail.com>
|
||||
Roy Frostig <rfrostig@mozilla.com>
|
||||
Russell <rpjohnst@gmail.com>
|
||||
|
@ -198,6 +198,8 @@ include $(CFG_SRC_DIR)mk/rustllvm.mk
|
||||
include $(CFG_SRC_DIR)mk/docs.mk
|
||||
# LLVM
|
||||
include $(CFG_SRC_DIR)mk/llvm.mk
|
||||
# Rules for installing debugger scripts
|
||||
include $(CFG_SRC_DIR)mk/debuggers.mk
|
||||
|
||||
######################################################################
|
||||
# Secondary makefiles, conditionalized for speed
|
||||
|
38
configure
vendored
38
configure
vendored
@ -546,22 +546,26 @@ CFG_TARGET=$(to_llvm_triple $CFG_TARGET)
|
||||
# there's no rpath. This is where the build system itself puts libraries;
|
||||
# --libdir is used to configure the installation directory.
|
||||
# FIXME: This needs to parameterized over target triples. Do it in platform.mk
|
||||
CFG_LIBDIR_RELATIVE=lib
|
||||
if [ "$CFG_OSTYPE" = "pc-windows-gnu" ]
|
||||
then
|
||||
CFG_LIBDIR_RELATIVE=bin
|
||||
CFG_LIBDIR="${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}"
|
||||
else
|
||||
valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries (ignored on windows platform)"
|
||||
CFG_LIBDIR_RELATIVE=lib
|
||||
fi
|
||||
|
||||
case "$CFG_LIBDIR" in
|
||||
"$CFG_PREFIX"/*) CAT_INC=2;;
|
||||
"$CFG_PREFIX"*) CAT_INC=1;;
|
||||
*)
|
||||
err "libdir must begin with the prefix. Use --prefix to set it accordingly.";;
|
||||
esac
|
||||
valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries (do not set it on windows platform)"
|
||||
|
||||
CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-`
|
||||
case "$CFG_LIBDIR" in
|
||||
"$CFG_PREFIX"/*) CAT_INC=2;;
|
||||
"$CFG_PREFIX"*) CAT_INC=1;;
|
||||
*)
|
||||
err "libdir must begin with the prefix. Use --prefix to set it accordingly.";;
|
||||
esac
|
||||
|
||||
CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-`
|
||||
|
||||
if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] && [ "$CFG_LIBDIR_RELATIVE" != "bin" ]; then
|
||||
err "libdir on windows should be set to 'bin'"
|
||||
fi
|
||||
|
||||
if [ $HELP -eq 1 ]
|
||||
@ -620,7 +624,6 @@ probe CFG_LD ld
|
||||
probe CFG_VALGRIND valgrind
|
||||
probe CFG_PERF perf
|
||||
probe CFG_ISCC iscc
|
||||
probe CFG_LLNEXTGEN LLnextgen
|
||||
probe CFG_JAVAC javac
|
||||
probe CFG_ANTLR4 antlr4
|
||||
probe CFG_GRUN grun
|
||||
@ -711,11 +714,6 @@ then
|
||||
fi
|
||||
step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
|
||||
putvar CFG_LOCAL_RUST_ROOT
|
||||
else
|
||||
if [ ! -z "$CFG_LOCAL_RUST_ROOT" ]
|
||||
then
|
||||
warn "Use of --local-rust-root without --enable-local-rust"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Force freebsd to build with clang; gcc doesn't like us there
|
||||
@ -990,8 +988,7 @@ do
|
||||
make_dir $t/rt/jemalloc
|
||||
for i in \
|
||||
isaac sync test \
|
||||
arch/i386 arch/x86_64 arch/arm arch/mips \
|
||||
sundown/src sundown/html
|
||||
arch/i386 arch/x86_64 arch/arm arch/mips
|
||||
do
|
||||
make_dir $t/rt/stage$s/$i
|
||||
done
|
||||
@ -1042,19 +1039,18 @@ do
|
||||
make_dir $h/test/debuginfo-gdb
|
||||
make_dir $h/test/debuginfo-lldb
|
||||
make_dir $h/test/codegen
|
||||
make_dir $h/test/doc-tutorial
|
||||
make_dir $h/test/doc-guide
|
||||
make_dir $h/test/doc-guide-ffi
|
||||
make_dir $h/test/doc-guide-runtime
|
||||
make_dir $h/test/doc-guide-macros
|
||||
make_dir $h/test/doc-guide-lifetimes
|
||||
make_dir $h/test/doc-guide-ownership
|
||||
make_dir $h/test/doc-guide-pointers
|
||||
make_dir $h/test/doc-guide-container
|
||||
make_dir $h/test/doc-guide-tasks
|
||||
make_dir $h/test/doc-guide-plugin
|
||||
make_dir $h/test/doc-guide-crates
|
||||
make_dir $h/test/doc-guide-error-handling
|
||||
make_dir $h/test/doc-rust
|
||||
make_dir $h/test/doc-reference
|
||||
done
|
||||
|
||||
# Configure submodules
|
||||
|
131
man/rustc.1
131
man/rustc.1
@ -12,75 +12,54 @@ This program is a compiler for the Rust language, available at
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
\fB\-\-crate-name NAME\fR
|
||||
Specify the name of the crate being built
|
||||
.TP
|
||||
\fB\-\-crate-type=[bin|lib|dylib|rlib|staticlib]\fR
|
||||
Configure the flavor of rust crate that is generated (default `bin`)
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Display the help message
|
||||
.TP
|
||||
\fB\-\-cfg\fR SPEC
|
||||
Configure the compilation environment
|
||||
.TP
|
||||
\fB\-\-emit=[asm,ir,bc,obj,link]\fR
|
||||
Configure the output that rustc will produce
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Display this message
|
||||
.TP
|
||||
\fB\-L\fR PATH
|
||||
Add a directory to the library search path
|
||||
.TP
|
||||
\fB\-\-no\-trans\fR
|
||||
Run all passes except translation; no output
|
||||
\fB\-l\fR NAME[:KIND]
|
||||
Link the generated crate(s) to the specified native library NAME. The optional
|
||||
KIND can be one of, static, dylib, or framework. If omitted, dylib is assumed.
|
||||
.TP
|
||||
\fB\-\-no\-analysis\fR
|
||||
Parse and expand the source, but run no analysis and produce no output
|
||||
\fB\-\-crate-type\fR [bin|lib|rlib|dylib|staticlib]
|
||||
Comma separated list of types of crates for the compiler to emit
|
||||
.TP
|
||||
\fB\-\-crate-name NAME\fR
|
||||
Specify the name of the crate being built
|
||||
.TP
|
||||
\fB\-\-emit\fR [asm|llvm-bc|llvm-ir|obj|link|dep-info]
|
||||
Configure the output that rustc will produce
|
||||
.TP
|
||||
\fB\-\-print\fR [crate-name|output-file-names|sysroot]
|
||||
Comma separated list of compiler information to print on stdout
|
||||
.TP
|
||||
\fB\-g\fR
|
||||
Emit DWARF debug information into object files generated.
|
||||
.TP
|
||||
\fB\-\-debuginfo\fR LEVEL
|
||||
Emit DWARF debug info to the objects created: 0 = no debug info, 1 =
|
||||
line-tables only (for stacktraces and breakpoints), 2 = full debug
|
||||
info with variable and type information (same as -g).
|
||||
Equivalent to \fI\-C\fR debuginfo=2
|
||||
.TP
|
||||
\fB\-O\fR
|
||||
Equivalent to \fI\-\-opt\-level=2\fR
|
||||
Equivalent to \fI\-C\fR opt-level=2
|
||||
.TP
|
||||
\fB\-o\fR FILENAME
|
||||
Write output to <filename>. Ignored if more than one --emit is specified.
|
||||
.TP
|
||||
\fB\-\-opt\-level\fR LEVEL
|
||||
Optimize with possible levels 0-3
|
||||
Write output to <filename>. Ignored if multiple \fI\-\-emit\fR outputs are
|
||||
specified.
|
||||
.TP
|
||||
\fB\-\-out\-dir\fR DIR
|
||||
Write output to compiler-chosen filename in <dir>. Ignored if -o is specified.
|
||||
(default the current directory)
|
||||
Write output to compiler-chosen filename in <dir>. Ignored if \fI\-o\fR is
|
||||
specified. Defaults to the current directory.
|
||||
.TP
|
||||
\fB\-\-parse\-only\fR
|
||||
Parse only; do not compile, assemble, or link
|
||||
.TP
|
||||
\fB\-\-pretty\fR [TYPE]
|
||||
Pretty-print the input instead of compiling; valid types are: normal
|
||||
(un-annotated source), expanded (crates expanded), typed (crates
|
||||
expanded, with type annotations), identified (fully parenthesized,
|
||||
AST nodes and blocks with IDs), or flowgraph=<nodeid> (graphviz
|
||||
formatted flowgraph for node)
|
||||
.TP
|
||||
\fB\-\-dep-info\fR [FILENAME]
|
||||
Output dependency info to <filename> after compiling, in a format suitable
|
||||
for use by Makefiles.
|
||||
.TP
|
||||
\fB\-\-sysroot\fR PATH
|
||||
Override the system root
|
||||
\fB\-\-explain\fR OPT
|
||||
Provide a detailed explanation of an error message
|
||||
.TP
|
||||
\fB\-\-test\fR
|
||||
Build a test harness
|
||||
.TP
|
||||
\fB\-\-target\fR TRIPLE
|
||||
Target triple cpu-manufacturer-kernel[-os] to compile for (see
|
||||
http://sources.redhat.com/autobook/autobook/autobook_17.html
|
||||
for details)
|
||||
Target triple cpu-manufacturer-kernel[-os] to compile for (see chapter 3.4 of
|
||||
http://www.sourceware.org/autobook/ for details)
|
||||
.TP
|
||||
\fB\-W\fR help
|
||||
Print 'lint' options and default settings
|
||||
@ -97,15 +76,30 @@ Set lint denied
|
||||
\fB\-F\fR OPT, \fB\-\-forbid\fR OPT
|
||||
Set lint forbidden
|
||||
.TP
|
||||
\fB\-Z\fR FLAG
|
||||
Set internal debugging options. Use "-Z help" to print available options.
|
||||
.TP
|
||||
\fB\-C\fR FLAG[=VAL], \fB\-\-codegen\fR FLAG[=VAL]
|
||||
Set a codegen-related flag to the value specified. Use "-C help" to print
|
||||
available flags. See CODEGEN OPTIONS below
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Print version info and exit
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Use verbose output
|
||||
.TP
|
||||
\fB\-\-extern\fR NAME=PATH
|
||||
Specify where an external rust library is located
|
||||
.TP
|
||||
\fB\-\-sysroot\fR PATH
|
||||
Override the system root
|
||||
.TP
|
||||
\fB\-Z\fR FLAG
|
||||
Set internal debugging options. Use "-Z help" to print available options.
|
||||
.TP
|
||||
\fB\-\-color\fR auto|always|never
|
||||
Configure coloring of output:
|
||||
auto = colorize, if output goes to a tty (default);
|
||||
always = always colorize output;
|
||||
never = never colorize output
|
||||
|
||||
.SH CODEGEN OPTIONS
|
||||
|
||||
@ -121,6 +115,9 @@ objects.
|
||||
A space-separated list of extra arguments to pass to the linker when the linker
|
||||
is invoked.
|
||||
.TP
|
||||
\fBlto\fR
|
||||
Perform LLVM link-time optimizations.
|
||||
.TP
|
||||
\fBtarget-cpu\fR=help
|
||||
Selects a target processor. If the value is 'help', then a list of available
|
||||
CPUs is printed.
|
||||
@ -167,8 +164,38 @@ Prefers dynamic linking to static linking.
|
||||
\fBno-integrated-as\fR
|
||||
Force usage of an external assembler rather than LLVM's integrated one.
|
||||
.TP
|
||||
\fBno-redzone\fR
|
||||
Disable the use of the redzone.
|
||||
.TP
|
||||
\fBrelocation-model\fR=[pic,static,dynamic-no-pic]
|
||||
The relocation model to use. (default: pic)
|
||||
The relocation model to use. (Default: pic)
|
||||
.TP
|
||||
\fBcode-model\fR=[small,kernel,medium,large]
|
||||
Choose the code model to use.
|
||||
.TP
|
||||
\fBmetadata\fR=val
|
||||
Metadata to mangle symbol names with.
|
||||
.TP
|
||||
\fBextra-filename\fR=val
|
||||
Extra data to put in each output filename.
|
||||
.TP
|
||||
\fBcodegen-units\fR=val
|
||||
Divide crate into N units to optimize in parallel.
|
||||
.TP
|
||||
\fBremark\fR=val
|
||||
Print remarks for these optimization passes (space separated, or "all").
|
||||
.TP
|
||||
\fBno-stack-check\fR
|
||||
Disable checks for stack exhaustion (a memory-safety hazard!).
|
||||
.TP
|
||||
\fBdebuginfo\fR=val
|
||||
Debug info emission level:
|
||||
0 = no debug info;
|
||||
1 = line-tables only (for stacktraces and breakpoints);
|
||||
2 = full debug info with variable and type information.
|
||||
.TP
|
||||
\fBopt-level\fR=val
|
||||
Optimize with possible levels 0-3
|
||||
|
||||
.SH "EXAMPLES"
|
||||
To build an executable from a source file with a main function:
|
||||
|
@ -63,6 +63,7 @@ clean-generic-$(2)-$(1):
|
||||
-name '*.lib' -o \
|
||||
-name '*.dll' -o \
|
||||
-name '*.def' -o \
|
||||
-name '*.py' -o \
|
||||
-name '*.bc' \
|
||||
\) \
|
||||
| xargs rm -f
|
||||
@ -78,7 +79,7 @@ define CLEAN_HOST_STAGE_N
|
||||
|
||||
clean$(1)_H_$(2): \
|
||||
$$(foreach crate,$$(CRATES),clean$(1)_H_$(2)-lib-$$(crate)) \
|
||||
$$(foreach tool,$$(TOOLS),clean$(1)_H_$(2)-tool-$$(tool))
|
||||
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS),clean$(1)_H_$(2)-tool-$$(tool))
|
||||
$$(Q)rm -fr $(2)/rt/libbacktrace
|
||||
|
||||
clean$(1)_H_$(2)-tool-%:
|
||||
@ -98,7 +99,7 @@ define CLEAN_TARGET_STAGE_N
|
||||
|
||||
clean$(1)_T_$(2)_H_$(3): \
|
||||
$$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
|
||||
$$(foreach tool,$$(TOOLS),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
|
||||
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
|
||||
|
38
mk/crates.mk
38
mk/crates.mk
@ -50,11 +50,12 @@
|
||||
################################################################################
|
||||
|
||||
TARGET_CRATES := libc std flate arena term \
|
||||
serialize sync getopts collections test time rand \
|
||||
log regex graphviz core rbml alloc rustrt \
|
||||
serialize getopts collections test time rand \
|
||||
log regex graphviz core rbml alloc \
|
||||
unicode
|
||||
HOST_CRATES := syntax rustc rustc_trans rustdoc regex_macros fmt_macros \
|
||||
rustc_llvm rustc_back
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm
|
||||
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc regex_macros fmt_macros
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
TOOLS := compiletest rustdoc rustc
|
||||
|
||||
@ -62,17 +63,22 @@ DEPS_core :=
|
||||
DEPS_libc := core
|
||||
DEPS_unicode := core
|
||||
DEPS_alloc := core libc native:jemalloc
|
||||
DEPS_rustrt := alloc core libc collections native:rustrt_native
|
||||
DEPS_std := core libc rand alloc collections rustrt sync unicode \
|
||||
native:rust_builtin native:backtrace
|
||||
DEPS_std := core libc rand alloc collections unicode \
|
||||
native:rust_builtin native:backtrace native:rustrt_native
|
||||
DEPS_graphviz := std
|
||||
DEPS_syntax := std term serialize log fmt_macros arena libc
|
||||
DEPS_rustc_trans := rustc rustc_back rustc_llvm libc
|
||||
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
||||
rustc_typeck rustc_resolve log syntax serialize rustc_llvm rustc_trans
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
||||
log syntax serialize rustc_llvm
|
||||
DEPS_rustc_typeck := rustc syntax
|
||||
DEPS_rustc_borrowck := rustc log graphviz syntax
|
||||
DEPS_rustc_resolve := rustc log syntax
|
||||
DEPS_rustc := syntax flate arena serialize getopts rbml \
|
||||
time log graphviz rustc_llvm rustc_back
|
||||
DEPS_rustc_llvm := native:rustllvm libc std
|
||||
DEPS_rustc_back := std syntax rustc_llvm flate log libc
|
||||
DEPS_rustdoc := rustc rustc_trans native:hoedown serialize getopts \
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||
test time
|
||||
DEPS_flate := std native:miniz
|
||||
DEPS_arena := std
|
||||
@ -81,7 +87,6 @@ DEPS_glob := std
|
||||
DEPS_serialize := std log
|
||||
DEPS_rbml := std log serialize
|
||||
DEPS_term := std log
|
||||
DEPS_sync := core alloc rustrt collections
|
||||
DEPS_getopts := std
|
||||
DEPS_collections := core alloc unicode
|
||||
DEPS_num := std
|
||||
@ -95,7 +100,7 @@ DEPS_fmt_macros = std
|
||||
|
||||
TOOL_DEPS_compiletest := test getopts
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
TOOL_DEPS_rustc := rustc_trans
|
||||
TOOL_DEPS_rustc := rustc_driver
|
||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
@ -111,8 +116,15 @@ ONLY_RLIB_unicode := 1
|
||||
# You should not need to edit below this line
|
||||
################################################################################
|
||||
|
||||
DOC_CRATES := $(filter-out rustc, $(filter-out rustc_trans, $(filter-out syntax, $(CRATES))))
|
||||
COMPILER_DOC_CRATES := rustc rustc_trans syntax
|
||||
DOC_CRATES := $(filter-out rustc, \
|
||||
$(filter-out rustc_trans, \
|
||||
$(filter-out rustc_typeck, \
|
||||
$(filter-out rustc_borrowck, \
|
||||
$(filter-out rustc_resolve, \
|
||||
$(filter-out rustc_driver, \
|
||||
$(filter-out syntax, $(CRATES))))))))
|
||||
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
|
||||
rustc_typeck rustc_driver syntax
|
||||
|
||||
# This macro creates some simple definitions for each crate being built, just
|
||||
# some munging of all of the parameters above.
|
||||
|
@ -16,7 +16,7 @@
|
||||
.PHONY: TAGS.emacs TAGS.vi
|
||||
|
||||
# This is using a blacklist approach, probably more durable than a whitelist.
|
||||
# We exclude: external dependencies (llvm, rt/{msvc,sundown,vg}),
|
||||
# We exclude: external dependencies (llvm, rt/{msvc,vg}),
|
||||
# tests (compiletest, test) and a couple of other things (rt/arch, etc)
|
||||
CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/compiletest,, \
|
||||
@ -25,10 +25,9 @@ CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/rt,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/rt/arch,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/rt/msvc,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/rt/sundown,, \
|
||||
$(patsubst ${CFG_SRC_DIR}src/rt/vg,, \
|
||||
$(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \
|
||||
)))))))))
|
||||
))))))))
|
||||
CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS}
|
||||
# We could use `--languages=Rust`, but there is value in producing tags for the
|
||||
# C++ parts of the code base too (at the time of writing, those are .h and .cpp
|
||||
|
59
mk/debuggers.mk
Normal file
59
mk/debuggers.mk
Normal file
@ -0,0 +1,59 @@
|
||||
# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
######################################################################
|
||||
# Copy debugger related scripts
|
||||
######################################################################
|
||||
|
||||
DEBUGGER_RUSTLIB_ETC_SCRIPTS=lldb_rust_formatters.py
|
||||
DEBUGGER_BIN_SCRIPTS=rust-lldb
|
||||
|
||||
DEBUGGER_RUSTLIB_ETC_SCRIPTS_ABS=$(foreach script,$(DEBUGGER_RUSTLIB_ETC_SCRIPTS), \
|
||||
$(CFG_SRC_DIR)src/etc/$(script))
|
||||
DEBUGGER_BIN_SCRIPTS_ABS=$(foreach script,$(DEBUGGER_BIN_SCRIPTS), \
|
||||
$(CFG_SRC_DIR)src/etc/$(script))
|
||||
|
||||
DEBUGGER_SCRIPTS_ALL=$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ABS) $(DEBUGGER_BIN_SCRIPTS_ABS)
|
||||
|
||||
# $(1) - the stage to copy to
|
||||
# $(2) - the host triple
|
||||
define DEF_INSTALL_DEBUGGER_SCRIPTS_HOST
|
||||
|
||||
tmp/install-debugger-scripts$(1)_H_$(2).done: $$(DEBUGGER_SCRIPTS_ALL)
|
||||
$(Q)mkdir -p $$(HBIN$(1)_H_$(2))
|
||||
$(Q)mkdir -p $$(HLIB$(1)_H_$(2))/rustlib/etc
|
||||
$(Q)install $(DEBUGGER_BIN_SCRIPTS_ABS) $$(HBIN$(1)_H_$(2))
|
||||
$(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ABS) $$(HLIB$(1)_H_$(2))/rustlib/etc
|
||||
$(Q)touch $$@
|
||||
endef
|
||||
|
||||
# Expand host make-targets for all stages
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval $(call DEF_INSTALL_DEBUGGER_SCRIPTS_HOST,$(stage),$(host)))))
|
||||
|
||||
# $(1) is the stage number
|
||||
# $(2) is the target triple
|
||||
# $(3) is the host triple
|
||||
define DEF_INSTALL_DEBUGGER_SCRIPTS_TARGET
|
||||
|
||||
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3).done: $$(DEBUGGER_SCRIPTS_ALL)
|
||||
$(Q)mkdir -p $$(TBIN$(1)_T_$(2)_H_$(3))
|
||||
$(Q)mkdir -p $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
|
||||
$(Q)install $(DEBUGGER_BIN_SCRIPTS_ABS) $$(TBIN$(1)_T_$(2)_H_$(3))
|
||||
$(Q)install $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ABS) $$(TLIB$(1)_T_$(2)_H_$(3))/rustlib/etc
|
||||
$(Q)touch $$@
|
||||
endef
|
||||
|
||||
# Expand target make-targets for all stages
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval $(call DEF_INSTALL_DEBUGGER_SCRIPTS_TARGET,$(stage),$(target),$(host))))))
|
42
mk/dist.mk
42
mk/dist.mk
@ -48,7 +48,6 @@ PKG_FILES := \
|
||||
$(S)configure $(S)Makefile.in \
|
||||
$(S)man \
|
||||
$(addprefix $(S)src/, \
|
||||
README.md \
|
||||
compiletest \
|
||||
doc \
|
||||
driver \
|
||||
@ -59,6 +58,7 @@ PKG_FILES := \
|
||||
rt \
|
||||
rustllvm \
|
||||
snapshots.txt \
|
||||
rust-installer \
|
||||
test) \
|
||||
$(PKG_GITMODULES) \
|
||||
$(filter-out config.stamp, \
|
||||
@ -123,7 +123,8 @@ PKG_EXE = dist/$(PKG_NAME)-$(CFG_BUILD).exe
|
||||
$(PKG_EXE): rust.iss modpath.iss upgrade.iss LICENSE.txt rust-logo.ico \
|
||||
$(CSREQ3_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
|
||||
dist-prepare-win
|
||||
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win $(CFG_BUILD)
|
||||
$(Q)rm -rf tmp/dist/win/gcc
|
||||
$(CFG_PYTHON) $(S)src/etc/make-win-dist.py tmp/dist/win/rust tmp/dist/win/gcc $(CFG_BUILD)
|
||||
@$(call E, ISCC: $@)
|
||||
$(Q)$(CFG_ISCC) $<
|
||||
|
||||
@ -131,7 +132,7 @@ $(eval $(call DEF_PREPARE,win))
|
||||
|
||||
dist-prepare-win: PREPARE_HOST=$(CFG_BUILD)
|
||||
dist-prepare-win: PREPARE_TARGETS=$(CFG_BUILD)
|
||||
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win
|
||||
dist-prepare-win: PREPARE_DEST_DIR=tmp/dist/win/rust
|
||||
dist-prepare-win: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
|
||||
dist-prepare-win: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
|
||||
dist-prepare-win: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
|
||||
@ -209,33 +210,40 @@ distcheck-osx: dist-osx
|
||||
# Unix binary installer tarballs
|
||||
######################################################################
|
||||
|
||||
NON_INSTALLED_PREFIXES=COPYRIGHT,LICENSE-APACHE,LICENSE-MIT,README.md,doc
|
||||
|
||||
define DEF_INSTALLER
|
||||
|
||||
$$(eval $$(call DEF_PREPARE,dir-$(1)))
|
||||
|
||||
dist-install-dir-$(1): PREPARE_HOST=$(1)
|
||||
dist-install-dir-$(1): PREPARE_TARGETS=$(2)
|
||||
dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)
|
||||
dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image
|
||||
dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
|
||||
dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
|
||||
dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
|
||||
dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
|
||||
dist-install-dir-$(1): PREPARE_CLEAN=true
|
||||
dist-install-dir-$(1): prepare-base-dir-$(1) docs compiler-docs
|
||||
$$(Q)(cd $$(PREPARE_DEST_DIR)/ && find . -type f | sed 's/^\.\///') \
|
||||
> tmp/dist/manifest-$(1).in
|
||||
$$(Q)mv tmp/dist/manifest-$(1).in $$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)/rustlib/manifest.in
|
||||
# Add remaining non-installed files
|
||||
$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)
|
||||
$$(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)cp -r doc $$(PREPARE_DEST_DIR)
|
||||
$$(Q)$$(PREPARE_BIN_CMD) $$(S)src/etc/install.sh $$(PREPARE_DEST_DIR)
|
||||
$$(Q)[ ! -d doc ] || cp -r doc $$(PREPARE_DEST_DIR)
|
||||
|
||||
dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)
|
||||
@$(call E, build: $$@)
|
||||
$$(Q)tar -czf dist/$$(PKG_NAME)-$(1).tar.gz -C tmp/dist $$(PKG_NAME)-$(1)
|
||||
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
|
||||
--product-name=Rust \
|
||||
--verify-bin=rustc \
|
||||
--rel-manifest-dir=rustlib \
|
||||
--success-message=Rust-is-ready-to-roll. \
|
||||
--image-dir=tmp/dist/$$(PKG_NAME)-$(1)-image \
|
||||
--work-dir=tmp/dist \
|
||||
--output-dir=dist \
|
||||
--non-installed-prefixes=$$(NON_INSTALLED_PREFIXES) \
|
||||
--package-name=$$(PKG_NAME)-$(1)
|
||||
$$(Q)rm -R tmp/dist/$$(PKG_NAME)-$(1)-image
|
||||
|
||||
endef
|
||||
|
||||
@ -304,9 +312,17 @@ MAYBE_DIST_TAR_SRC=dist-tar-src
|
||||
MAYBE_DISTCHECK_TAR_SRC=distcheck-tar-src
|
||||
endif
|
||||
|
||||
dist: $(MAYBE_DIST_TAR_SRC) dist-osx dist-tar-bins dist-docs
|
||||
ifneq ($(CFG_DISABLE_DOCS),)
|
||||
MAYBE_DIST_DOCS=
|
||||
MAYBE_DISTCHECK_DOCS=
|
||||
else
|
||||
MAYBE_DIST_DOCS=dist-docs
|
||||
MAYBE_DISTCHECK_DOCS=distcheck-docs
|
||||
endif
|
||||
|
||||
distcheck: $(MAYBE_DISTCHECK_TAR_SRC) distcheck-osx distcheck-tar-bins distcheck-docs
|
||||
dist: $(MAYBE_DIST_TAR_SRC) dist-osx dist-tar-bins $(MAYBE_DIST_DOCS)
|
||||
|
||||
distcheck: $(MAYBE_DISTCHECK_TAR_SRC) distcheck-osx distcheck-tar-bins $(MAYBE_DISTCHECK_DOCS)
|
||||
$(Q)rm -Rf tmp/distcheck
|
||||
@echo
|
||||
@echo -----------------------------------------------
|
||||
|
59
mk/docs.mk
59
mk/docs.mk
@ -25,7 +25,7 @@
|
||||
# L10N_LANGS are the languages for which the docs have been
|
||||
# translated.
|
||||
######################################################################
|
||||
DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
|
||||
DOCS := index intro tutorial guide guide-ffi guide-macros guide-ownership \
|
||||
guide-tasks guide-container guide-pointers guide-testing \
|
||||
guide-plugin guide-crates complement-bugreport guide-error-handling \
|
||||
complement-lang-faq complement-design-faq complement-project-faq \
|
||||
@ -216,56 +216,6 @@ endef
|
||||
$(foreach docname,$(DOCS),$(eval $(call DEF_DOC,$(docname))))
|
||||
|
||||
|
||||
# Localized documentation
|
||||
|
||||
# FIXME: I (huonw) haven't actually been able to test properly, since
|
||||
# e.g. (by default) I'm doing an out-of-tree build (#12763), but even
|
||||
# adjusting for that, the files are too old(?) and are rejected by
|
||||
# po4a.
|
||||
#
|
||||
# As such, I've attempted to get it working as much as possible (and
|
||||
# switching from pandoc to rustdoc), but preserving the old behaviour
|
||||
# (e.g. only running on the guide)
|
||||
.PHONY: l10n-mds
|
||||
l10n-mds: $(D)/po4a.conf \
|
||||
$(foreach lang,$(L10N_LANG),$(D)/po/$(lang)/*.md.po)
|
||||
$(warning WARNING: localized documentation is experimental)
|
||||
po4a --copyright-holder="The Rust Project Developers" \
|
||||
--package-name="Rust" \
|
||||
--package-version="$(CFG_RELEASE)" \
|
||||
-M UTF-8 -L UTF-8 \
|
||||
$(D)/po4a.conf
|
||||
|
||||
define DEF_L10N_DOC
|
||||
DOC_L10N_TARGETS += doc/l10n/$(1)/$(2).html
|
||||
doc/l10n/$(1)/$(2).html: l10n-mds $$(HTML_DEPS) $$(RUSTDOC_DEPS_$(2))
|
||||
@$$(call E, rustdoc: $$@)
|
||||
$$(RUSTDOC) $$(RUSTDOC_HTML_OPTS) $$(RUSTDOC_FLAGS_$(1)) doc/l10n/$(1)/$(2).md
|
||||
endef
|
||||
|
||||
$(foreach lang,$(L10N_LANGS),$(eval $(call DEF_L10N_DOC,$(lang),guide)))
|
||||
|
||||
|
||||
######################################################################
|
||||
# LLnextgen (grammar analysis from refman)
|
||||
######################################################################
|
||||
|
||||
ifeq ($(CFG_LLNEXTGEN),)
|
||||
$(info cfg: no llnextgen found, omitting grammar-verification)
|
||||
else
|
||||
.PHONY: verify-grammar
|
||||
|
||||
doc/rust.g: $(D)/rust.md $(S)src/etc/extract_grammar.py
|
||||
@$(call E, extract_grammar: $@)
|
||||
$(Q)$(CFG_PYTHON) $(S)src/etc/extract_grammar.py $< >$@
|
||||
|
||||
verify-grammar: doc/rust.g
|
||||
@$(call E, LLnextgen: $<)
|
||||
$(Q)$(CFG_LLNEXTGEN) --generate-lexer-wrapper=no $< >$@
|
||||
$(Q)rm -f doc/rust.c doc/rust.h
|
||||
endif
|
||||
|
||||
|
||||
######################################################################
|
||||
# Rustdoc (libstd/extra)
|
||||
######################################################################
|
||||
@ -299,7 +249,8 @@ $(2) += doc/$(1)/index.html
|
||||
doc/$(1)/index.html: CFG_COMPILER_HOST_TRIPLE = $(CFG_TARGET)
|
||||
doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
|
||||
@$$(call E, rustdoc: $$@)
|
||||
$$(Q)$$(RUSTDOC) --cfg dox --cfg stage2 $$<
|
||||
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(CFG_BUILD)) \
|
||||
$$(RUSTDOC) --cfg dox --cfg stage2 $$<
|
||||
endef
|
||||
|
||||
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
|
||||
@ -313,7 +264,3 @@ endif
|
||||
|
||||
docs: $(DOC_TARGETS)
|
||||
compiler-docs: $(COMPILER_DOC_TARGETS)
|
||||
|
||||
docs-l10n: $(DOC_L10N_TARGETS)
|
||||
|
||||
.PHONY: docs-l10n
|
||||
|
@ -25,7 +25,7 @@ endif
|
||||
# Remove tmp files because it's a decent amount of disk space
|
||||
$(Q)rm -R tmp/dist
|
||||
|
||||
prepare_install: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir
|
||||
prepare_install: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir
|
||||
|
||||
uninstall:
|
||||
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
|
||||
@ -38,7 +38,7 @@ endif
|
||||
# Remove tmp files because it's a decent amount of disk space
|
||||
$(Q)rm -R tmp/dist
|
||||
|
||||
prepare_uninstall: dist-install-dir-$(CFG_BUILD) | tmp/empty_dir
|
||||
prepare_uninstall: dist/$(PKG_NAME)-$(CFG_BUILD).tar.gz | tmp/empty_dir
|
||||
|
||||
.PHONY: install prepare_install uninstall prepare_uninstall
|
||||
|
||||
|
24
mk/llvm.mk
24
mk/llvm.mk
@ -49,6 +49,12 @@ else
|
||||
LLVM_STDCPP_LOCATION_$(1) =
|
||||
endif
|
||||
|
||||
|
||||
# LLVM linkage:
|
||||
LLVM_LINKAGE_PATH_$(1):=$$(abspath $$(RT_OUTPUT_DIR_$(1))/llvmdeps.rs)
|
||||
$$(LLVM_LINKAGE_PATH_$(1)): $(S)src/etc/mklldeps.py $$(LLVM_CONFIG_$(1))
|
||||
$(Q)$(CFG_PYTHON) "$$<" "$$@" "$$(LLVM_COMPONENTS)" "$$(CFG_ENABLE_LLVM_STATIC_STDCPP)" \
|
||||
$$(LLVM_CONFIG_$(1))
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
@ -57,10 +63,14 @@ $(foreach host,$(CFG_HOST), \
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(eval LLVM_CONFIGS := $(LLVM_CONFIGS) $(LLVM_CONFIG_$(host))))
|
||||
|
||||
$(S)src/librustc_llvm/llvmdeps.rs: \
|
||||
$(LLVM_CONFIGS) \
|
||||
$(S)src/etc/mklldeps.py \
|
||||
$(MKFILE_DEPS)
|
||||
$(Q)$(CFG_PYTHON) $(S)src/etc/mklldeps.py \
|
||||
"$@" "$(LLVM_COMPONENTS)" "$(CFG_ENABLE_LLVM_STATIC_STDCPP)" \
|
||||
$(LLVM_CONFIGS)
|
||||
# This can't be done in target.mk because it's included before this file.
|
||||
define LLVM_LINKAGE_DEPS
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $$(LLVM_LINKAGE_PATH_$(3))
|
||||
endef
|
||||
|
||||
$(foreach source,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call LLVM_LINKAGE_DEPS,0,$(target),$(source))) \
|
||||
$(eval $(call LLVM_LINKAGE_DEPS,1,$(target),$(source))) \
|
||||
$(eval $(call LLVM_LINKAGE_DEPS,2,$(target),$(source))) \
|
||||
$(eval $(call LLVM_LINKAGE_DEPS,3,$(target),$(source)))))
|
||||
|
13
mk/main.mk
13
mk/main.mk
@ -190,11 +190,14 @@ endif
|
||||
# Target-and-rule "utility variables"
|
||||
######################################################################
|
||||
|
||||
define DEF_X
|
||||
define DEF_FOR_TARGET
|
||||
X_$(1) := $(CFG_EXE_SUFFIX_$(1))
|
||||
ifndef CFG_LLVM_TARGET_$(1)
|
||||
CFG_LLVM_TARGET_$(1) := $(1)
|
||||
endif
|
||||
endef
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call DEF_X,$(target))))
|
||||
$(eval $(call DEF_FOR_TARGET,$(target))))
|
||||
|
||||
# "Source" files we generate in builddir along the way.
|
||||
GENERATED :=
|
||||
@ -353,7 +356,8 @@ HSREQ$(1)_H_$(3) = $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3))
|
||||
else
|
||||
HSREQ$(1)_H_$(3) = \
|
||||
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||
$$(MKFILE_DEPS)
|
||||
$$(MKFILE_DEPS) \
|
||||
tmp/install-debugger-scripts$(1)_H_$(3).done
|
||||
endif
|
||||
|
||||
# Prerequisites for using the stageN compiler to build target artifacts
|
||||
@ -367,7 +371,8 @@ TSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
SREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||
$$(foreach dep,$$(TARGET_CRATES), \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
||||
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3).done
|
||||
|
||||
# Prerequisites for a working stageN compiler and complete set of target
|
||||
# libraries
|
||||
|
@ -155,7 +155,7 @@ prepare-base-$(1): PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELAT
|
||||
prepare-base-$(1): PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1
|
||||
prepare-base-$(1): prepare-everything-$(1)
|
||||
|
||||
prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1)
|
||||
prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1) prepare-debugger-scripts-$(1)
|
||||
|
||||
prepare-host-$(1): prepare-host-tools-$(1)
|
||||
|
||||
@ -167,8 +167,13 @@ prepare-host-tools-$(1): \
|
||||
prepare-host-dirs-$(1): prepare-maybe-clean-$(1)
|
||||
$$(call PREPARE_DIR,$$(PREPARE_DEST_BIN_DIR))
|
||||
$$(call PREPARE_DIR,$$(PREPARE_DEST_LIB_DIR))
|
||||
$$(call PREPARE_DIR,$$(PREPARE_DEST_LIB_DIR)/rustlib/etc)
|
||||
$$(call PREPARE_DIR,$$(PREPARE_DEST_MAN_DIR))
|
||||
|
||||
prepare-debugger-scripts-$(1): prepare-host-dirs-$(1) $(DEBUGGER_SCRIPTS_ALL)
|
||||
$$(Q)$$(PREPARE_BIN_CMD) $(DEBUGGER_BIN_SCRIPTS_ABS) $$(PREPARE_DEST_BIN_DIR)
|
||||
$$(Q)$$(PREPARE_LIB_CMD) $(DEBUGGER_RUSTLIB_ETC_SCRIPTS_ABS) $$(PREPARE_DEST_LIB_DIR)/rustlib/etc
|
||||
|
||||
$$(foreach tool,$$(PREPARE_TOOLS), \
|
||||
$$(foreach host,$$(CFG_HOST), \
|
||||
$$(eval $$(call DEF_PREPARE_HOST_TOOL,$$(tool),$$(PREPARE_STAGE),$$(host),$(1)))))
|
||||
|
7
mk/rt.mk
7
mk/rt.mk
@ -35,7 +35,7 @@
|
||||
# that's per-target so you're allowed to conditionally add files based on the
|
||||
# target.
|
||||
################################################################################
|
||||
NATIVE_LIBS := rust_builtin hoedown morestack miniz context_switch \
|
||||
NATIVE_LIBS := rust_builtin hoedown morestack miniz \
|
||||
rustrt_native rust_test_helpers
|
||||
|
||||
# $(1) is the target triple
|
||||
@ -58,8 +58,7 @@ NATIVE_DEPS_rustrt_native_$(1) := \
|
||||
arch/$$(HOST_$(1))/record_sp.S
|
||||
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
|
||||
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
|
||||
NATIVE_DEPS_context_switch_$(1) := \
|
||||
arch/$$(HOST_$(1))/_context.S
|
||||
|
||||
|
||||
################################################################################
|
||||
# You shouldn't find it that necessary to edit anything below this line.
|
||||
@ -75,7 +74,7 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
|
||||
-filetype=obj -mtriple=$(1) -relocation-model=pic -o $$@ $$<
|
||||
-filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) -relocation-model=pic -o $$@ $$<
|
||||
|
||||
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
|
||||
@mkdir -p $$(@D)
|
||||
|
@ -22,7 +22,8 @@ LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
|
||||
-iquote $$(CFG_LLVM_BUILD_DIR_$(1))/include
|
||||
endif
|
||||
|
||||
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, RustWrapper.cpp PassWrapper.cpp)
|
||||
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
|
||||
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
|
||||
|
||||
RUSTLLVM_DEF_$(1) := $(1)/rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
|
||||
|
||||
|
@ -22,7 +22,7 @@ ifdef CFG_ENABLE_LOCAL_RUST
|
||||
else
|
||||
$(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD) $(SNAPSHOT_FILE)
|
||||
endif
|
||||
$(Q)touch $@
|
||||
$(Q)if [ -e "$@" ]; then touch "$@"; else echo "ERROR: snapshot $@ not found"; exit 1; fi
|
||||
|
||||
# For other targets, let the host build the target:
|
||||
|
||||
|
@ -79,7 +79,8 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
|
||||
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \
|
||||
$$(dir $$@)$$(call CFG_RLIB_GLOB,$(4)))
|
||||
$$(STAGE$(1)_T_$(2)_H_$(3)) \
|
||||
$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
|
||||
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) \
|
||||
$$(RUST_LIB_FLAGS_ST$(1)) \
|
||||
-L "$$(RT_OUTPUT_DIR_$(2))" \
|
||||
-L "$$(LLVM_LIBDIR_$(2))" \
|
||||
@ -116,7 +117,7 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
$$(foreach dep,$$(TOOL_DEPS_$(4)), \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||
| $$(TBIN$(1)_T_$(4)_H_$(3))/
|
||||
| $$(TBIN$(1)_T_$(2)_H_$(3))/
|
||||
@$$(call E, rustc: $$@)
|
||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --cfg $(4)
|
||||
|
||||
@ -134,8 +135,6 @@ SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))
|
||||
|
||||
define TARGET_HOST_RULES
|
||||
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $(S)src/librustc_llvm/llvmdeps.rs
|
||||
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/:
|
||||
mkdir -p $$@
|
||||
|
||||
|
28
mk/tests.mk
28
mk/tests.mk
@ -21,7 +21,8 @@ $(eval $(call RUST_CRATE,coretest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES)
|
||||
TEST_HOST_CRATES = $(HOST_CRATES)
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans,\
|
||||
$(HOST_CRATES))
|
||||
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
|
||||
|
||||
######################################################################
|
||||
@ -73,21 +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
|
||||
|
||||
TEST_RATCHET_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4)-metrics.json
|
||||
TEST_RATCHET_NOISE_PERCENT=10.0
|
||||
|
||||
# Whether to ratchet or merely save benchmarks
|
||||
ifdef CFG_RATCHET_BENCH
|
||||
CRATE_TEST_EXTRA_ARGS= \
|
||||
--test $(TEST_BENCH) \
|
||||
--ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
|
||||
--ratchet-noise-percent $(TEST_RATCHET_NOISE_PERCENT)
|
||||
else
|
||||
CRATE_TEST_EXTRA_ARGS= \
|
||||
--test $(TEST_BENCH) \
|
||||
--save-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4))
|
||||
endif
|
||||
|
||||
# If we're sharding the testsuite between parallel testers,
|
||||
# pass this argument along to the compiletest and crate test
|
||||
# invocations.
|
||||
@ -412,7 +398,8 @@ $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \
|
||||
$$(CRATEFILE_$(4)) \
|
||||
$$(TESTDEP_$(1)_$(2)_$(3)_$(4))
|
||||
@$$(call E, rustc: $$@)
|
||||
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test \
|
||||
$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
|
||||
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
|
||||
-L "$$(RT_OUTPUT_DIR_$(2))" \
|
||||
-L "$$(LLVM_LIBDIR_$(2))" \
|
||||
$$(RUSTFLAGS_$(4))
|
||||
@ -453,7 +440,6 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||
$$(Q)touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
|
||||
$$(Q)$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/
|
||||
$$(Q)$(CFG_ADB) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
|
||||
$$(Q)$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/$$(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) tmp/
|
||||
@if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
|
||||
then \
|
||||
rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \
|
||||
@ -597,7 +583,7 @@ CTEST_DISABLE_debuginfo-lldb = "lldb tests are only run on darwin"
|
||||
endif
|
||||
|
||||
ifeq ($(CFG_OSTYPE),apple-darwin)
|
||||
CTEST_DISABLE_debuginfo-gdb = "gdb on darwing needs root"
|
||||
CTEST_DISABLE_debuginfo-gdb = "gdb on darwin needs root"
|
||||
endif
|
||||
|
||||
# CTEST_DISABLE_NONSELFHOST_$(TEST_GROUP), if set, will cause that
|
||||
@ -695,7 +681,6 @@ CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4) := \
|
||||
$$(CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3)) \
|
||||
--src-base $$(S)src/test/$$(CTEST_SRC_BASE_$(4))/ \
|
||||
--build-base $(3)/test/$$(CTEST_BUILD_BASE_$(4))/ \
|
||||
--ratchet-metrics $(call TEST_RATCHET_FILE,$(1),$(2),$(3),$(4)) \
|
||||
--mode $$(CTEST_MODE_$(4)) \
|
||||
$$(CTEST_RUNTOOL_$(4))
|
||||
|
||||
@ -890,7 +875,8 @@ endif
|
||||
ifeq ($(2),$$(CFG_BUILD))
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
|
||||
@$$(call E, run doc-crate-$(4) [$(2)])
|
||||
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
|
||||
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
|
||||
$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
|
||||
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@
|
||||
else
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)):
|
||||
|
@ -1,66 +0,0 @@
|
||||
This is a preliminary version of the Rust compiler, libraries and tools.
|
||||
|
||||
Source layout:
|
||||
|
||||
| Path | Description |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `librustc/` | The self-hosted compiler |
|
||||
| `liballoc/` | Rust's core allocation library |
|
||||
| `libcore/` | The Rust core library |
|
||||
| `libdebug/` | Debugging utilities |
|
||||
| `libstd/` | The standard library (imported and linked by default) |
|
||||
| `libsyntax/` | The Rust parser and pretty-printer |
|
||||
| `libtest/` | Rust's test-runner code |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `libarena/` | The arena (a fast but limited) memory allocator |
|
||||
| `libbacktrace/` | The libbacktrace library |
|
||||
| `libcollections/` | A collection of useful data structures and containers |
|
||||
| `libflate/` | Simple compression library |
|
||||
| `libfmt_macros/` | Macro support for format strings |
|
||||
| `libfourcc/` | Data format identifier library |
|
||||
| `libgetopts/` | Get command-line-options library |
|
||||
| `libglob/` | Unix glob patterns library |
|
||||
| `libgraphviz/` | Generating files for Graphviz |
|
||||
| `libhexfloat/` | Hexadecimal floating-point literals |
|
||||
| `liblibc/` | Bindings for the C standard library |
|
||||
| `liblog/` | Utilities for program-wide and customizable logging |
|
||||
| `libnum/` | Extended number support library (complex, rational, etc) |
|
||||
| `librand/` | Random numbers and distributions |
|
||||
| `libregex/` | Regular expressions |
|
||||
| `libregex_macros/` | The regex! syntax extension |
|
||||
| `libsemver/` | Rust's semantic versioning library |
|
||||
| `libserialize/` | Encode-Decode types library |
|
||||
| `libsync/` | Concurrency mechanisms and primitives |
|
||||
| `libterm/` | ANSI color library for terminals |
|
||||
| `libtime/` | Time operations library |
|
||||
| `liburl/` | URL handling lirary |
|
||||
| `libuuid/` | UUID's handling code |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `rt/` | The runtime system |
|
||||
| `rt/rust_*.c` | - Some of the runtime services |
|
||||
| `rt/vg` | - Valgrind headers |
|
||||
| `rt/msvc` | - MSVC support |
|
||||
| `rt/sundown` | - The Markdown library used by rustdoc |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `compiletest/` | The test runner |
|
||||
| `test/` | Testsuite |
|
||||
| `test/codegen` | - Tests for the LLVM IR infrastructure |
|
||||
| `test/compile-fail` | - Tests that should fail to compile |
|
||||
| `test/debug-info` | - Tests for the `debuginfo` tool |
|
||||
| `test/run-fail` | - Tests that should compile, run and fail |
|
||||
| `test/run-make` | - Tests that depend on a Makefile infrastructure |
|
||||
| `test/run-pass` | - Tests that should compile, run and succeed |
|
||||
| `test/bench` | - Benchmarks and miscellaneous |
|
||||
| `test/pretty` | - Pretty-printer tests |
|
||||
| `test/auxiliary` | - Dependencies of tests |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `librustdoc/` | The Rust API documentation tool |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `llvm/` | The LLVM submodule |
|
||||
| `rustllvm/` | LLVM support code |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `etc/` | Scripts, editors support, misc |
|
||||
|
||||
|
||||
NOTE: This list (especially the second part of the table which contains modules and libraries)
|
||||
is highly volatile and subject to change.
|
@ -25,6 +25,8 @@ pub enum Mode {
|
||||
Codegen
|
||||
}
|
||||
|
||||
impl Copy for Mode {}
|
||||
|
||||
impl FromStr for Mode {
|
||||
fn from_str(s: &str) -> Option<Mode> {
|
||||
match s {
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "bin"]
|
||||
#![feature(phase, slicing_syntax, globs)]
|
||||
#![feature(phase, slicing_syntax, globs, unboxed_closures)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
@ -23,6 +23,7 @@ use std::os;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use std::str::FromStr;
|
||||
use std::thunk::{Thunk};
|
||||
use getopts::{optopt, optflag, reqopt};
|
||||
use common::Config;
|
||||
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
|
||||
@ -151,7 +152,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
|
||||
matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
|
||||
ratchet_noise_percent:
|
||||
matches.opt_str("ratchet-noise-percent")
|
||||
.and_then(|s| from_str::<f64>(s.as_slice())),
|
||||
.and_then(|s| s.as_slice().parse::<f64>()),
|
||||
runtool: matches.opt_str("runtool"),
|
||||
host_rustcflags: matches.opt_str("host-rustcflags"),
|
||||
target_rustcflags: matches.opt_str("target-rustcflags"),
|
||||
@ -189,9 +190,7 @@ pub fn log_config(config: &Config) {
|
||||
logv(c, format!("filter: {}",
|
||||
opt_str(&config.filter
|
||||
.as_ref()
|
||||
.map(|re| {
|
||||
re.to_string().into_string()
|
||||
}))));
|
||||
.map(|re| re.to_string()))));
|
||||
logv(c, format!("runtool: {}", opt_str(&config.runtool)));
|
||||
logv(c, format!("host-rustcflags: {}",
|
||||
opt_str(&config.host_rustcflags)));
|
||||
@ -286,6 +285,9 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
test_shard: config.test_shard.clone(),
|
||||
nocapture: false,
|
||||
color: test::AutoColor,
|
||||
show_boxplot: false,
|
||||
boxplot_width: 50,
|
||||
show_all_stats: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,7 +345,7 @@ pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
|
||||
desc: test::TestDesc {
|
||||
name: make_test_name(config, testfile),
|
||||
ignore: header::is_test_ignored(config, testfile),
|
||||
should_fail: false
|
||||
should_fail: test::ShouldFail::No,
|
||||
},
|
||||
testfn: f(),
|
||||
}
|
||||
@ -366,16 +368,16 @@ pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
|
||||
let config = (*config).clone();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let testfile = testfile.as_str().unwrap().to_string();
|
||||
test::DynTestFn(proc() {
|
||||
test::DynTestFn(Thunk::new(move || {
|
||||
runtest::run(config, testfile)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
|
||||
let config = (*config).clone();
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let testfile = testfile.as_str().unwrap().to_string();
|
||||
test::DynMetricFn(proc(mm) {
|
||||
test::DynMetricFn(box move |: mm: &mut test::MetricMap| {
|
||||
runtest::run_metrics(config, testfile, mm)
|
||||
})
|
||||
}
|
||||
@ -390,7 +392,7 @@ fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
|
||||
match re.captures(full_version_line) {
|
||||
Some(captures) => {
|
||||
Some(captures.at(2).to_string())
|
||||
Some(captures.at(2).unwrap_or("").to_string())
|
||||
}
|
||||
None => {
|
||||
println!("Could not extract GDB version from line '{}'",
|
||||
@ -424,7 +426,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
|
||||
match re.captures(full_version_line) {
|
||||
Some(captures) => {
|
||||
Some(captures.at(1).to_string())
|
||||
Some(captures.at(1).unwrap_or("").to_string())
|
||||
}
|
||||
None => {
|
||||
println!("Could not extract LLDB version from line '{}'",
|
||||
|
@ -7,7 +7,9 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use self::WhichLine::*;
|
||||
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io::{BufferedReader, File};
|
||||
use regex::Regex;
|
||||
|
||||
@ -17,28 +19,74 @@ pub struct ExpectedError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
pub static EXPECTED_PATTERN : &'static str = r"//~(?P<adjusts>\^*)\s*(?P<kind>\S*)\s*(?P<msg>.*)";
|
||||
/// Looks for either "//~| KIND MESSAGE" or "//~^^... KIND MESSAGE"
|
||||
/// The former is a "follow" that inherits its target from the preceding line;
|
||||
/// the latter is an "adjusts" that goes that many lines up.
|
||||
///
|
||||
/// Goal is to enable tests both like: //~^^^ ERROR go up three
|
||||
/// and also //~^ ERROR message one for the preceding line, and
|
||||
/// //~| ERROR message two for that same line.
|
||||
|
||||
pub static EXPECTED_PATTERN : &'static str =
|
||||
r"//~(?P<follow>\|)?(?P<adjusts>\^*)\s*(?P<kind>\S*)\s*(?P<msg>.*)";
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
enum WhichLine { ThisLine, FollowPrevious(uint), AdjustBackward(uint) }
|
||||
|
||||
// Load any test directives embedded in the file
|
||||
pub fn load_errors(re: &Regex, testfile: &Path) -> Vec<ExpectedError> {
|
||||
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
|
||||
|
||||
// `last_nonfollow_error` tracks the most recently seen
|
||||
// line with an error template that did not use the
|
||||
// follow-syntax, "//~| ...".
|
||||
//
|
||||
// (pnkfelix could not find an easy way to compose Iterator::scan
|
||||
// and Iterator::filter_map to pass along this information into
|
||||
// `parse_expected`. So instead I am storing that state here and
|
||||
// updating it in the map callback below.)
|
||||
let mut last_nonfollow_error = None;
|
||||
|
||||
rdr.lines().enumerate().filter_map(|(line_no, ln)| {
|
||||
parse_expected(line_no + 1, ln.unwrap().as_slice(), re)
|
||||
parse_expected(last_nonfollow_error,
|
||||
line_no + 1,
|
||||
ln.unwrap().as_slice(), re)
|
||||
.map(|(which, error)| {
|
||||
match which {
|
||||
FollowPrevious(_) => {}
|
||||
_ => last_nonfollow_error = Some(error.line),
|
||||
}
|
||||
error
|
||||
})
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn parse_expected(line_num: uint, line: &str, re: &Regex) -> Option<ExpectedError> {
|
||||
fn parse_expected(last_nonfollow_error: Option<uint>,
|
||||
line_num: uint,
|
||||
line: &str,
|
||||
re: &Regex) -> Option<(WhichLine, ExpectedError)> {
|
||||
re.captures(line).and_then(|caps| {
|
||||
let adjusts = caps.name("adjusts").len();
|
||||
let kind = caps.name("kind").to_ascii().to_lowercase().into_string();
|
||||
let msg = caps.name("msg").trim().to_string();
|
||||
let adjusts = caps.name("adjusts").unwrap_or("").len();
|
||||
let kind = caps.name("kind").unwrap_or("").to_ascii_lower();
|
||||
let msg = caps.name("msg").unwrap_or("").trim().to_string();
|
||||
let follow = caps.name("follow").unwrap_or("").len() > 0;
|
||||
|
||||
debug!("line={} kind={} msg={}", line_num, kind, msg);
|
||||
Some(ExpectedError {
|
||||
line: line_num - adjusts,
|
||||
kind: kind,
|
||||
msg: msg,
|
||||
})
|
||||
let (which, line) = if follow {
|
||||
assert!(adjusts == 0, "use either //~| or //~^, not both.");
|
||||
let line = last_nonfollow_error.unwrap_or_else(|| {
|
||||
panic!("encountered //~| without preceding //~^ line.")
|
||||
});
|
||||
(FollowPrevious(line), line)
|
||||
} else {
|
||||
let which =
|
||||
if adjusts > 0 { AdjustBackward(adjusts) } else { ThisLine };
|
||||
let line = line_num - adjusts;
|
||||
(which, line)
|
||||
};
|
||||
|
||||
debug!("line={} which={} kind={} msg={}", line_num, which, kind, msg);
|
||||
Some((which, ExpectedError { line: line,
|
||||
kind: kind,
|
||||
msg: msg, }))
|
||||
})
|
||||
}
|
||||
|
@ -351,8 +351,8 @@ pub fn gdb_version_to_int(version_string: &str) -> int {
|
||||
panic!("{}", error_string);
|
||||
}
|
||||
|
||||
let major: int = from_str(components[0]).expect(error_string);
|
||||
let minor: int = from_str(components[1]).expect(error_string);
|
||||
let major: int = components[0].parse().expect(error_string);
|
||||
let minor: int = components[1].parse().expect(error_string);
|
||||
|
||||
return major * 1000 + minor;
|
||||
}
|
||||
@ -362,6 +362,6 @@ pub fn lldb_version_to_int(version_string: &str) -> int {
|
||||
"Encountered LLDB version string with unexpected format: {}",
|
||||
version_string);
|
||||
let error_string = error_string.as_slice();
|
||||
let major: int = from_str(version_string).expect(error_string);
|
||||
let major: int = version_string.parse().expect(error_string);
|
||||
return major;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#[cfg(not(stage0))]
|
||||
|
||||
use self::TargetLocation::*;
|
||||
|
||||
use common::Config;
|
||||
@ -32,7 +32,7 @@ use std::io;
|
||||
use std::os;
|
||||
use std::str;
|
||||
use std::string::String;
|
||||
use std::task;
|
||||
use std::thread::Thread;
|
||||
use std::time::Duration;
|
||||
use test::MetricMap;
|
||||
|
||||
@ -445,9 +445,9 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
loop {
|
||||
//waiting 1 second for gdbserver start
|
||||
timer::sleep(Duration::milliseconds(1000));
|
||||
let result = task::try(proc() {
|
||||
let result = Thread::spawn(move || {
|
||||
tcp::TcpStream::connect("127.0.0.1:5039").unwrap();
|
||||
});
|
||||
}).join();
|
||||
if result.is_err() {
|
||||
continue;
|
||||
}
|
||||
@ -990,7 +990,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
let i = s.chars();
|
||||
let c : Vec<char> = i.map( |c| {
|
||||
if c.is_ascii() {
|
||||
c.to_ascii().to_lowercase().to_char()
|
||||
c.to_ascii().to_lowercase().as_char()
|
||||
} else {
|
||||
c
|
||||
}
|
||||
@ -1161,7 +1161,7 @@ fn compile_test_(config: &Config, props: &TestProps,
|
||||
let args = make_compile_args(config,
|
||||
props,
|
||||
link_args,
|
||||
|a, b| ThisFile(make_exe_name(a, b)), testfile);
|
||||
|a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testfile);
|
||||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
||||
@ -1219,7 +1219,7 @@ fn compose_and_run_compiler(
|
||||
crate_type,
|
||||
|a,b| {
|
||||
let f = make_lib_name(a, b, testfile);
|
||||
ThisDirectory(f.dir_path())
|
||||
TargetLocation::ThisDirectory(f.dir_path())
|
||||
},
|
||||
&abs_ab);
|
||||
let auxres = compose_and_run(config,
|
||||
@ -1296,11 +1296,11 @@ fn make_compile_args(config: &Config,
|
||||
args.push("prefer-dynamic".to_string());
|
||||
}
|
||||
let path = match xform_file {
|
||||
ThisFile(path) => {
|
||||
TargetLocation::ThisFile(path) => {
|
||||
args.push("-o".to_string());
|
||||
path
|
||||
}
|
||||
ThisDirectory(path) => {
|
||||
TargetLocation::ThisDirectory(path) => {
|
||||
args.push("--out-dir".to_string());
|
||||
path
|
||||
}
|
||||
@ -1361,7 +1361,7 @@ fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
|
||||
s.as_slice()
|
||||
.split(' ')
|
||||
.filter_map(|s| {
|
||||
if s.is_whitespace() {
|
||||
if s.chars().all(|c| c.is_whitespace()) {
|
||||
None
|
||||
} else {
|
||||
Some(s.to_string())
|
||||
@ -1609,7 +1609,7 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
stderr_out.as_slice());
|
||||
|
||||
ProcRes {
|
||||
status: process::ExitStatus(exitcode),
|
||||
status: process::ProcessExit::ExitStatus(exitcode),
|
||||
stdout: stdout_out,
|
||||
stderr: stderr_out,
|
||||
cmdline: cmdline
|
||||
@ -1666,13 +1666,14 @@ fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut link_args = vec!("-L".to_string(),
|
||||
aux_dir.as_str().unwrap().to_string());
|
||||
let llvm_args = vec!("--emit=bc,obj".to_string(),
|
||||
let llvm_args = vec!("--emit=llvm-bc,obj".to_string(),
|
||||
"--crate-type=lib".to_string());
|
||||
link_args.extend(llvm_args.into_iter());
|
||||
let args = make_compile_args(config,
|
||||
props,
|
||||
link_args,
|
||||
|a, b| ThisDirectory(output_base_name(a, b).dir_path()),
|
||||
|a, b| TargetLocation::ThisDirectory(
|
||||
output_base_name(a, b).dir_path()),
|
||||
testfile);
|
||||
compose_and_run_compiler(config, props, testfile, args, None)
|
||||
}
|
||||
|
@ -6,12 +6,6 @@
|
||||
document converter, is required to generate docs as HTML from Rust's
|
||||
source code.
|
||||
|
||||
[po4a](http://po4a.alioth.debian.org/) is required for generating translated
|
||||
docs from the master (English) docs.
|
||||
|
||||
[GNU gettext](http://www.gnu.org/software/gettext/) is required for managing
|
||||
the translation data.
|
||||
|
||||
## Building
|
||||
|
||||
To generate all the docs, just run `make docs` from the root of the repository.
|
||||
@ -44,43 +38,3 @@ The syntax for pandoc flavored markdown can be found at:
|
||||
A nice quick reference (for non-pandoc markdown) is at:
|
||||
|
||||
- http://kramdown.gettalong.org/quickref.html
|
||||
|
||||
## Notes for translators
|
||||
|
||||
Notice: The procedure described below is a work in progress. We are working on
|
||||
translation system but the procedure contains some manual operations for now.
|
||||
|
||||
To start the translation for a new language, see `po4a.conf` at first.
|
||||
|
||||
To generate `.pot` and `.po` files, do something like:
|
||||
|
||||
~~~~
|
||||
po4a --copyright-holder="The Rust Project Developers" \
|
||||
--package-name="Rust" \
|
||||
--package-version="0.13.0" \
|
||||
-M UTF-8 -L UTF-8 \
|
||||
src/doc/po4a.conf
|
||||
~~~~
|
||||
|
||||
(the version number must be changed if it is not `0.13.0` now.)
|
||||
|
||||
Now you can translate documents with `.po` files, commonly used with gettext. If
|
||||
you are not familiar with gettext-based translation, please read the online
|
||||
manual linked from http://www.gnu.org/software/gettext/ . We use UTF-8 as the
|
||||
file encoding of `.po` files.
|
||||
|
||||
When you want to make a commit, do the command below before staging your
|
||||
change:
|
||||
|
||||
~~~~
|
||||
for f in src/doc/po/**/*.po; do
|
||||
msgattrib --translated $f -o $f.strip
|
||||
if [ -e $f.strip ]; then
|
||||
mv $f.strip $f
|
||||
else
|
||||
rm $f
|
||||
fi
|
||||
done
|
||||
~~~~
|
||||
|
||||
This removes untranslated entries from `.po` files to save disk space.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# I think I found a bug in the compiler!
|
||||
|
||||
If you see this message: `error: internal compiler error: unexpected failure`,
|
||||
If you see this message: `error: internal compiler error: unexpected panic`,
|
||||
then you have definitely found a bug in the compiler. It's also possible that
|
||||
your code is not well-typed, but if you saw this message, it's still a bug in
|
||||
error reporting.
|
||||
@ -34,10 +34,10 @@ miss out on valid bug reports.
|
||||
It generally helps our diagnosis to include your specific OS (for example: Mac OS X 10.8.3,
|
||||
Windows 7, Ubuntu 12.04) and your hardware architecture (for example: i686, x86_64).
|
||||
It's also helpful to provide the exact version and host by copying the output of
|
||||
re-running the erroneous rustc command with the `--version=verbose` flag, which will
|
||||
re-running the erroneous rustc command with the `--version --verbose` flags, which will
|
||||
produce something like this:
|
||||
|
||||
```{ignore}
|
||||
```text
|
||||
rustc 0.12.0 (ba4081a5a 2014-10-07 13:44:41 -0700)
|
||||
binary: rustc
|
||||
commit-hash: ba4081a5a8573875fed17545846f6f6902c8ba8d
|
||||
@ -46,8 +46,13 @@ host: i686-apple-darwin
|
||||
release: 0.12.0
|
||||
```
|
||||
|
||||
Finally, if you can run the offending command under gdb, pasting a stack trace can be
|
||||
useful; to do so, you will need to set a breakpoint on `rust_panic`.
|
||||
Finally, if you can also provide a backtrace, that'd be great. You can get a
|
||||
backtrace by setting the `RUST_BACKTRACE` environment variable to `1`, like
|
||||
this:
|
||||
|
||||
```bash
|
||||
$ RUST_BACKTRACE=1 rustc ...
|
||||
```
|
||||
|
||||
# I submitted a bug, but nobody has commented on it!
|
||||
|
||||
|
@ -24,7 +24,7 @@ Some examples that demonstrate different aspects of the language:
|
||||
[HashMap]: https://github.com/rust-lang/rust/blob/master/src/libcollections/hashmap.rs
|
||||
[json]: https://github.com/rust-lang/rust/blob/master/src/libserialize/json.rs
|
||||
|
||||
You may also be interested in browsing [GitHub's Rust][github-rust] page.
|
||||
You may also be interested in browsing [trending Rust repositories][github-rust] on GitHub.
|
||||
|
||||
[github-rust]: https://github.com/trending?l=rust
|
||||
|
||||
@ -42,7 +42,7 @@ Let the fact that this is an easily countable number be a warning.
|
||||
|
||||
## Does it run on Windows?
|
||||
|
||||
Yes. All development happens in lock-step on all 3 target platforms. Using MinGW, not Cygwin. Note that the windows implementation currently has some limitations: in particular 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc].
|
||||
Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). Note that the Windows implementation currently has some limitations; in particular, the 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc].
|
||||
|
||||
[win64]: https://github.com/rust-lang/rust/issues/1237
|
||||
[libgcc]: https://github.com/rust-lang/rust/issues/11782
|
||||
@ -104,11 +104,11 @@ Similar to the reasoning about default-sync: it wires fewer assumptions into the
|
||||
|
||||
## Why are strings UTF-8 by default? Why not UCS2 or UCS4?
|
||||
|
||||
The `str` type is UTF-8 because we observe more text in the wild in this encoding -- particularly in network transmissions, which are endian-agnostic -- and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction.
|
||||
The `str` type is UTF-8 because we observe more text in the wild in this encoding – particularly in network transmissions, which are endian-agnostic – and we think it's best that the default treatment of I/O not involve having to recode codepoints in each direction.
|
||||
|
||||
This does mean that indexed access to a Unicode codepoint inside a `str` value is an O(n) operation. On the one hand, this is clearly undesirable; on the other hand, this problem is full of trade-offs and we'd like to point a few important qualifications:
|
||||
|
||||
* Scanning a `str` for ASCII-range codepoints can still be done safely octet-at-a-time, with each indexing operation pulling out a `u8` costing only O(1) and producing a value that can be cast and compared to an ASCII-range `char`. So if you're (say) line-breaking on `'\n'`, octet-based treatment still works. UTF8 was well-designed this way.
|
||||
* Scanning a `str` for ASCII-range codepoints can still be done safely octet-at-a-time. If you use `.as_bytes()`, pulling out a `u8` costs only O(1) and produces a value that can be cast and compared to an ASCII-range `char`. So if you're (say) line-breaking on `'\n'`, octet-based treatment still works. UTF8 was well-designed this way.
|
||||
* Most "character oriented" operations on text only work under very restricted language assumptions sets such as "ASCII-range codepoints only". Outside ASCII-range, you tend to have to use a complex (non-constant-time) algorithm for determining linguistic-unit (glyph, word, paragraph) boundaries anyways. We recommend using an "honest" linguistically-aware, Unicode-approved algorithm.
|
||||
* The `char` type is UCS4. If you honestly need to do a codepoint-at-a-time algorithm, it's trivial to write a `type wstr = [char]`, and unpack a `str` into it in a single pass, then work with the `wstr`. In other words: the fact that the language is not "decoding to UCS4 by default" shouldn't stop you from decoding (or re-encoding any other way) if you need to work with that encoding.
|
||||
|
||||
@ -145,7 +145,7 @@ For simplicity, we do not plan to do so. Implementing automatic semicolon insert
|
||||
|
||||
## How do I get my program to display the output of logging macros?
|
||||
|
||||
**Short answer** set the RUST_LOG environment variable to the name of your source file, sans extension.
|
||||
**Short Answer**: Set the `RUST_LOG` environment variable to the name of your source file, sans extension.
|
||||
|
||||
```sh
|
||||
rustc hello.rs
|
||||
@ -153,15 +153,19 @@ export RUST_LOG=hello
|
||||
./hello
|
||||
```
|
||||
|
||||
**Long answer** RUST_LOG takes a 'logging spec' that consists of a
|
||||
**Long Answer**: `RUST_LOG` takes a 'logging spec' that consists of a
|
||||
comma-separated list of paths, where a path consists of the crate name and
|
||||
sequence of module names, each separated by double-colons. For standalone .rs
|
||||
files the crate is implicitly named after the source file, so in the above
|
||||
example we were setting RUST_LOG to the name of the hello crate. Multiple paths
|
||||
sequence of module names, each separated by double-colons. For standalone `.rs`
|
||||
files, the crate is implicitly named after the source file, so in the above
|
||||
example we were setting `RUST_LOG` to the name of the hello crate. Multiple paths
|
||||
can be combined to control the exact logging you want to see. For example, when
|
||||
debugging linking in the compiler you might set
|
||||
`RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath`
|
||||
For a full description see [the logging crate][1].
|
||||
debugging linking in the compiler, you might set the following:
|
||||
|
||||
```sh
|
||||
RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath
|
||||
```
|
||||
|
||||
For a full description, see [the logging crate][1].
|
||||
|
||||
## How fast is Rust?
|
||||
|
||||
@ -172,6 +176,6 @@ performance.
|
||||
That said, it is an explicit goal of Rust to be as fast as C++ for most things.
|
||||
Language decisions are made with performance in mind, and we want Rust to be as
|
||||
fast as possible. Given that Rust is built on top of LLVM, any performance
|
||||
improvements in it also help us be faster.
|
||||
improvements in it also help Rust become faster.
|
||||
|
||||
[1]:log/index.html
|
||||
|
@ -32,7 +32,7 @@ two languages for those phrases to be in. We'll use this module layout:
|
||||
+---------+ | +-----------+
|
||||
| +---| farewells |
|
||||
+---------+ | +-----------+
|
||||
| phrases |---+
|
||||
| phrases |---+
|
||||
+---------+ | +-----------+
|
||||
| +---| greetings |
|
||||
+----------+ | +-----------+
|
||||
@ -219,7 +219,7 @@ Put this in `src/english/greetings.rs`:
|
||||
|
||||
fn hello() -> String {
|
||||
"Hello!".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Put this in `src/english/farewells.rs`:
|
||||
@ -229,7 +229,7 @@ Put this in `src/english/farewells.rs`:
|
||||
|
||||
fn goodbye() -> String {
|
||||
"Goodbye.".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Put this in `src/japanese/greetings.rs`:
|
||||
@ -239,7 +239,7 @@ Put this in `src/japanese/greetings.rs`:
|
||||
|
||||
fn hello() -> String {
|
||||
"こんにちは".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Of course, you can copy and paste this from this web page, or just type
|
||||
@ -253,7 +253,7 @@ Put this in `src/japanese/farewells.rs`:
|
||||
|
||||
fn goodbye() -> String {
|
||||
"さようなら".to_string()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(This is "Sayoonara", if you're curious.)
|
||||
@ -381,11 +381,11 @@ $ cargo run
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1:1: 3:2 warning: code is never used: `hello`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:1 fn hello() -> String {
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:2 "こんにちは".to_string()
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/greetings.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1:1: 3:2 warning: code is never used: `goodbye`, #[warn(dead_code)] on by default
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:1 fn goodbye() -> String {
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:2 "さようなら".to_string()
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
|
||||
/home/you/projects/phrases/src/japanese/farewells.rs:3 }
|
||||
Running `target/phrases`
|
||||
Hello in English: Hello!
|
||||
Goodbye in English: Goodbye.
|
||||
@ -452,7 +452,7 @@ fn main() {
|
||||
|
||||
Rust will give us a compile-time error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
||||
/home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module
|
||||
/home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
> The best-laid plans of mice and men
|
||||
> Often go awry
|
||||
>
|
||||
>
|
||||
> "Tae a Moose", Robert Burns
|
||||
|
||||
Sometimes, things just go wrong. It's important to have a plan for when the
|
||||
@ -76,7 +76,7 @@ fn main() {
|
||||
|
||||
This will give us an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
error: non-exhaustive patterns: `_` not covered [E0004]
|
||||
```
|
||||
|
||||
@ -189,7 +189,7 @@ panic!("boom");
|
||||
|
||||
gives
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
task '<main>' panicked at 'boom', hello.rs:2
|
||||
```
|
||||
|
||||
|
@ -1,565 +0,0 @@
|
||||
% The Rust References and Lifetimes Guide
|
||||
|
||||
# Introduction
|
||||
|
||||
References are one of the more flexible and powerful tools available in
|
||||
Rust. They can point anywhere: into the heap, stack, and even into the
|
||||
interior of another data structure. A reference is as flexible as a C pointer
|
||||
or C++ reference.
|
||||
|
||||
Unlike C and C++ compilers, the Rust compiler includes special static
|
||||
checks that ensure that programs use references safely.
|
||||
|
||||
Despite their complete safety, a reference's representation at runtime
|
||||
is the same as that of an ordinary pointer in a C program. They introduce zero
|
||||
overhead. The compiler does all safety checks at compile time.
|
||||
|
||||
Although references have rather elaborate theoretical underpinnings
|
||||
(e.g. region pointers), the core concepts will be familiar to anyone
|
||||
who has worked with C or C++. The best way to explain how they are
|
||||
used—and their limitations—is probably just to work through several examples.
|
||||
|
||||
# By example
|
||||
|
||||
References, sometimes known as *borrowed pointers*, are only valid for
|
||||
a limited duration. References never claim any kind of ownership
|
||||
over the data that they point to. Instead, they are used for cases
|
||||
where you would like to use data for a short time.
|
||||
|
||||
Consider a simple struct type `Point`:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}
|
||||
~~~
|
||||
|
||||
We can use this simple definition to allocate points in many different ways. For
|
||||
example, in this code, each of these local variables contains a point,
|
||||
but allocated in a different place:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack : Point = Point {x: 3.0, y: 4.0};
|
||||
let on_the_heap : Box<Point> = box Point {x: 7.0, y: 9.0};
|
||||
~~~
|
||||
|
||||
Suppose we wanted to write a procedure that computed the distance between any
|
||||
two points, no matter where they were stored. One option is to define a function
|
||||
that takes two arguments of type `Point`—that is, it takes the points by value.
|
||||
But if we define it this way, calling the function will cause the points to be
|
||||
copied. For points, this is probably not so bad, but often copies are
|
||||
expensive. So we'd like to define a function that takes the points just as
|
||||
a reference.
|
||||
|
||||
~~~
|
||||
# use std::num::Float;
|
||||
# struct Point {x: f64, y: f64}
|
||||
# fn sqrt(f: f64) -> f64 { 0.0 }
|
||||
fn compute_distance(p1: &Point, p2: &Point) -> f64 {
|
||||
let x_d = p1.x - p2.x;
|
||||
let y_d = p1.y - p2.y;
|
||||
(x_d * x_d + y_d * y_d).sqrt()
|
||||
}
|
||||
~~~
|
||||
|
||||
Now we can call `compute_distance()`:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
|
||||
# let on_the_heap : Box<Point> = box Point{x: 7.0, y: 9.0};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&on_the_stack, &*on_the_heap);
|
||||
~~~
|
||||
|
||||
Here, the `&` operator takes the address of the variable
|
||||
`on_the_stack`; this is because `on_the_stack` has the type `Point`
|
||||
(that is, a struct value) and we have to take its address to get a
|
||||
value. We also call this _borrowing_ the local variable
|
||||
`on_the_stack`, because we have created an alias: that is, another
|
||||
name for the same data.
|
||||
|
||||
Likewise, in the case of `on_the_heap`,
|
||||
the `&` operator is used in conjunction with the `*` operator
|
||||
to take a reference to the contents of the box.
|
||||
|
||||
Whenever a caller lends data to a callee, there are some limitations on what
|
||||
the caller can do with the original. For example, if the contents of a
|
||||
variable have been lent out, you cannot send that variable to another task. In
|
||||
addition, the compiler will reject any code that might cause the borrowed
|
||||
value to be freed or overwrite its component fields with values of different
|
||||
types (I'll get into what kinds of actions those are shortly). This rule
|
||||
should make intuitive sense: you must wait for a borrower to return the value
|
||||
that you lent it (that is, wait for the reference to go out of scope)
|
||||
before you can make full use of it again.
|
||||
|
||||
# Other uses for the & operator
|
||||
|
||||
In the previous example, the value `on_the_stack` was defined like so:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack: Point = Point {x: 3.0, y: 4.0};
|
||||
~~~
|
||||
|
||||
This declaration means that code can only pass `Point` by value to other
|
||||
functions. As a consequence, we had to explicitly take the address of
|
||||
`on_the_stack` to get a reference. Sometimes however it is more
|
||||
convenient to move the & operator into the definition of `on_the_stack`:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
|
||||
~~~
|
||||
|
||||
Applying `&` to an rvalue (non-assignable location) is just a convenient
|
||||
shorthand for creating a temporary and taking its address. A more verbose
|
||||
way to write the same code is:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
let tmp = Point {x: 3.0, y: 4.0};
|
||||
let on_the_stack2 : &Point = &tmp;
|
||||
~~~
|
||||
|
||||
# Taking the address of fields
|
||||
|
||||
The `&` operator is not limited to taking the address of
|
||||
local variables. It can also take the address of fields or
|
||||
individual array elements. For example, consider this type definition
|
||||
for `Rectangle`:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64} // as before
|
||||
struct Size {w: f64, h: f64} // as before
|
||||
struct Rectangle {origin: Point, size: Size}
|
||||
~~~
|
||||
|
||||
Now, as before, we can define rectangles in a few different ways:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}
|
||||
# struct Size {w: f64, h: f64} // as before
|
||||
# struct Rectangle {origin: Point, size: Size}
|
||||
let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
let rect_heap = box Rectangle {origin: Point {x: 5.0, y: 6.0},
|
||||
size: Size {w: 3.0, h: 4.0}};
|
||||
~~~
|
||||
|
||||
In each case, we can extract out individual subcomponents with the `&`
|
||||
operator. For example, I could write:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64} // as before
|
||||
# struct Size {w: f64, h: f64} // as before
|
||||
# struct Rectangle {origin: Point, size: Size}
|
||||
# let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# let rect_heap = box Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
|
||||
# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
|
||||
compute_distance(&rect_stack.origin, &rect_heap.origin);
|
||||
~~~
|
||||
|
||||
which would borrow the field `origin` from the rectangle on the stack
|
||||
as well as from the owned box, and then compute the distance between them.
|
||||
|
||||
# Lifetimes
|
||||
|
||||
We’ve seen a few examples of borrowing data. To this point, we’ve glossed
|
||||
over issues of safety. As stated in the introduction, at runtime a reference
|
||||
is simply a pointer, nothing more. Therefore, avoiding C's problems with
|
||||
dangling pointers requires a compile-time safety check.
|
||||
|
||||
The basis for the check is the notion of _lifetimes_. A lifetime is a
|
||||
static approximation of the span of execution during which the pointer
|
||||
is valid: it always corresponds to some expression or block within the
|
||||
program.
|
||||
|
||||
The compiler will only allow a borrow *if it can guarantee that the data will
|
||||
not be reassigned or moved for the lifetime of the pointer*. This does not
|
||||
necessarily mean that the data is stored in immutable memory. For example,
|
||||
the following function is legal:
|
||||
|
||||
~~~
|
||||
# fn some_condition() -> bool { true }
|
||||
# struct Foo { f: int }
|
||||
fn example3() -> int {
|
||||
let mut x = box Foo {f: 3};
|
||||
if some_condition() {
|
||||
let y = &x.f; // -+ L
|
||||
return *y; // |
|
||||
} // -+
|
||||
x = box Foo {f: 4};
|
||||
// ...
|
||||
# return 0;
|
||||
}
|
||||
~~~
|
||||
|
||||
Here, the interior of the variable `x` is being borrowed
|
||||
and `x` is declared as mutable. However, the compiler can prove that
|
||||
`x` is not assigned anywhere in the lifetime L of the variable
|
||||
`y`. Therefore, it accepts the function, even though `x` is mutable
|
||||
and in fact is mutated later in the function.
|
||||
|
||||
It may not be clear why we are so concerned about mutating a borrowed
|
||||
variable. The reason is that the runtime system frees any box
|
||||
_as soon as its owning reference changes or goes out of
|
||||
scope_. Therefore, a program like this is illegal (and would be
|
||||
rejected by the compiler):
|
||||
|
||||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
let mut x = box X {f: 3};
|
||||
let y = &x.f;
|
||||
x = box X {f: 4}; // Error reported here.
|
||||
*y
|
||||
}
|
||||
~~~
|
||||
|
||||
To make this clearer, consider this diagram showing the state of
|
||||
memory immediately before the re-assignment of `x`:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +-------------+
|
||||
| box {f:int} | ----+
|
||||
y +-------------+ |
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | f: 3 |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Once the reassignment occurs, the memory will look like this:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Exchange Heap
|
||||
|
||||
x +-------------+ +---------+
|
||||
| box {f:int} | -------> | f: 4 |
|
||||
y +-------------+ +---------+
|
||||
| &int | ----+
|
||||
+-------------+ | +---------+
|
||||
+--> | (freed) |
|
||||
+---------+
|
||||
~~~
|
||||
|
||||
Here you can see that the variable `y` still points at the old `f`
|
||||
property of Foo, which has been freed.
|
||||
|
||||
In fact, the compiler can apply the same kind of reasoning to any
|
||||
memory that is (uniquely) owned by the stack frame. So we could
|
||||
modify the previous example to introduce additional owned pointers
|
||||
and structs, and the compiler will still be able to detect possible
|
||||
mutations. This time, we'll use an analogy to illustrate the concept.
|
||||
|
||||
~~~ {.ignore}
|
||||
fn example3() -> int {
|
||||
struct House { owner: Box<Person> }
|
||||
struct Person { age: int }
|
||||
|
||||
let mut house = box House {
|
||||
owner: box Person {age: 30}
|
||||
};
|
||||
|
||||
let owner_age = &house.owner.age;
|
||||
house = box House {owner: box Person {age: 40}}; // Error reported here.
|
||||
house.owner = box Person {age: 50}; // Error reported here.
|
||||
*owner_age
|
||||
}
|
||||
~~~
|
||||
|
||||
In this case, two errors are reported, one when the variable `house` is
|
||||
modified and another when `house.owner` is modified. Either modification would
|
||||
invalidate the pointer `owner_age`.
|
||||
|
||||
# Borrowing and enums
|
||||
|
||||
The previous example showed that the type system forbids any mutations
|
||||
of owned boxed values while they are being borrowed. In general, the type
|
||||
system also forbids borrowing a value as mutable if it is already being
|
||||
borrowed - either as a mutable reference or an immutable one. This restriction
|
||||
prevents pointers from pointing into freed memory. There is one other
|
||||
case where the compiler must be very careful to ensure that pointers
|
||||
remain valid: pointers into the interior of an `enum`.
|
||||
|
||||
Let’s look at the following `shape` type that can represent both rectangles
|
||||
and circles:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}; // as before
|
||||
struct Size {w: f64, h: f64}; // as before
|
||||
enum Shape {
|
||||
Circle(Point, f64), // origin, radius
|
||||
Rectangle(Point, Size) // upper-left, dimensions
|
||||
}
|
||||
~~~
|
||||
|
||||
Now we might write a function to compute the area of a shape. This
|
||||
function takes a reference to a shape, to avoid the need for
|
||||
copying.
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
fn compute_area(shape: &Shape) -> f64 {
|
||||
match *shape {
|
||||
Shape::Circle(_, radius) => std::f64::consts::PI * radius * radius,
|
||||
Shape::Rectangle(_, ref size) => size.w * size.h
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
The first case matches against circles. Here, the pattern extracts the
|
||||
radius from the shape variant and the action uses it to compute the
|
||||
area of the circle.
|
||||
|
||||
The second match is more interesting. Here we match against a
|
||||
rectangle and extract its size: but rather than copy the `size`
|
||||
struct, we use a by-reference binding to create a pointer to it. In
|
||||
other words, a pattern binding like `ref size` binds the name `size`
|
||||
to a pointer of type `&size` into the _interior of the enum_.
|
||||
|
||||
To make this more clear, let's look at a diagram of memory layout in
|
||||
the case where `shape` points at a rectangle:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Memory
|
||||
|
||||
+-------+ +---------------+
|
||||
| shape | ------> | rectangle( |
|
||||
+-------+ | {x: f64, |
|
||||
| size | -+ | y: f64}, |
|
||||
+-------+ +----> | {w: f64, |
|
||||
| h: f64}) |
|
||||
+---------------+
|
||||
~~~
|
||||
|
||||
Here you can see that rectangular shapes are composed of five words of
|
||||
memory. The first is a tag indicating which variant this enum is
|
||||
(`rectangle`, in this case). The next two words are the `x` and `y`
|
||||
fields for the point and the remaining two are the `w` and `h` fields
|
||||
for the size. The binding `size` is then a pointer into the inside of
|
||||
the shape.
|
||||
|
||||
Perhaps you can see where the danger lies: if the shape were somehow
|
||||
to be reassigned, perhaps to a circle, then although the memory used
|
||||
to store that shape value would still be valid, _it would have a
|
||||
different type_! The following diagram shows what memory would look
|
||||
like if code overwrote `shape` with a circle:
|
||||
|
||||
~~~ {.text}
|
||||
Stack Memory
|
||||
|
||||
+-------+ +---------------+
|
||||
| shape | ------> | circle( |
|
||||
+-------+ | {x: f64, |
|
||||
| size | -+ | y: f64}, |
|
||||
+-------+ +----> | f64) |
|
||||
| |
|
||||
+---------------+
|
||||
~~~
|
||||
|
||||
As you can see, the `size` pointer would be pointing at a `f64`
|
||||
instead of a struct. This is not good: dereferencing the second field
|
||||
of a `f64` as if it were a struct with two fields would be a memory
|
||||
safety violation.
|
||||
|
||||
So, in fact, for every `ref` binding, the compiler will impose the
|
||||
same rules as the ones we saw for borrowing the interior of an owned
|
||||
box: it must be able to guarantee that the `enum` will not be
|
||||
overwritten for the duration of the borrow. In fact, the compiler
|
||||
would accept the example we gave earlier. The example is safe because
|
||||
the shape pointer has type `&Shape`, which means "reference to
|
||||
immutable memory containing a `shape`". If, however, the type of that
|
||||
pointer were `&mut Shape`, then the ref binding would be ill-typed.
|
||||
Just as with owned boxes, the compiler will permit `ref` bindings
|
||||
into data owned by the stack frame even if the data are mutable,
|
||||
but otherwise it requires that the data reside in immutable memory.
|
||||
|
||||
# Returning references
|
||||
|
||||
So far, all of the examples we have looked at, use references in a
|
||||
“downward” direction. That is, a method or code block creates a
|
||||
reference, then uses it within the same scope. It is also
|
||||
possible to return references as the result of a function, but
|
||||
as we'll see, doing so requires some explicit annotation.
|
||||
|
||||
We could write a subroutine like this:
|
||||
|
||||
~~~
|
||||
struct Point {x: f64, y: f64}
|
||||
fn get_x<'r>(p: &'r Point) -> &'r f64 { &p.x }
|
||||
~~~
|
||||
|
||||
Here, the function `get_x()` returns a pointer into the structure it
|
||||
was given. The type of the parameter (`&'r Point`) and return type
|
||||
(`&'r f64`) both use a new syntactic form that we have not seen so
|
||||
far. Here the identifier `r` names the lifetime of the pointer
|
||||
explicitly. So in effect, this function declares that it takes a
|
||||
pointer with lifetime `r` and returns a pointer with that same
|
||||
lifetime.
|
||||
|
||||
In general, it is only possible to return references if they
|
||||
are derived from a parameter to the procedure. In that case, the
|
||||
pointer result will always have the same lifetime as one of the
|
||||
parameters; named lifetimes indicate which parameter that
|
||||
is.
|
||||
|
||||
In the previous code samples, function parameter types did not include a
|
||||
lifetime name. The compiler simply creates a fresh name for the lifetime
|
||||
automatically: that is, the lifetime name is guaranteed to refer to a distinct
|
||||
lifetime from the lifetimes of all other parameters.
|
||||
|
||||
Named lifetimes that appear in function signatures are conceptually
|
||||
the same as the other lifetimes we have seen before, but they are a bit
|
||||
abstract: they don’t refer to a specific expression within `get_x()`,
|
||||
but rather to some expression within the *caller of `get_x()`*. The
|
||||
lifetime `r` is actually a kind of *lifetime parameter*: it is defined
|
||||
by the caller to `get_x()`, just as the value for the parameter `p` is
|
||||
defined by that caller.
|
||||
|
||||
In any case, whatever the lifetime of `r` is, the pointer produced by
|
||||
`&p.x` always has the same lifetime as `p` itself: a pointer to a
|
||||
field of a struct is valid as long as the struct is valid. Therefore,
|
||||
the compiler accepts the function `get_x()`.
|
||||
|
||||
In general, if you borrow a struct or box to create a
|
||||
reference, it will only be valid within the function
|
||||
and cannot be returned. This is why the typical way to return references
|
||||
is to take references as input (the only other case in
|
||||
which it can be legal to return a reference is if it
|
||||
points at a static constant).
|
||||
|
||||
# Named lifetimes
|
||||
|
||||
Lifetimes can be named and referenced. For example, the special lifetime
|
||||
`'static`, which does not go out of scope, can be used to create global
|
||||
variables and communicate between tasks (see the manual for use cases).
|
||||
|
||||
## Parameter Lifetimes
|
||||
|
||||
Named lifetimes allow for grouping of parameters by lifetime.
|
||||
For example, consider this function:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, T>(shape: &'r Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
This function takes three references and assigns each the same
|
||||
lifetime `r`. In practice, this means that, in the caller, the
|
||||
lifetime `r` will be the *intersection of the lifetime of the three
|
||||
region parameters*. This may be overly conservative, as in this
|
||||
example:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
# fn select<'r, T>(shape: &Shape, threshold: f64,
|
||||
# a: &'r T, b: &'r T) -> &'r T {
|
||||
# if compute_area(shape) > threshold {a} else {b}
|
||||
# }
|
||||
// -+ r
|
||||
fn select_based_on_unit_circle<'r, T>( // |-+ B
|
||||
threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
|
||||
// | |
|
||||
let shape = Shape::Circle(Point {x: 0., y: 0.}, 1.); // | |
|
||||
select(&shape, threshold, a, b) // | |
|
||||
} // |-+
|
||||
// -+
|
||||
~~~
|
||||
|
||||
In this call to `select()`, the lifetime of the first parameter shape
|
||||
is B, the function body. Both of the second two parameters `a` and `b`
|
||||
share the same lifetime, `r`, which is a lifetime parameter of
|
||||
`select_based_on_unit_circle()`. The caller will infer the
|
||||
intersection of these two lifetimes as the lifetime of the returned
|
||||
value, and hence the return value of `select()` will be assigned a
|
||||
lifetime of B. This will in turn lead to a compilation error, because
|
||||
`select_based_on_unit_circle()` is supposed to return a value with the
|
||||
lifetime `r`.
|
||||
|
||||
To address this, we can modify the definition of `select()` to
|
||||
distinguish the lifetime of the first parameter from the lifetime of
|
||||
the latter two. After all, the first parameter is not being
|
||||
returned. Here is how the new `select()` might look:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
Here you can see that `shape`'s lifetime is now named `tmp`. The
|
||||
parameters `a`, `b`, and the return value all have the lifetime `r`.
|
||||
However, since the lifetime `tmp` is not returned, it would be more
|
||||
concise to just omit the named lifetime for `shape` altogether:
|
||||
|
||||
~~~
|
||||
# struct Point {x: f64, y: f64}; // as before
|
||||
# struct Size {w: f64, h: f64}; // as before
|
||||
# enum Shape {
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# fn compute_area(shape: &Shape) -> f64 { 0.0 }
|
||||
fn select<'r, T>(shape: &Shape, threshold: f64,
|
||||
a: &'r T, b: &'r T) -> &'r T {
|
||||
if compute_area(shape) > threshold {a} else {b}
|
||||
}
|
||||
~~~
|
||||
|
||||
This is equivalent to the previous definition.
|
||||
|
||||
## Labeled Control Structures
|
||||
|
||||
Named lifetime notation can also be used to control the flow of execution:
|
||||
|
||||
~~~
|
||||
'h: for i in range(0u, 10) {
|
||||
'g: loop {
|
||||
if i % 2 == 0 { continue 'h; }
|
||||
if i == 9 { break 'h; }
|
||||
break 'g;
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
> *Note:* Labelled breaks are not currently supported within `while` loops.
|
||||
|
||||
Named labels are hygienic and can be used safely within macros.
|
||||
See the macros guide section on hygiene for more details.
|
||||
|
||||
# Conclusion
|
||||
|
||||
So there you have it: a (relatively) brief tour of the lifetime
|
||||
system. For more details, we refer to the (yet to be written) reference
|
||||
document on references, which will explain the full notation
|
||||
and give more examples.
|
@ -58,7 +58,7 @@ macro_rules! early_return(
|
||||
_ => {}
|
||||
}
|
||||
);
|
||||
)
|
||||
);
|
||||
// ...
|
||||
early_return!(input_1 T::SpecialA);
|
||||
// ...
|
||||
@ -179,8 +179,8 @@ macro_rules! early_return(
|
||||
)+
|
||||
_ => {}
|
||||
}
|
||||
);
|
||||
)
|
||||
)
|
||||
);
|
||||
// ...
|
||||
early_return!(input_1, [T::SpecialA|T::SpecialC|T::SpecialD]);
|
||||
// ...
|
||||
@ -195,7 +195,7 @@ early_return!(input_2, [T::SpecialB]);
|
||||
As the above example demonstrates, `$(...)*` is also valid on the right-hand
|
||||
side of a macro definition. The behavior of `*` in transcription,
|
||||
especially in cases where multiple `*`s are nested, and multiple different
|
||||
names are involved, can seem somewhat magical and intuitive at first. The
|
||||
names are involved, can seem somewhat magical and unintuitive at first. The
|
||||
system that interprets them is called "Macro By Example". The two rules to
|
||||
keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer"
|
||||
of repetitions for all of the `$name`s it contains in lockstep, and (2) each
|
||||
@ -275,17 +275,17 @@ macro_rules! biased_match (
|
||||
_ => { $err }
|
||||
};
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
# enum T1 { Good1(T2, uint), Bad1}
|
||||
# struct T2 { body: T3 }
|
||||
# enum T3 { Good2(uint), Bad2}
|
||||
# fn f(x: T1) -> uint {
|
||||
biased_match!((x) ~ (T1::Good1(g1, val)) else { return 0 };
|
||||
binds g1, val )
|
||||
binds g1, val );
|
||||
biased_match!((g1.body) ~ (T3::Good2(result) )
|
||||
else { panic!("Didn't get good_2") };
|
||||
binds result )
|
||||
binds result );
|
||||
// complicated stuff goes here
|
||||
return result + val;
|
||||
# }
|
||||
@ -303,7 +303,7 @@ pattern we want is clear:
|
||||
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0))
|
||||
# => (0));
|
||||
~~~~
|
||||
|
||||
However, it's not possible to directly expand to nested match statements. But
|
||||
@ -323,7 +323,7 @@ input patterns:
|
||||
# #![feature(macro_rules)]
|
||||
# macro_rules! b(
|
||||
( binds $( $bind_res:ident ),* )
|
||||
# => (0))
|
||||
# => (0));
|
||||
# fn main() {}
|
||||
~~~~
|
||||
|
||||
@ -337,7 +337,7 @@ input patterns:
|
||||
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
|
||||
binds $( $bind_res:ident ),*
|
||||
)
|
||||
# => (0))
|
||||
# => (0));
|
||||
~~~~
|
||||
|
||||
The resulting macro looks like this. Note that the separation into
|
||||
@ -366,7 +366,7 @@ macro_rules! biased_match_rec (
|
||||
);
|
||||
// Produce the requested values
|
||||
( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
|
||||
)
|
||||
);
|
||||
|
||||
// Wrap the whole thing in a `let`.
|
||||
macro_rules! biased_match (
|
||||
@ -388,7 +388,7 @@ macro_rules! biased_match (
|
||||
binds $( $bind_res ),*
|
||||
);
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
# enum T1 { Good1(T2, uint), Bad1}
|
||||
@ -398,7 +398,7 @@ macro_rules! biased_match (
|
||||
biased_match!(
|
||||
(x) ~ (T1::Good1(g1, val)) else { return 0 };
|
||||
(g1.body) ~ (T3::Good2(result) ) else { panic!("Didn't get Good2") };
|
||||
binds val, result )
|
||||
binds val, result );
|
||||
// complicated stuff goes here
|
||||
return result + val;
|
||||
# }
|
||||
@ -444,7 +444,7 @@ macro_rules! loop_x (
|
||||
$e
|
||||
}
|
||||
);
|
||||
)
|
||||
);
|
||||
|
||||
fn main() {
|
||||
'x: loop {
|
||||
@ -482,7 +482,7 @@ An example:
|
||||
|
||||
```rust
|
||||
# #![feature(macro_rules)]
|
||||
macro_rules! m1 (() => (()))
|
||||
macro_rules! m1 (() => (()));
|
||||
|
||||
// visible here: m1
|
||||
|
||||
@ -490,14 +490,14 @@ mod foo {
|
||||
// visible here: m1
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! m2 (() => (()))
|
||||
macro_rules! m2 (() => (()));
|
||||
|
||||
// visible here: m1, m2
|
||||
}
|
||||
|
||||
// visible here: m1
|
||||
|
||||
macro_rules! m3 (() => (()))
|
||||
macro_rules! m3 (() => (()));
|
||||
|
||||
// visible here: m1, m3
|
||||
|
||||
@ -505,7 +505,7 @@ macro_rules! m3 (() => (()))
|
||||
mod bar {
|
||||
// visible here: m1, m3
|
||||
|
||||
macro_rules! m4 (() => (()))
|
||||
macro_rules! m4 (() => (()));
|
||||
|
||||
// visible here: m1, m3, m4
|
||||
}
|
||||
|
454
src/doc/guide-ownership.md
Normal file
454
src/doc/guide-ownership.md
Normal file
@ -0,0 +1,454 @@
|
||||
% The Rust Ownership Guide
|
||||
|
||||
This guide presents Rust's ownership system. This is one of Rust's most unique
|
||||
and compelling features, with which Rust developers should become quite
|
||||
acquainted. Ownership is how Rust achieves its largest goal, memory safety.
|
||||
The ownership system has a few distinct concepts: **ownership**, **borrowing**,
|
||||
and **lifetimes**. We'll talk about each one in turn.
|
||||
|
||||
# Meta
|
||||
|
||||
Before we get to the details, two important notes about the ownership system.
|
||||
|
||||
Rust has a focus on safety and speed. It accomplishes these goals through many
|
||||
"zero cost abstractions," which means that in Rust, abstractions cost as little
|
||||
as possible in order to make them work. The ownership system is a prime example
|
||||
of a zero cost abstraction. All of the analysis we'll talk about in this guide
|
||||
is _done at compile time_. You do not pay any run-time cost for any of these
|
||||
features.
|
||||
|
||||
However, this system does have a certain cost: learning curve. Many new users
|
||||
to Rust experience something we like to call "fighting with the borrow
|
||||
checker," where the Rust compiler refuses to compile a program that the author
|
||||
thinks is valid. This often happens because the programmer's mental model of
|
||||
how ownership should work doesn't match the actual rules that Rust implements.
|
||||
You probably will experience similar things at first. There is good news,
|
||||
however: more experienced Rust developers report that once they work with the
|
||||
rules of the ownership system for a period of time, they fight the borrow
|
||||
checker less and less.
|
||||
|
||||
With that in mind, let's learn about ownership.
|
||||
|
||||
# Ownership
|
||||
|
||||
At its core, ownership is about 'resources.' For the purposes of the vast
|
||||
majority of this guide, we will talk about a specific resource: memory. The
|
||||
concept generalizes to any kind of resource, like a file handle, but to make it
|
||||
more concrete, we'll focus on memory.
|
||||
|
||||
When your program allocates some memory, it needs some way to deallocate that
|
||||
memory. Imagine a function `foo` that allocates four bytes of memory, and then
|
||||
never deallocates that memory. We call this problem 'leaking' memory, because
|
||||
each time we call `foo`, we're allocating another four bytes. Eventually, with
|
||||
enough calls to `foo`, we will run our system out of memory. That's no good. So
|
||||
we need some way for `foo` to deallocate those four bytes. It's also important
|
||||
that we don't deallocate too many times, either. Without getting into the
|
||||
details, attempting to deallocate memory multiple times can lead to problems.
|
||||
In other words, any time some memory is allocated, we need to make sure that we
|
||||
deallocate that memory once and only once. Too many times is bad, not enough
|
||||
times is bad. The counts must match.
|
||||
|
||||
There's one other important detail with regards to allocating memory. Whenever
|
||||
we request some amount of memory, what we are given is a handle to that memory.
|
||||
This handle (often called a 'pointer', when we're referring to memory) is how
|
||||
we interact with the allocated memory. As long as we have that handle, we can
|
||||
do something with the memory. Once we're done with the handle, we're also done
|
||||
with the memory, as we can't do anything useful without a handle to it.
|
||||
|
||||
Historically, systems programming languages require you to track these
|
||||
allocations, deallocations, and handles yourself. For example, if we want some
|
||||
memory from the heap in a language like C, we do this:
|
||||
|
||||
```c
|
||||
{
|
||||
int *x = malloc(sizeof(int));
|
||||
|
||||
// we can now do stuff with our handle x
|
||||
*x = 5;
|
||||
|
||||
free(x);
|
||||
}
|
||||
```
|
||||
|
||||
The call to `malloc` allocates some memory. The call to `free` deallocates the
|
||||
memory. There's also bookkeeping about allocating the correct amount of memory.
|
||||
|
||||
Rust combines these two aspects of allocating memory (and other resources) into
|
||||
a concept called 'ownership.' Whenever we request some memory, that handle we
|
||||
receive is called the 'owning handle.' Whenever that handle goes out of scope,
|
||||
Rust knows that you cannot do anything with the memory anymore, and so
|
||||
therefore deallocates the memory for you. Here's the equivalent example in
|
||||
Rust:
|
||||
|
||||
```rust
|
||||
{
|
||||
let x = box 5i;
|
||||
}
|
||||
```
|
||||
|
||||
The `box` keyword creates a `Box<T>` (specifically `Box<int>` in this case) by
|
||||
allocating a small segment of memory on the heap with enough space to fit an
|
||||
`int`. But where in the code is the box deallocated? We said before that we
|
||||
must have a deallocation for each allocation. Rust handles this for you. It
|
||||
knows that our handle, `x`, is the owning reference to our box. Rust knows that
|
||||
`x` will go out of scope at the end of the block, and so it inserts a call to
|
||||
deallocate the memory at the end of the scope. Because the compiler does this
|
||||
for us, it's impossible to forget. We always have exactly one deallocation paired
|
||||
with each of our allocations.
|
||||
|
||||
This is pretty straightforward, but what happens when we want to pass our box
|
||||
to a function? Let's look at some code:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = box 5i;
|
||||
|
||||
add_one(x);
|
||||
}
|
||||
|
||||
fn add_one(mut num: Box<int>) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
This code works, but it's not ideal. For example, let's add one more line of
|
||||
code, where we print out the value of `x`:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let x = box 5i;
|
||||
|
||||
add_one(x);
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
|
||||
fn add_one(mut num: Box<int>) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
This does not compile, and gives us an error:
|
||||
|
||||
```text
|
||||
error: use of moved value: `x`
|
||||
println!("{}", x);
|
||||
^
|
||||
```
|
||||
|
||||
Remember, we need one deallocation for every allocation. When we try to pass
|
||||
our box to `add_one`, we would have two handles to the memory: `x` in `main`,
|
||||
and `num` in `add_one`. If we deallocated the memory when each handle went out
|
||||
of scope, we would have two deallocations and one allocation, and that's wrong.
|
||||
So when we call `add_one`, Rust defines `num` as the owner of the handle. And
|
||||
so, now that we've given ownership to `num`, `x` is invalid. `x`'s value has
|
||||
"moved" from `x` to `num`. Hence the error: use of moved value `x`.
|
||||
|
||||
To fix this, we can have `add_one` give ownership back when it's done with the
|
||||
box:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = box 5i;
|
||||
|
||||
let y = add_one(x);
|
||||
|
||||
println!("{}", y);
|
||||
}
|
||||
|
||||
fn add_one(mut num: Box<int>) -> Box<int> {
|
||||
*num += 1;
|
||||
|
||||
num
|
||||
}
|
||||
```
|
||||
|
||||
This code will compile and run just fine. Now, we return a `box`, and so the
|
||||
ownership is transferred back to `y` in `main`. We only have ownership for the
|
||||
duration of our function before giving it back. This pattern is very common,
|
||||
and so Rust introduces a concept to describe a handle which temporarily refers
|
||||
to something another handle owns. It's called "borrowing," and it's done with
|
||||
"references", designated by the `&` symbol.
|
||||
|
||||
# Borrowing
|
||||
|
||||
Here's the current state of our `add_one` function:
|
||||
|
||||
```rust
|
||||
fn add_one(mut num: Box<int>) -> Box<int> {
|
||||
*num += 1;
|
||||
|
||||
num
|
||||
}
|
||||
```
|
||||
|
||||
This function takes ownership, because it takes a `Box`, which owns its
|
||||
contents. But then we give ownership right back.
|
||||
|
||||
In the physical world, you can give one of your possessions to someone for a
|
||||
short period of time. You still own your possession, you're just letting someone
|
||||
else use it for a while. We call that 'lending' something to someone, and that
|
||||
person is said to be 'borrowing' that something from you.
|
||||
|
||||
Rust's ownership system also allows an owner to lend out a handle for a limited
|
||||
period. This is also called 'borrowing.' Here's a version of `add_one` which
|
||||
borrows its argument rather than taking ownership:
|
||||
|
||||
```rust
|
||||
fn add_one(num: &mut int) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
This function borrows an `int` from its caller, and then increments it. When
|
||||
the function is over, and `num` goes out of scope, the borrow is over.
|
||||
|
||||
# Lifetimes
|
||||
|
||||
Lending out a reference to a resource that someone else owns can be
|
||||
complicated, however. For example, imagine this set of operations:
|
||||
|
||||
1. I acquire a handle to some kind of resource.
|
||||
2. I lend you a reference to the resource.
|
||||
3. I decide I'm done with the resource, and deallocate it, while you still have
|
||||
your reference.
|
||||
4. You decide to use the resource.
|
||||
|
||||
Uh oh! Your reference is pointing to an invalid resource. This is called a
|
||||
"dangling pointer" or "use after free," when the resource is memory.
|
||||
|
||||
To fix this, we have to make sure that step four never happens after step
|
||||
three. The ownership system in Rust does this through a concept called
|
||||
"lifetimes," which describe the scope that a reference is valid for.
|
||||
|
||||
Let's look at that function which borrows an `int` again:
|
||||
|
||||
```rust
|
||||
fn add_one(num: &int) -> int {
|
||||
*num + 1
|
||||
}
|
||||
```
|
||||
|
||||
Rust has a feature called 'lifetime elision,' which allows you to not write
|
||||
lifetime annotations in certain circumstances. This is one of them. Without
|
||||
eliding the lifetimes, `add_one` looks like this:
|
||||
|
||||
```rust
|
||||
fn add_one<'a>(num: &'a int) -> int {
|
||||
*num + 1
|
||||
}
|
||||
```
|
||||
|
||||
The `'a` is called a **lifetime**. Most lifetimes are used in places where
|
||||
short names like `'a`, `'b` and `'c` are clearest, but it's often useful to
|
||||
have more descriptive names. Let's dig into the syntax in a bit more detail:
|
||||
|
||||
```{rust,ignore}
|
||||
fn add_one<'a>(...)
|
||||
```
|
||||
|
||||
This part _declares_ our lifetimes. This says that `add_one` has one lifetime,
|
||||
`'a`. If we had two, it would look like this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn add_two<'a, 'b>(...)
|
||||
```
|
||||
|
||||
Then in our parameter list, we use the lifetimes we've named:
|
||||
|
||||
```{rust,ignore}
|
||||
...(num: &'a int) -> ...
|
||||
```
|
||||
|
||||
If you compare `&int` to `&'a int`, they're the same, it's just that the
|
||||
lifetime `'a` has snuck in between the `&` and the `int`. We read `&int` as "a
|
||||
reference to an int" and `&'a int` as "a reference to an int with the lifetime 'a.'"
|
||||
|
||||
Why do lifetimes matter? Well, for example, here's some code:
|
||||
|
||||
```rust
|
||||
struct Foo<'a> {
|
||||
x: &'a int,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y = &5i; // this is the same as `let _y = 5; let y = &_y;
|
||||
let f = Foo { x: y };
|
||||
|
||||
println!("{}", f.x);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, `struct`s can also have lifetimes. In a similar way to functions,
|
||||
|
||||
```{rust}
|
||||
struct Foo<'a> {
|
||||
# x: &'a int,
|
||||
# }
|
||||
```
|
||||
|
||||
declares a lifetime, and
|
||||
|
||||
```rust
|
||||
# struct Foo<'a> {
|
||||
x: &'a int,
|
||||
# }
|
||||
```
|
||||
|
||||
uses it. So why do we need a lifetime here? We need to ensure that any reference
|
||||
to a `Foo` cannot outlive the reference to an `int` it contains.
|
||||
|
||||
## Thinking in scopes
|
||||
|
||||
A way to think about lifetimes is to visualize the scope that a reference is
|
||||
valid for. For example:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let y = &5i; // -+ y goes into scope
|
||||
// |
|
||||
// stuff // |
|
||||
// |
|
||||
} // -+ y goes out of scope
|
||||
```
|
||||
|
||||
Adding in our `Foo`:
|
||||
|
||||
```rust
|
||||
struct Foo<'a> {
|
||||
x: &'a int,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let y = &5i; // -+ y goes into scope
|
||||
let f = Foo { x: y }; // -+ f goes into scope
|
||||
// stuff // |
|
||||
// |
|
||||
} // -+ f and y go out of scope
|
||||
```
|
||||
|
||||
Our `f` lives within the scope of `y`, so everything works. What if it didn't?
|
||||
This code won't work:
|
||||
|
||||
```{rust,ignore}
|
||||
struct Foo<'a> {
|
||||
x: &'a int,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x; // -+ x goes into scope
|
||||
// |
|
||||
{ // |
|
||||
let y = &5i; // ---+ y goes into scope
|
||||
let f = Foo { x: y }; // ---+ f goes into scope
|
||||
x = &f.x; // | | error here
|
||||
} // ---+ f and y go out of scope
|
||||
// |
|
||||
println!("{}", x); // |
|
||||
} // -+ x goes out of scope
|
||||
```
|
||||
|
||||
Whew! As you can see here, the scopes of `f` and `y` are smaller than the scope
|
||||
of `x`. But when we do `x = &f.x`, we make `x` a reference to something that's
|
||||
about to go out of scope.
|
||||
|
||||
Named lifetimes are a way of giving these scopes a name. Giving something a
|
||||
name is the first step towards being able to talk about it.
|
||||
|
||||
## 'static
|
||||
|
||||
The lifetime named 'static' is a special lifetime. It signals that something
|
||||
has the lifetime of the entire program. Most Rust programmers first come across
|
||||
`'static` when dealing with strings:
|
||||
|
||||
```rust
|
||||
let x: &'static str = "Hello, world.";
|
||||
```
|
||||
|
||||
String literals have the type `&'static str` because the reference is always
|
||||
alive: they are baked into the data segment of the final binary. Another
|
||||
example are globals:
|
||||
|
||||
```rust
|
||||
static FOO: int = 5i;
|
||||
let x: &'static int = &FOO;
|
||||
```
|
||||
|
||||
This adds an `int` to the data segment of the binary, and FOO is a reference to
|
||||
it.
|
||||
|
||||
# Shared Ownership
|
||||
|
||||
In all the examples we've considered so far, we've assumed that each handle has
|
||||
a singular owner. But sometimes, this doesn't work. Consider a car. Cars have
|
||||
four wheels. We would want a wheel to know which car it was attached to. But
|
||||
this won't work:
|
||||
|
||||
```{rust,ignore}
|
||||
struct Car {
|
||||
name: String,
|
||||
}
|
||||
|
||||
struct Wheel {
|
||||
size: int,
|
||||
owner: Car,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let car = Car { name: "DeLorean".to_string() };
|
||||
|
||||
for _ in range(0u, 4) {
|
||||
Wheel { size: 360, owner: car };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We try to make four `Wheel`s, each with a `Car` that it's attached to. But the
|
||||
compiler knows that on the second iteration of the loop, there's a problem:
|
||||
|
||||
```text
|
||||
error: use of moved value: `car`
|
||||
Wheel { size: 360, owner: car };
|
||||
^~~
|
||||
note: `car` moved here because it has type `Car`, which is non-copyable
|
||||
Wheel { size: 360, owner: car };
|
||||
^~~
|
||||
```
|
||||
|
||||
We need our `Car` to be pointed to by multiple `Wheel`s. We can't do that with
|
||||
`Box<T>`, because it has a single owner. We can do it with `Rc<T>` instead:
|
||||
|
||||
```rust
|
||||
use std::rc::Rc;
|
||||
|
||||
struct Car {
|
||||
name: String,
|
||||
}
|
||||
|
||||
struct Wheel {
|
||||
size: int,
|
||||
owner: Rc<Car>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let car = Car { name: "DeLorean".to_string() };
|
||||
|
||||
let car_owner = Rc::new(car);
|
||||
|
||||
for _ in range(0u, 4) {
|
||||
Wheel { size: 360, owner: car_owner.clone() };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We wrap our `Car` in an `Rc<T>`, getting an `Rc<Car>`, and then use the
|
||||
`clone()` method to make new references. We've also changed our `Wheel` to have
|
||||
an `Rc<Car>` rather than just a `Car`.
|
||||
|
||||
This is the simplest kind of multiple ownership possible. For example, there's
|
||||
also `Arc<T>`, which uses more expensive atomic instructions to be the
|
||||
thread-safe counterpart of `Rc<T>`.
|
||||
|
||||
# Related Resources
|
||||
|
||||
Coming Soon.
|
@ -84,7 +84,7 @@ println!("{}", x + z);
|
||||
|
||||
This gives us an error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
hello.rs:6:24: 6:25 error: mismatched types: expected `int` but found `&int` (expected int but found &-ptr)
|
||||
hello.rs:6 println!("{}", x + z);
|
||||
^
|
||||
@ -132,7 +132,7 @@ Pointers are useful in languages that are pass-by-value, rather than
|
||||
pass-by-reference. Basically, languages can make two choices (this is made
|
||||
up syntax, it's not Rust):
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
func foo(x) {
|
||||
x = 5
|
||||
}
|
||||
@ -152,7 +152,7 @@ and therefore, can change its value. At the comment, `i` will be `5`.
|
||||
So what do pointers have to do with this? Well, since pointers point to a
|
||||
location in memory...
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
func foo(&int x) {
|
||||
*x = 5
|
||||
}
|
||||
@ -179,7 +179,7 @@ but here are problems with pointers in other languages:
|
||||
Uninitialized pointers can cause a problem. For example, what does this program
|
||||
do?
|
||||
|
||||
```{notrust,ignore}
|
||||
```{ignore}
|
||||
&int x;
|
||||
*x = 5; // whoops!
|
||||
```
|
||||
@ -191,7 +191,7 @@ knows. This might be harmless, and it might be catastrophic.
|
||||
When you combine pointers and functions, it's easy to accidentally invalidate
|
||||
the memory the pointer is pointing to. For example:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
func make_pointer(): &int {
|
||||
x = 5;
|
||||
|
||||
@ -213,7 +213,7 @@ As one last example of a big problem with pointers, **aliasing** can be an
|
||||
issue. Two pointers are said to alias when they point at the same location
|
||||
in memory. Like this:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
func mutate(&int i, int j) {
|
||||
*i = j;
|
||||
}
|
||||
@ -398,7 +398,7 @@ fn main() {
|
||||
|
||||
It gives this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
test.rs:5:8: 5:10 error: cannot assign to `*x` because it is borrowed
|
||||
test.rs:5 *x -= 1;
|
||||
^~
|
||||
@ -408,8 +408,8 @@ test.rs:4 let y = &x;
|
||||
```
|
||||
|
||||
As you might guess, this kind of analysis is complex for a human, and therefore
|
||||
hard for a computer, too! There is an entire [guide devoted to references
|
||||
and lifetimes](guide-lifetimes.html) that goes into lifetimes in
|
||||
hard for a computer, too! There is an entire [guide devoted to references, ownership,
|
||||
and lifetimes](guide-ownership.html) that goes into this topic in
|
||||
great detail, so if you want the full details, check that out.
|
||||
|
||||
## Best practices
|
||||
@ -445,11 +445,32 @@ fn succ(x: &int) -> int { *x + 1 }
|
||||
to
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn box_succ(x: Box<int>) -> int { *x + 1 }
|
||||
|
||||
fn rc_succ(x: std::rc::Rc<int>) -> int { *x + 1 }
|
||||
fn rc_succ(x: Rc<int>) -> int { *x + 1 }
|
||||
```
|
||||
|
||||
Note that the caller of your function will have to modify their calls slightly:
|
||||
|
||||
```{rust}
|
||||
use std::rc::Rc;
|
||||
|
||||
fn succ(x: &int) -> int { *x + 1 }
|
||||
|
||||
let ref_x = &5i;
|
||||
let box_x = box 5i;
|
||||
let rc_x = Rc::new(5i);
|
||||
|
||||
succ(ref_x);
|
||||
succ(&*box_x);
|
||||
succ(&*rc_x);
|
||||
```
|
||||
|
||||
The initial `*` dereferences the pointer, and then `&` takes a reference to
|
||||
those contents.
|
||||
|
||||
# Boxes
|
||||
|
||||
`Box<T>` is Rust's 'boxed pointer' type. Boxes provide the simplest form of
|
||||
@ -501,7 +522,7 @@ boxes, though. As a rough approximation, you can treat this Rust code:
|
||||
|
||||
As being similar to this C code:
|
||||
|
||||
```{notrust,ignore}
|
||||
```c
|
||||
{
|
||||
int *x;
|
||||
x = (int *)malloc(sizeof(int));
|
||||
@ -526,7 +547,7 @@ with some improvements:
|
||||
4. Rust enforces that no other writeable pointers alias to this heap memory,
|
||||
which means writing to an invalid pointer is not possible.
|
||||
|
||||
See the section on references or the [lifetimes guide](guide-lifetimes.html)
|
||||
See the section on references or the [ownership guide](guide-ownership.html)
|
||||
for more detail on how lifetimes work.
|
||||
|
||||
Using boxes and references together is very common. For example:
|
||||
@ -572,7 +593,7 @@ fn add_one(x: &mut int) -> int {
|
||||
fn main() {
|
||||
let x = box 5i;
|
||||
|
||||
println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference
|
||||
println!("{}", add_one(&*x)); // error: cannot borrow immutable dereference
|
||||
// of `&`-pointer as mutable
|
||||
}
|
||||
```
|
||||
@ -605,7 +626,7 @@ fn main() {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
Cons(1, box Cons(2, box Cons(3, box Nil)))
|
||||
```
|
||||
|
||||
@ -700,9 +721,9 @@ This gives you flexibility without sacrificing performance.
|
||||
|
||||
You may think that this gives us terrible performance: return a value and then
|
||||
immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
|
||||
than that. There is no copy in this code. main allocates enough room for the
|
||||
`box , passes a pointer to that memory into foo as x, and then foo writes the
|
||||
value straight into that pointer. This writes the return value directly into
|
||||
than that. There is no copy in this code. `main` allocates enough room for the
|
||||
`box`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
|
||||
the value straight into that pointer. This writes the return value directly into
|
||||
the allocated box.
|
||||
|
||||
This is important enough that it bears repeating: pointers are not for
|
||||
@ -759,5 +780,5 @@ Here's a quick rundown of Rust's pointer types:
|
||||
# Related resources
|
||||
|
||||
* [API documentation for Box](std/boxed/index.html)
|
||||
* [Lifetimes guide](guide-lifetimes.html)
|
||||
* [Ownership guide](guide-ownership.html)
|
||||
* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system
|
||||
|
@ -181,7 +181,7 @@ for l in s.graphemes(true) {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
@ -207,7 +207,7 @@ for l in s.chars() {
|
||||
|
||||
This prints:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
u
|
||||
͔
|
||||
n
|
||||
@ -252,7 +252,7 @@ for l in s.bytes() {
|
||||
|
||||
This will print:
|
||||
|
||||
```{notrust,ignore}
|
||||
```{text}
|
||||
117
|
||||
205
|
||||
148
|
||||
|
@ -1,5 +1,7 @@
|
||||
% The Rust Tasks and Communication Guide
|
||||
|
||||
**NOTE** This guide is badly out of date an needs to be rewritten.
|
||||
|
||||
# Introduction
|
||||
|
||||
Rust provides safe concurrent abstractions through a number of core library
|
||||
@ -22,17 +24,18 @@ from shared mutable state.
|
||||
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.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
|
||||
// Print something profound in a different task using a named function
|
||||
fn print_message() { println!("I am running in a different task!"); }
|
||||
spawn(print_message);
|
||||
|
||||
// Alternatively, use a `proc` expression instead of a named function.
|
||||
// The `proc` expression evaluates to an (unnamed) proc.
|
||||
// That proc will call `println!(...)` when the spawned task runs.
|
||||
spawn(proc() println!("I am also running in a different task!") );
|
||||
// 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!"));
|
||||
```
|
||||
|
||||
In Rust, a task is not a concept that appears in the language semantics.
|
||||
@ -40,20 +43,25 @@ 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.
|
||||
|
||||
The `spawn` function has a very simple type signature: `fn spawn(f: proc():
|
||||
Send)`. Because it accepts only procs, and procs contain only owned data,
|
||||
`spawn` can safely move the entire proc and all its associated state into an
|
||||
entirely different task for execution. Like any closure, the function passed to
|
||||
`spawn` may capture an environment that it carries across tasks.
|
||||
The `spawn` function has the type signature: `fn
|
||||
spawn<F:FnOnce()+Send>(f: F)`. This indicates that it takes as
|
||||
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.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# fn generate_task_number() -> int { 0 }
|
||||
// Generate some state locally
|
||||
let child_task_number = generate_task_number();
|
||||
|
||||
spawn(proc() {
|
||||
// Capture it in the remote task
|
||||
spawn(move || {
|
||||
// Capture it in the remote task. The `move` keyword indicates
|
||||
// that this closure should move `child_task_number` into its
|
||||
// environment, rather than capturing a reference into the
|
||||
// enclosing stack frame.
|
||||
println!("I am child number {}", child_task_number);
|
||||
});
|
||||
```
|
||||
@ -69,12 +77,12 @@ The simplest way to create a channel is to use the `channel` function to create
|
||||
of a channel, and a **receiver** is the receiving endpoint. Consider the following
|
||||
example of calculating two results concurrently:
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
|
||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
||||
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
let result = some_expensive_computation();
|
||||
tx.send(result);
|
||||
});
|
||||
@ -90,7 +98,7 @@ stream for sending and receiving integers (the left-hand side of the `let`,
|
||||
`(tx, rx)`, is an example of a destructuring let: the pattern separates a tuple
|
||||
into its component parts).
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
let (tx, rx): (Sender<int>, Receiver<int>) = channel();
|
||||
```
|
||||
|
||||
@ -98,11 +106,11 @@ The child task will use the sender to send data to the parent task, which will
|
||||
wait to receive the data on the receiver. The next statement spawns the child
|
||||
task.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
# let (tx, rx) = channel();
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
let result = some_expensive_computation();
|
||||
tx.send(result);
|
||||
});
|
||||
@ -117,7 +125,7 @@ computation, then sends the result over the captured channel.
|
||||
Finally, the parent continues with some other expensive computation, then waits
|
||||
for the child's result to arrive on the receiver:
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# fn some_other_expensive_computation() {}
|
||||
# let (tx, rx) = channel::<int>();
|
||||
# tx.send(0);
|
||||
@ -135,26 +143,26 @@ results across a number of tasks? The following program is ill-typed:
|
||||
# fn some_expensive_computation() -> int { 42 }
|
||||
let (tx, rx) = channel();
|
||||
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
tx.send(some_expensive_computation());
|
||||
});
|
||||
|
||||
// ERROR! The previous spawn statement already owns the sender,
|
||||
// so the compiler will not allow it to be captured again
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
tx.send(some_expensive_computation());
|
||||
});
|
||||
```
|
||||
|
||||
Instead we can clone the `tx`, which allows for multiple senders.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
let (tx, rx) = channel();
|
||||
|
||||
for init_val in range(0u, 3) {
|
||||
// Create a new channel handle to distribute to the child task
|
||||
let child_tx = tx.clone();
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
child_tx.send(some_expensive_computation(init_val));
|
||||
});
|
||||
}
|
||||
@ -173,13 +181,13 @@ Note that the above cloning example is somewhat contrived since you could also
|
||||
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}
|
||||
```{rust,ignore}
|
||||
# use std::task::spawn;
|
||||
|
||||
// Create a vector of ports, one for each child task
|
||||
let rxs = Vec::from_fn(3, |init_val| {
|
||||
let (tx, rx) = channel();
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
tx.send(some_expensive_computation(init_val));
|
||||
});
|
||||
rx
|
||||
@ -197,7 +205,7 @@ getting the result later.
|
||||
|
||||
The basic example below illustrates this.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
use std::sync::Future;
|
||||
|
||||
# fn main() {
|
||||
@ -207,7 +215,7 @@ fn fib(n: u64) -> u64 {
|
||||
12586269025
|
||||
}
|
||||
|
||||
let mut delayed_fib = Future::spawn(proc() fib(50));
|
||||
let mut delayed_fib = Future::spawn(move || fib(50));
|
||||
make_a_sandwich();
|
||||
println!("fib(50) = {}", delayed_fib.get())
|
||||
# }
|
||||
@ -224,7 +232,7 @@ called.
|
||||
Here is another example showing how futures allow you to background
|
||||
computations. The workload will be distributed on the available cores.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::num::Float;
|
||||
# use std::sync::Future;
|
||||
fn partial_sum(start: uint) -> f64 {
|
||||
@ -236,7 +244,7 @@ fn partial_sum(start: uint) -> f64 {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut futures = Vec::from_fn(200, |ind| Future::spawn( proc() { partial_sum(ind) }));
|
||||
let mut futures = Vec::from_fn(200, |ind| Future::spawn(move || partial_sum(ind)));
|
||||
|
||||
let mut final_res = 0f64;
|
||||
for ft in futures.iter_mut() {
|
||||
@ -262,7 +270,7 @@ 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
|
||||
full vector to perform its duty.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
use std::num::Float;
|
||||
use std::rand;
|
||||
use std::sync::Arc;
|
||||
@ -278,7 +286,7 @@ fn main() {
|
||||
for num in range(1u, 10) {
|
||||
let task_numbers = numbers_arc.clone();
|
||||
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
|
||||
});
|
||||
}
|
||||
@ -289,7 +297,7 @@ The function `pnorm` performs a simple computation on the vector (it computes
|
||||
the sum of its items at the power given as argument and takes the inverse power
|
||||
of this value). The Arc on the vector is created by the line:
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::rand;
|
||||
# use std::sync::Arc;
|
||||
# fn main() {
|
||||
@ -303,7 +311,7 @@ the wrapper and not its contents. Within the task's procedure, the captured
|
||||
Arc reference can be used as a shared reference to the underlying vector as
|
||||
if it were local.
|
||||
|
||||
```{rust}
|
||||
```{rust,ignore}
|
||||
# use std::rand;
|
||||
# use std::sync::Arc;
|
||||
# fn pnorm(nums: &[f64], p: uint) -> f64 { 4.0 }
|
||||
@ -312,7 +320,7 @@ if it were local.
|
||||
# let numbers_arc = Arc::new(numbers);
|
||||
# let num = 4;
|
||||
let task_numbers = numbers_arc.clone();
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
// Capture task_numbers and use it as if it was the underlying vector
|
||||
println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
|
||||
});
|
||||
@ -340,17 +348,17 @@ and `()`, callers can pattern-match on a result to check whether it's an `Ok`
|
||||
result with an `int` field (representing a successful result) or an `Err` result
|
||||
(representing termination with an error).
|
||||
|
||||
```{rust}
|
||||
# use std::task;
|
||||
```{rust,ignore}
|
||||
# use std::thread::Thread;
|
||||
# fn some_condition() -> bool { false }
|
||||
# fn calculate_result() -> int { 0 }
|
||||
let result: Result<int, Box<std::any::Any + Send>> = task::try(proc() {
|
||||
let result: Result<int, Box<std::any::Any + Send>> = Thread::spawn(move || {
|
||||
if some_condition() {
|
||||
calculate_result()
|
||||
} else {
|
||||
panic!("oops!");
|
||||
}
|
||||
});
|
||||
}).join();
|
||||
assert!(result.is_err());
|
||||
```
|
||||
|
||||
|
@ -1,268 +1,515 @@
|
||||
% The Rust Testing Guide
|
||||
|
||||
# Quick start
|
||||
> Program testing can be a very effective way to show the presence of bugs, but
|
||||
> it is hopelessly inadequate for showing their absence.
|
||||
>
|
||||
> Edsger W. Dijkstra, "The Humble Programmer" (1972)
|
||||
|
||||
To create test functions, add a `#[test]` attribute like this:
|
||||
Let's talk about how to test Rust code. What we will not be talking about is
|
||||
the right way to test Rust code. There are many schools of thought regarding
|
||||
the right and wrong way to write tests. All of these approaches use the same
|
||||
basic tools, and so we'll show you the syntax for using them.
|
||||
|
||||
~~~test_harness
|
||||
fn return_two() -> int {
|
||||
2
|
||||
}
|
||||
# The `test` attribute
|
||||
|
||||
At its simplest, a test in Rust is a function that's annotated with the `test`
|
||||
attribute. Let's make a new project with Cargo called `adder`:
|
||||
|
||||
```bash
|
||||
$ cargo new adder
|
||||
$ cd adder
|
||||
```
|
||||
|
||||
Cargo will automatically generate a simple test when you make a new project.
|
||||
Here's the contents of `src/lib.rs`:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn return_two_test() {
|
||||
let x = return_two();
|
||||
assert!(x == 2);
|
||||
fn it_works() {
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
To run these tests, compile with `rustc --test` and run the resulting
|
||||
binary:
|
||||
Note the `#[test]`. This attribute indicates that this is a test function. It
|
||||
currently has no body. That's good enough to pass! We can run the tests with
|
||||
`cargo test`:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
~~~console
|
||||
$ rustc --test foo.rs
|
||||
$ ./foo
|
||||
running 1 test
|
||||
test return_two_test ... ok
|
||||
test it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
~~~
|
||||
|
||||
`rustc foo.rs` will *not* compile the tests, since `#[test]` implies
|
||||
`#[cfg(test)]`. The `--test` flag to `rustc` implies `--cfg test`.
|
||||
Doc-tests adder
|
||||
|
||||
running 0 tests
|
||||
|
||||
# Unit testing in Rust
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
Rust has built in support for simple unit testing. Functions can be
|
||||
marked as unit tests using the `test` attribute.
|
||||
Cargo compiled and ran our tests. There are two sets of output here: one
|
||||
for the test we wrote, and another for documentation tests. We'll talk about
|
||||
those later. For now, see this line:
|
||||
|
||||
~~~test_harness
|
||||
```text
|
||||
test it_works ... ok
|
||||
```
|
||||
|
||||
Note the `it_works`. This comes from the name of our function:
|
||||
|
||||
```rust
|
||||
fn it_works() {
|
||||
# }
|
||||
```
|
||||
|
||||
We also get a summary line:
|
||||
|
||||
```text
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
So why does our do-nothing test pass? Any test which doesn't `panic!` passes,
|
||||
and any test that does `panic!` fails. Let's make our test fail:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn return_none_if_empty() {
|
||||
// ... test code ...
|
||||
fn it_works() {
|
||||
assert!(false);
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
A test function's signature must have no arguments and no return
|
||||
value. To run the tests in a crate, it must be compiled with the
|
||||
`--test` flag: `rustc myprogram.rs --test -o myprogram-tests`. Running
|
||||
the resulting executable will run all the tests in the crate. A test
|
||||
is considered successful if its function returns; if the task running
|
||||
the test fails, through a call to `panic!`, a failed `assert`, or some
|
||||
other (`assert_eq`, ...) means, then the test fails.
|
||||
`assert!` is a macro provided by Rust which takes one argument: if the argument
|
||||
is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run
|
||||
our tests again:
|
||||
|
||||
When compiling a crate with the `--test` flag `--cfg test` is also
|
||||
implied, so that tests can be conditionally compiled.
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
~~~test_harness
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn return_none_if_empty() {
|
||||
// ... test code ...
|
||||
}
|
||||
}
|
||||
~~~
|
||||
running 1 test
|
||||
test it_works ... FAILED
|
||||
|
||||
Additionally `#[test]` items behave as if they also have the
|
||||
`#[cfg(test)]` attribute, and will not be compiled when the `--test` flag
|
||||
is not used.
|
||||
failures:
|
||||
|
||||
Tests that should not be run can be annotated with the `ignore`
|
||||
attribute. The existence of these tests will be noted in the test
|
||||
runner output, but the test will not be run. Tests can also be ignored
|
||||
by configuration using the `cfg_attr` attribute so, for example, to ignore a
|
||||
test on windows you can write `#[cfg_attr(windows, ignore)]`.
|
||||
---- it_works stdout ----
|
||||
task 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
|
||||
|
||||
Tests that are intended to fail can be annotated with the
|
||||
`should_fail` attribute. The test will be run, and if it causes its
|
||||
task to panic then the test will be counted as successful; otherwise it
|
||||
will be counted as a failure. For example:
|
||||
|
||||
~~~test_harness
|
||||
|
||||
failures:
|
||||
it_works
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
|
||||
task '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
|
||||
```
|
||||
|
||||
Rust indicates that our test failed:
|
||||
|
||||
```text
|
||||
test it_works ... FAILED
|
||||
```
|
||||
|
||||
And that's reflected in the summary line:
|
||||
|
||||
```text
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
We also get a non-zero status code:
|
||||
|
||||
```bash
|
||||
$ echo $?
|
||||
101
|
||||
```
|
||||
|
||||
This is useful if you want to integrate `cargo test` into other tooling.
|
||||
|
||||
We can invert our test's failure with another attribute: `should_fail`:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_out_of_bounds_failure() {
|
||||
let v: &[int] = &[];
|
||||
v[0];
|
||||
fn it_works() {
|
||||
assert!(false);
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
A test runner built with the `--test` flag supports a limited set of
|
||||
arguments to control which tests are run:
|
||||
This test will now succeed if we `panic!` and fail if we complete. Let's try it:
|
||||
|
||||
- the first free argument passed to a test runner is interpreted as a
|
||||
regular expression
|
||||
([syntax reference](regex/index.html#syntax))
|
||||
and is used to narrow down the set of tests being run. Note: a plain
|
||||
string is a valid regular expression that matches itself.
|
||||
- the `--ignored` flag tells the test runner to run only tests with the
|
||||
`ignore` attribute.
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
## Parallelism
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
|
||||
By default, tests are run in parallel, which can make interpreting
|
||||
failure output difficult. In these cases you can set the
|
||||
`RUST_TEST_TASKS` environment variable to 1 to make the tests run
|
||||
sequentially.
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
## Examples
|
||||
Doc-tests adder
|
||||
|
||||
### Typical test run
|
||||
running 0 tests
|
||||
|
||||
~~~console
|
||||
$ mytests
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
running 30 tests
|
||||
running driver::tests::mytest1 ... ok
|
||||
running driver::tests::mytest2 ... ignored
|
||||
... snip ...
|
||||
running driver::tests::mytest30 ... ok
|
||||
Rust provides another macro, `assert_eq!`, that compares two arguments for
|
||||
equality:
|
||||
|
||||
result: ok. 28 passed; 0 failed; 2 ignored
|
||||
~~~
|
||||
```rust
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn it_works() {
|
||||
assert_eq!("Hello", "world");
|
||||
}
|
||||
```
|
||||
|
||||
### Test run with failures
|
||||
Does this test pass or fail? Because of the `should_fail` attribute, it
|
||||
passes:
|
||||
|
||||
~~~console
|
||||
$ mytests
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 30 tests
|
||||
running driver::tests::mytest1 ... ok
|
||||
running driver::tests::mytest2 ... ignored
|
||||
... snip ...
|
||||
running driver::tests::mytest30 ... FAILED
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
|
||||
result: FAILED. 27 passed; 1 failed; 2 ignored
|
||||
~~~
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
### Running ignored tests
|
||||
Doc-tests adder
|
||||
|
||||
~~~console
|
||||
$ mytests --ignored
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
`should_fail` tests can be fragile, as it's hard to guarantee that the test
|
||||
didn't fail for an unexpected reason. To help with this, an optional `expected`
|
||||
parameter can be added to the `should_fail` attribute. The test harness will
|
||||
make sure that the failure message contains the provided text. A safer version
|
||||
of the example above would be:
|
||||
|
||||
```
|
||||
#[test]
|
||||
#[should_fail(expected = "assertion failed")]
|
||||
fn it_works() {
|
||||
assert_eq!("Hello", "world");
|
||||
}
|
||||
```
|
||||
|
||||
That's all there is to the basics! Let's write one 'real' test:
|
||||
|
||||
```{rust,ignore}
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
```
|
||||
|
||||
This is a very common use of `assert_eq!`: call some function with
|
||||
some known arguments and compare it to the expected output.
|
||||
|
||||
# The `test` module
|
||||
|
||||
There is one way in which our existing example is not idiomatic: it's
|
||||
missing the test module. The idiomatic way of writing our example
|
||||
looks like this:
|
||||
|
||||
```{rust,ignore}
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::add_two;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There's a few changes here. The first is the introduction of a `mod tests` with
|
||||
a `cfg` attribute. The module allows us to group all of our tests together, and
|
||||
to also define helper functions if needed, that don't become a part of the rest
|
||||
of our crate. The `cfg` attribute only compiles our test code if we're
|
||||
currently trying to run the tests. This can save compile time, and also ensures
|
||||
that our tests are entirely left out of a normal build.
|
||||
|
||||
The second change is the `use` declaration. Because we're in an inner module,
|
||||
we need to bring our test function into scope. This can be annoying if you have
|
||||
a large module, and so this is a common use of the `glob` feature. Let's change
|
||||
our `src/lib.rs` to make use of it:
|
||||
|
||||
```{rust,ignore}
|
||||
#![feature(globs)]
|
||||
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the `feature` attribute, as well as the different `use` line. Now we run
|
||||
our tests:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Updating registry `https://github.com/rust-lang/crates.io-index`
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test test::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests adder
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
It works!
|
||||
|
||||
The current convention is to use the `test` module to hold your "unit"-style
|
||||
tests. Anything that just tests one small bit of functionality makes sense to
|
||||
go here. But what about "integration"-style tests instead? For that, we have
|
||||
the `tests` directory
|
||||
|
||||
# The `tests` directory
|
||||
|
||||
To write an integration test, let's make a `tests` directory, and
|
||||
put a `tests/lib.rs` file inside, with this as its contents:
|
||||
|
||||
```{rust,ignore}
|
||||
extern crate adder;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq(4, adder::add_two(2));
|
||||
}
|
||||
```
|
||||
|
||||
This looks similar to our previous tests, but slightly different. We now have
|
||||
an `extern crate adder` at the top. This is because the tests in the `tests`
|
||||
directory are an entirely separate crate, and so we need to import our library.
|
||||
This is also why `tests` is a suitable place to write integration-style tests:
|
||||
they use the library like any other consumer of it would.
|
||||
|
||||
Let's run them:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test test::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Running target/lib-c18e7d3494509e74
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests adder
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
Now we have three sections: our previous test is also run, as well as our new
|
||||
one.
|
||||
|
||||
That's all there is to the `tests` directory. The `test` module isn't needed
|
||||
here, since the whole thing is focused on tests.
|
||||
|
||||
Let's finally check out that third section: documentation tests.
|
||||
|
||||
# Documentation tests
|
||||
|
||||
Nothing is better than documentation with examples. Nothing is worse than
|
||||
examples that don't actually work, because the code has changed since the
|
||||
documentation has been written. To this end, Rust supports automatically
|
||||
running examples in your documentation. Here's a fleshed-out `src/lib.rs`
|
||||
with examples:
|
||||
|
||||
```{rust,ignore}
|
||||
//! The `adder` crate provides functions that add numbers to other numbers.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```
|
||||
//! assert_eq!(4, adder::add_two(2));
|
||||
//! ```
|
||||
|
||||
#![feature(globs)]
|
||||
|
||||
/// This function adds two to its argument.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use adder::add_two;
|
||||
///
|
||||
/// assert_eq!(4, add_two(2));
|
||||
/// ```
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the module-level documentation with `//!` and the function-level
|
||||
documentation with `///`. Rust's documentation supports Markdown in comments,
|
||||
and so triple graves mark code blocks. It is conventional to include the
|
||||
`# Examples` section, exactly like that, with examples following.
|
||||
|
||||
Let's run the tests again:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test test::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Running target/lib-c18e7d3494509e74
|
||||
|
||||
running 1 test
|
||||
test it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests adder
|
||||
|
||||
running 2 tests
|
||||
running driver::tests::mytest2 ... failed
|
||||
running driver::tests::mytest10 ... ok
|
||||
test add_two_0 ... ok
|
||||
test _0 ... ok
|
||||
|
||||
result: FAILED. 1 passed; 1 failed; 0 ignored
|
||||
~~~
|
||||
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
### Running a subset of tests
|
||||
Now we have all three kinds of tests running! Note the names of the
|
||||
documentation tests: the `_0` is generated for the module test, and `add_two_0`
|
||||
for the function test. These will auto increment with names like `add_two_1` as
|
||||
you add more examples.
|
||||
|
||||
Using a plain string:
|
||||
# Benchmark tests
|
||||
|
||||
~~~console
|
||||
$ mytests mytest23
|
||||
Rust also supports benchmark tests, which can test the performance of your
|
||||
code. Let's make our `src/lib.rs` look like this (comments elided):
|
||||
|
||||
running 1 tests
|
||||
running driver::tests::mytest23 ... ok
|
||||
```{rust,ignore}
|
||||
#![feature(globs)]
|
||||
|
||||
result: ok. 1 passed; 0 failed; 0 ignored
|
||||
~~~
|
||||
|
||||
Using some regular expression features:
|
||||
|
||||
~~~console
|
||||
$ mytests 'mytest[145]'
|
||||
|
||||
running 13 tests
|
||||
running driver::tests::mytest1 ... ok
|
||||
running driver::tests::mytest4 ... ok
|
||||
running driver::tests::mytest5 ... ok
|
||||
running driver::tests::mytest10 ... ignored
|
||||
... snip ...
|
||||
running driver::tests::mytest19 ... ok
|
||||
|
||||
result: ok. 13 passed; 0 failed; 1 ignored
|
||||
~~~
|
||||
|
||||
# Microbenchmarking
|
||||
|
||||
The test runner also understands a simple form of benchmark execution.
|
||||
Benchmark functions are marked with the `#[bench]` attribute, rather
|
||||
than `#[test]`, and have a different form and meaning. They are
|
||||
compiled along with `#[test]` functions when a crate is compiled with
|
||||
`--test`, but they are not run by default. To run the benchmark
|
||||
component of your testsuite, pass `--bench` to the compiled test
|
||||
runner.
|
||||
|
||||
The type signature of a benchmark function differs from a unit test:
|
||||
it takes a mutable reference to type
|
||||
`test::Bencher`. Inside the benchmark function, any
|
||||
time-variable or "setup" code should execute first, followed by a call
|
||||
to `iter` on the benchmark harness, passing a closure that contains
|
||||
the portion of the benchmark you wish to actually measure the
|
||||
per-iteration speed of.
|
||||
|
||||
For benchmarks relating to processing/generating data, one can set the
|
||||
`bytes` field to the number of bytes consumed/produced in each
|
||||
iteration; this will be used to show the throughput of the benchmark.
|
||||
This must be the amount used in each iteration, *not* the total
|
||||
amount.
|
||||
|
||||
For example:
|
||||
|
||||
~~~test_harness
|
||||
extern crate test;
|
||||
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_sum_1024_ints(b: &mut Bencher) {
|
||||
let v = Vec::from_fn(1024, |n| n);
|
||||
b.iter(|| v.iter().fold(0, |old, new| old + *new));
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn initialise_a_vector(b: &mut Bencher) {
|
||||
b.iter(|| Vec::from_elem(1024, 0u64));
|
||||
b.bytes = 1024 * 8;
|
||||
}
|
||||
~~~
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test::Bencher;
|
||||
|
||||
The benchmark runner will calibrate measurement of the benchmark
|
||||
function to run the `iter` block "enough" times to get a reliable
|
||||
measure of the per-iteration speed.
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_add_two(b: &mut Bencher) {
|
||||
b.iter(|| add_two(2));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We've imported the `test` crate, which contains our benchmarking support.
|
||||
We have a new function as well, with the `bench` attribute. Unlike regular
|
||||
tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
|
||||
`Bencher` provides an `iter` method, which takes a closure. This closure
|
||||
contains the code we'd like to benchmark.
|
||||
|
||||
We can run benchmark tests with `cargo bench`:
|
||||
|
||||
```bash
|
||||
$ cargo bench
|
||||
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
|
||||
Running target/release/adder-91b3e234d4ed382a
|
||||
|
||||
running 2 tests
|
||||
test tests::it_works ... ignored
|
||||
test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
|
||||
```
|
||||
|
||||
Our non-benchmark test was ignored. You may have noticed that `cargo bench`
|
||||
takes a bit longer than `cargo test`. This is because Rust runs our benchmark
|
||||
a number of times, and then takes the average. Because we're doing so little
|
||||
work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
|
||||
the variance if there was one.
|
||||
|
||||
Advice on writing benchmarks:
|
||||
|
||||
- Move setup code outside the `iter` loop; only put the part you
|
||||
want to measure inside
|
||||
- Make the code do "the same thing" on each iteration; do not
|
||||
accumulate or change state
|
||||
- Make the outer function idempotent too; the benchmark runner is
|
||||
likely to run it many times
|
||||
- Make the inner `iter` loop short and fast so benchmark runs are
|
||||
fast and the calibrator can adjust the run-length at fine
|
||||
resolution
|
||||
- Make the code in the `iter` loop do something simple, to assist in
|
||||
pinpointing performance improvements (or regressions)
|
||||
|
||||
To run benchmarks, pass the `--bench` flag to the compiled
|
||||
test-runner. Benchmarks are compiled-in but not executed by default.
|
||||
* Move setup code outside the `iter` loop; only put the part you want to measure inside
|
||||
* Make the code do "the same thing" on each iteration; do not accumulate or change state
|
||||
* Make the outer function idempotent too; the benchmark runner is likely to run
|
||||
it many times
|
||||
* Make the inner `iter` loop short and fast so benchmark runs are fast and the
|
||||
calibrator can adjust the run-length at fine resolution
|
||||
* Make the code in the `iter` loop do something simple, to assist in pinpointing
|
||||
performance improvements (or regressions)
|
||||
|
||||
~~~console
|
||||
$ rustc mytests.rs -O --test
|
||||
$ mytests --bench
|
||||
There's another tricky part to writing benchmarks: benchmarks compiled with
|
||||
optimizations activated can be dramatically changed by the optimizer so that
|
||||
the benchmark is no longer benchmarking what one expects. For example, the
|
||||
compiler might recognize that some calculation has no external effects and
|
||||
remove it entirely.
|
||||
|
||||
running 2 tests
|
||||
test bench_sum_1024_ints ... bench: 709 ns/iter (+/- 82)
|
||||
test initialise_a_vector ... bench: 424 ns/iter (+/- 99) = 19320 MB/s
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
|
||||
~~~
|
||||
|
||||
## Benchmarks and the optimizer
|
||||
|
||||
Benchmarks compiled with optimizations activated can be dramatically
|
||||
changed by the optimizer so that the benchmark is no longer
|
||||
benchmarking what one expects. For example, the compiler might
|
||||
recognize that some calculation has no external effects and remove
|
||||
it entirely.
|
||||
|
||||
~~~test_harness
|
||||
```{rust,ignore}
|
||||
extern crate test;
|
||||
use test::Bencher;
|
||||
|
||||
@ -272,36 +519,36 @@ fn bench_xor_1000_ints(b: &mut Bencher) {
|
||||
range(0u, 1000).fold(0, |old, new| old ^ new);
|
||||
});
|
||||
}
|
||||
~~~
|
||||
```
|
||||
|
||||
gives the following results
|
||||
|
||||
~~~console
|
||||
```text
|
||||
running 1 test
|
||||
test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
|
||||
~~~
|
||||
```
|
||||
|
||||
The benchmarking runner offers two ways to avoid this. Either, the
|
||||
closure that the `iter` method receives can return an arbitrary value
|
||||
which forces the optimizer to consider the result used and ensures it
|
||||
cannot remove the computation entirely. This could be done for the
|
||||
example above by adjusting the `b.iter` call to
|
||||
The benchmarking runner offers two ways to avoid this. Either, the closure that
|
||||
the `iter` method receives can return an arbitrary value which forces the
|
||||
optimizer to consider the result used and ensures it cannot remove the
|
||||
computation entirely. This could be done for the example above by adjusting the
|
||||
`b.iter` call to
|
||||
|
||||
~~~
|
||||
```rust
|
||||
# struct X; impl X { fn iter<T>(&self, _: || -> T) {} } let b = X;
|
||||
b.iter(|| {
|
||||
// note lack of `;` (could also use an explicit `return`).
|
||||
range(0u, 1000).fold(0, |old, new| old ^ new)
|
||||
});
|
||||
~~~
|
||||
```
|
||||
|
||||
Or, the other option is to call the generic `test::black_box`
|
||||
function, which is an opaque "black box" to the optimizer and so
|
||||
forces it to consider any argument as used.
|
||||
Or, the other option is to call the generic `test::black_box` function, which
|
||||
is an opaque "black box" to the optimizer and so forces it to consider any
|
||||
argument as used.
|
||||
|
||||
~~~
|
||||
```rust
|
||||
extern crate test;
|
||||
|
||||
# fn main() {
|
||||
@ -310,54 +557,17 @@ b.iter(|| {
|
||||
test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new));
|
||||
});
|
||||
# }
|
||||
~~~
|
||||
```
|
||||
|
||||
Neither of these read or modify the value, and are very cheap for
|
||||
small values. Larger values can be passed indirectly to reduce
|
||||
overhead (e.g. `black_box(&huge_struct)`).
|
||||
Neither of these read or modify the value, and are very cheap for small values.
|
||||
Larger values can be passed indirectly to reduce overhead (e.g.
|
||||
`black_box(&huge_struct)`).
|
||||
|
||||
Performing either of the above changes gives the following
|
||||
benchmarking results
|
||||
Performing either of the above changes gives the following benchmarking results
|
||||
|
||||
~~~console
|
||||
```text
|
||||
running 1 test
|
||||
test bench_xor_1000_ints ... bench: 375 ns/iter (+/- 148)
|
||||
test bench_xor_1000_ints ... bench: 1 ns/iter (+/- 0)
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
|
||||
~~~
|
||||
|
||||
However, the optimizer can still modify a testcase in an undesirable
|
||||
manner even when using either of the above. Benchmarks can be checked
|
||||
by hand by looking at the output of the compiler using the `--emit=ir`
|
||||
(for LLVM IR), `--emit=asm` (for assembly) or compiling normally and
|
||||
using any method for examining object code.
|
||||
|
||||
## Saving and ratcheting metrics
|
||||
|
||||
When running benchmarks or other tests, the test runner can record
|
||||
per-test "metrics". Each metric is a scalar `f64` value, plus a noise
|
||||
value which represents uncertainty in the measurement. By default, all
|
||||
`#[bench]` benchmarks are recorded as metrics, which can be saved as
|
||||
JSON in an external file for further reporting.
|
||||
|
||||
In addition, the test runner supports _ratcheting_ against a metrics
|
||||
file. Ratcheting is like saving metrics, except that after each run,
|
||||
if the output file already exists the results of the current run are
|
||||
compared against the contents of the existing file, and any regression
|
||||
_causes the testsuite to fail_. If the comparison passes -- if all
|
||||
metrics stayed the same (within noise) or improved -- then the metrics
|
||||
file is overwritten with the new values. In this way, a metrics file
|
||||
in your workspace can be used to ensure your work does not regress
|
||||
performance.
|
||||
|
||||
Test runners take 3 options that are relevant to metrics:
|
||||
|
||||
- `--save-metrics=<file.json>` will save the metrics from a test run
|
||||
to `file.json`
|
||||
- `--ratchet-metrics=<file.json>` will ratchet the metrics against
|
||||
the `file.json`
|
||||
- `--ratchet-noise-percent=N` will override the noise measurements
|
||||
in `file.json`, and consider a metric change less than `N%` to be
|
||||
noise. This can be helpful if you are testing in a noisy
|
||||
environment where the benchmark calibration loop cannot acquire a
|
||||
clear enough signal.
|
||||
```
|
||||
|
@ -37,7 +37,7 @@ build safe interfaces.
|
||||
## References
|
||||
|
||||
One of Rust's biggest features is memory safety. This is achieved in
|
||||
part via [the lifetime system](guide-lifetimes.html), which is how the
|
||||
part via [the ownership system](guide-ownership.html), which is how the
|
||||
compiler can guarantee that every `&` reference is always valid, and,
|
||||
for example, never pointing to freed memory.
|
||||
|
||||
@ -661,6 +661,9 @@ extern {
|
||||
fn abort() -> !;
|
||||
}
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T>(*mut T);
|
||||
|
||||
#[lang="exchange_malloc"]
|
||||
unsafe fn allocate(size: uint, _align: uint) -> *mut u8 {
|
||||
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
||||
|
611
src/doc/guide.md
611
src/doc/guide.md
File diff suppressed because it is too large
Load Diff
@ -54,9 +54,9 @@ Rust Guides are in-depth looks at a particular topic that's relevant to Rust
|
||||
development. If you're trying to figure out how to do something, there may be
|
||||
a guide that can help you out:
|
||||
|
||||
* [Ownership](guide-ownership.html)
|
||||
* [Strings](guide-strings.html)
|
||||
* [Pointers](guide-pointers.html)
|
||||
* [References and Lifetimes](guide-lifetimes.html)
|
||||
* [Crates and modules](guide-crates.html)
|
||||
* [Tasks and Communication](guide-tasks.html)
|
||||
* [Error Handling](guide-error-handling.html)
|
||||
|
@ -58,13 +58,13 @@ authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
This is called a **manifest**, and it contains all of the metadata that Cargo
|
||||
needs to compile your project.
|
||||
needs to compile your project.
|
||||
|
||||
Here's what's in `src/main.rs`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
println!("Hello, world!")
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -155,13 +155,13 @@ when you have unrestricted access to memory. As an example, here's some Ruby
|
||||
code:
|
||||
|
||||
```{ruby}
|
||||
v = [];
|
||||
v = []
|
||||
|
||||
v.push("Hello");
|
||||
v.push("Hello")
|
||||
|
||||
x = v[0];
|
||||
x = v[0]
|
||||
|
||||
v.push("world");
|
||||
v.push("world")
|
||||
|
||||
puts x
|
||||
```
|
||||
@ -207,7 +207,7 @@ and two...
|
||||
|
||||
```{bash}
|
||||
$ g++ hello.cpp -Wall -Werror
|
||||
$ ./a.out
|
||||
$ ./a.out
|
||||
Segmentation fault (core dumped)
|
||||
```
|
||||
|
||||
@ -313,7 +313,7 @@ print `"Hello"`, or does Rust crash?
|
||||
|
||||
Neither. It refuses to compile:
|
||||
|
||||
```{notrust,ignore}
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
|
||||
main.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable
|
||||
@ -389,51 +389,59 @@ safe concurrent programs.
|
||||
Here's an example of a concurrent Rust program:
|
||||
|
||||
```{rust}
|
||||
use std::thread::Thread;
|
||||
|
||||
fn main() {
|
||||
for _ in range(0u, 10u) {
|
||||
spawn(proc() {
|
||||
Thread::spawn(move || {
|
||||
println!("Hello, world!");
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This program creates ten threads, who all print `Hello, world!`. The `spawn`
|
||||
function takes one argument, a `proc`. 'proc' is short for 'procedure,' and is
|
||||
a form of closure. This closure is executed in a new thread, created by `spawn`
|
||||
itself.
|
||||
This program creates ten threads, who all print `Hello, world!`. The
|
||||
`spawn` function takes one argument, a closure, indicated by the
|
||||
double bars `||`. (The `move` keyword indicates that the closure takes
|
||||
ownership of any data it uses; we'll have more on the significance of
|
||||
this shortly.) This closure is executed in a new thread created by
|
||||
`spawn`. The `detach` method means that the child thread is allowed to
|
||||
outlive its parent.
|
||||
|
||||
One common form of problem in concurrent programs is a 'data race.' This occurs
|
||||
when two different threads attempt to access the same location in memory in a
|
||||
non-synchronized way, where at least one of them is a write. If one thread is
|
||||
attempting to read, and one thread is attempting to write, you cannot be sure
|
||||
that your data will not be corrupted. Note the first half of that requirement:
|
||||
two threads that attempt to access the same location in memory. Rust's
|
||||
ownership model can track which pointers own which memory locations, which
|
||||
solves this problem.
|
||||
One common form of problem in concurrent programs is a 'data race.'
|
||||
This occurs when two different threads attempt to access the same
|
||||
location in memory in a non-synchronized way, where at least one of
|
||||
them is a write. If one thread is attempting to read, and one thread
|
||||
is attempting to write, you cannot be sure that your data will not be
|
||||
corrupted. Note the first half of that requirement: two threads that
|
||||
attempt to access the same location in memory. Rust's ownership model
|
||||
can track which pointers own which memory locations, which solves this
|
||||
problem.
|
||||
|
||||
Let's see an example. This Rust code will not compile:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::thread::Thread;
|
||||
|
||||
fn main() {
|
||||
let mut numbers = vec![1i, 2i, 3i];
|
||||
|
||||
for i in range(0u, 3u) {
|
||||
spawn(proc() {
|
||||
Thread::spawn(move || {
|
||||
for j in range(0, 3) { numbers[j] += 1 }
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It gives us this error:
|
||||
|
||||
```{notrust,ignore}
|
||||
```text
|
||||
6:71 error: capture of moved value: `numbers`
|
||||
for j in range(0, 3) { numbers[j] += 1 }
|
||||
^~~~~~~
|
||||
7:50 note: `numbers` moved into closure environment here because it has type `proc():Send`, which is non-copyable (perhaps you meant to use clone()?)
|
||||
spawn(proc() {
|
||||
7:50 note: `numbers` moved into closure environment here
|
||||
spawn(move || {
|
||||
for j in range(0, 3) { numbers[j] += 1 }
|
||||
});
|
||||
6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing)
|
||||
@ -441,11 +449,16 @@ It gives us this error:
|
||||
^~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
It mentions that "numbers moved into closure environment". Because we referred
|
||||
to `numbers` inside of our `proc`, and we create three `proc`s, we would have
|
||||
three references. Rust detects this and gives us the error: we claim that
|
||||
`numbers` has ownership, but our code tries to make three owners. This may
|
||||
cause a safety problem, so Rust disallows it.
|
||||
It mentions that "numbers moved into closure environment". Because we
|
||||
declared the closure as a moving closure, and it referred to
|
||||
`numbers`, the closure will try to take ownership of the vector. But
|
||||
the closure itself is created in a loop, and hence we will actually
|
||||
create three closures, one for every iteration of the loop. This means
|
||||
that all three of those closures would try to own `numbers`, which is
|
||||
impossible -- `numbers` must have just one owner. Rust detects this
|
||||
and gives us the error: we claim that `numbers` has ownership, but our
|
||||
code tries to make three owners. This may cause a safety problem, so
|
||||
Rust disallows it.
|
||||
|
||||
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
|
||||
"Arc" stands for "atomically reference counted." In other words, an Arc will
|
||||
@ -461,6 +474,7 @@ mutation doesn't cause a data race.
|
||||
Here's what using an Arc with a Mutex looks like:
|
||||
|
||||
```{rust}
|
||||
use std::thread::Thread;
|
||||
use std::sync::{Arc,Mutex};
|
||||
|
||||
fn main() {
|
||||
@ -468,13 +482,13 @@ fn main() {
|
||||
|
||||
for i in range(0u, 3u) {
|
||||
let number = numbers.clone();
|
||||
spawn(proc() {
|
||||
Thread::spawn(move || {
|
||||
let mut array = number.lock();
|
||||
|
||||
(*array)[i] += 1;
|
||||
|
||||
println!("numbers[{}] is {}", i, (*array)[i]);
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -524,13 +538,15 @@ As an example, Rust's ownership system is _entirely_ at compile time. The
|
||||
safety check that makes this an error about moved values:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::thread::Thread;
|
||||
|
||||
fn main() {
|
||||
let vec = vec![1i, 2, 3];
|
||||
|
||||
for i in range(1u, 3) {
|
||||
spawn(proc() {
|
||||
Thread::spawn(move || {
|
||||
println!("{}", vec[i]);
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -1,29 +0,0 @@
|
||||
# Add here a list of target languages; po4a will automatically
|
||||
# generates .po for them and build .md when translated, eg:
|
||||
# [po4a_langs] es fr it pt_BR
|
||||
[po4a_langs] ja
|
||||
[po4a_paths] doc/po/$master.pot $lang:src/doc/po/$lang/$master.po
|
||||
|
||||
# Add here below all source documents to be translated
|
||||
[type: text] src/doc/complement-bugreport.md $lang:doc/l10n/$lang/complement-bugreport.md
|
||||
[type: text] src/doc/complement-design-faq.md $lang:doc/l10n/$lang/complement-design-faq.md
|
||||
[type: text] src/doc/complement-lang-faq.md $lang:doc/l10n/$lang/complement-lang-faq.md
|
||||
[type: text] src/doc/complement-project-faq.md $lang:doc/l10n/$lang/complement-project-faq.md
|
||||
[type: text] src/doc/guide-container.md $lang:doc/l10n/$lang/guide-container.md
|
||||
[type: text] src/doc/guide-ffi.md $lang:doc/l10n/$lang/guide-ffi.md
|
||||
[type: text] src/doc/guide-lifetimes.md $lang:doc/l10n/$lang/guide-lifetimes.md
|
||||
[type: text] src/doc/guide-macros.md $lang:doc/l10n/$lang/guide-macros.md
|
||||
[type: text] src/doc/guide-plugin.md $lang:doc/l10n/$lang/guide-plugin.md
|
||||
[type: text] src/doc/guide-pointers.md $lang:doc/l10n/$lang/guide-pointers.md
|
||||
[type: text] src/doc/guide-strings.md $lang:doc/l10n/$lang/guide-strings.md
|
||||
[type: text] src/doc/guide-tasks.md $lang:doc/l10n/$lang/guide-tasks.md
|
||||
[type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md
|
||||
[type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-unsafe.md
|
||||
[type: text] src/doc/guide-crates.md $lang:doc/l10n/$lang/guide-crates.md
|
||||
[type: text] src/doc/guide-error-handling.md $lang:doc/l10n/$lang/guide-error-handling.md
|
||||
[type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md
|
||||
[type: text] src/doc/index.md $lang:doc/l10n/$lang/index.md
|
||||
[type: text] src/doc/intro.md $lang:doc/l10n/$lang/intro.md
|
||||
[type: text] src/doc/rust.md $lang:doc/l10n/$lang/rust.md
|
||||
[type: text] src/doc/rustdoc.md $lang:doc/l10n/$lang/rustdoc.md
|
||||
[type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md
|
@ -187,19 +187,18 @@ grammar as double-quoted strings. Other tokens have exact rules given.
|
||||
|
||||
<p id="keyword-table-marker"></p>
|
||||
|
||||
| | | | | |
|
||||
|----------|----------|----------|----------|--------|
|
||||
| abstract | alignof | as | be | box |
|
||||
| break | const | continue | crate | do |
|
||||
| else | enum | extern | false | final |
|
||||
| fn | for | if | impl | in |
|
||||
| let | loop | match | mod | move |
|
||||
| mut | offsetof | once | override | priv |
|
||||
| proc | pub | pure | ref | return |
|
||||
| sizeof | static | self | struct | super |
|
||||
| true | trait | type | typeof | unsafe |
|
||||
| unsized | use | virtual | where | while |
|
||||
| yield | | | | |
|
||||
| | | | | |
|
||||
|----------|----------|----------|----------|---------|
|
||||
| abstract | alignof | as | be | box |
|
||||
| break | const | continue | crate | do |
|
||||
| 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 |
|
||||
|
||||
|
||||
Each of these keywords has special meaning in its grammar, and all of them are
|
||||
@ -496,9 +495,8 @@ Examples of integer literals of various forms:
|
||||
|
||||
A _floating-point literal_ has one of two forms:
|
||||
|
||||
* Two _decimal literals_ separated by a period
|
||||
character `U+002E` (`.`), with an optional _exponent_ trailing after the
|
||||
second decimal literal.
|
||||
* A _decimal literal_ followed by a period character `U+002E` (`.`). This is
|
||||
optionally followed by another decimal literal, with an optional _exponent_.
|
||||
* A single _decimal literal_ followed by an _exponent_.
|
||||
|
||||
By default, a floating-point literal has a generic type, and, like integer
|
||||
@ -509,20 +507,25 @@ types), which explicitly determine the type of the literal.
|
||||
Examples of floating-point literals of various forms:
|
||||
|
||||
```
|
||||
123.0f64; // type f64
|
||||
0.1f64; // type f64
|
||||
0.1f32; // type f32
|
||||
12E+99_f64; // type f64
|
||||
123.0f64; // type f64
|
||||
0.1f64; // type f64
|
||||
0.1f32; // type f32
|
||||
12E+99_f64; // type f64
|
||||
let x: f64 = 2.; // type f64
|
||||
```
|
||||
|
||||
##### Boolean literals
|
||||
This last example is different because it is not possible to use the suffix
|
||||
syntax with a floating point literal ending in a period. `2.f64` would attempt
|
||||
to call a method named `f64` on `2`.
|
||||
|
||||
#### Boolean literals
|
||||
|
||||
The two values of the boolean type are written `true` and `false`.
|
||||
|
||||
### Symbols
|
||||
|
||||
```{.ebnf .gram}
|
||||
symbol : "::" "->"
|
||||
symbol : "::" | "->"
|
||||
| '#' | '[' | ']' | '(' | ')' | '{' | '}'
|
||||
| ',' | ';' ;
|
||||
```
|
||||
@ -777,13 +780,8 @@ metadata that influences the behavior of the compiler.
|
||||
|
||||
```{.rust}
|
||||
# #![allow(unused_attribute)]
|
||||
// Crate ID
|
||||
#![crate_id = "projx#2.5"]
|
||||
|
||||
// Additional metadata attributes
|
||||
#![desc = "Project X"]
|
||||
#![license = "BSD"]
|
||||
#![comment = "This is a comment on Project X."]
|
||||
// Crate name
|
||||
#![crate_name = "projx"]
|
||||
|
||||
// Specify the output type
|
||||
#![crate_type = "lib"]
|
||||
@ -936,7 +934,7 @@ kinds of view items:
|
||||
|
||||
```{.ebnf .gram}
|
||||
extern_crate_decl : "extern" "crate" crate_name
|
||||
crate_name: ident | ( string_lit as ident )
|
||||
crate_name: ident | ( string_lit "as" ident )
|
||||
```
|
||||
|
||||
An _`extern crate` declaration_ specifies a dependency on an external crate.
|
||||
@ -999,7 +997,7 @@ An example of `use` declarations:
|
||||
|
||||
```
|
||||
use std::iter::range_step;
|
||||
use std::option::{Some, None};
|
||||
use std::option::Option::{Some, None};
|
||||
use std::collections::hash_map::{mod, HashMap};
|
||||
|
||||
fn foo<T>(_: T){}
|
||||
@ -1009,8 +1007,8 @@ fn main() {
|
||||
// Equivalent to 'std::iter::range_step(0u, 10u, 2u);'
|
||||
range_step(0u, 10u, 2u);
|
||||
|
||||
// Equivalent to 'foo(vec![std::option::Some(1.0f64),
|
||||
// std::option::None]);'
|
||||
// Equivalent to 'foo(vec![std::option::Option::Some(1.0f64),
|
||||
// std::option::Option::None]);'
|
||||
foo(vec![Some(1.0f64), None]);
|
||||
|
||||
// Both `hash_map` and `HashMap` are in scope.
|
||||
@ -1319,10 +1317,10 @@ let fptr: extern "C" fn() -> int = new_int;
|
||||
Extern functions may be called directly from Rust code as Rust uses large,
|
||||
contiguous stack segments like C.
|
||||
|
||||
### Type definitions
|
||||
### Type aliases
|
||||
|
||||
A _type definition_ defines a new name for an existing [type](#types). Type
|
||||
definitions are declared with the keyword `type`. Every value has a single,
|
||||
A _type alias_ defines a new name for an existing [type](#types). Type
|
||||
aliases are declared with the keyword `type`. Every value has a single,
|
||||
specific type; the type-specified aspects of a value include:
|
||||
|
||||
* Whether the value is composed of sub-values or is indivisible.
|
||||
@ -1334,7 +1332,12 @@ specific type; the type-specified aspects of a value include:
|
||||
For example, the type `(u8, u8)` defines the set of immutable values that are
|
||||
composite pairs, each containing two unsigned 8-bit integers accessed by
|
||||
pattern-matching and laid out in memory with the `x` component preceding the
|
||||
`y` component.
|
||||
`y` component:
|
||||
|
||||
```
|
||||
type Point = (u8, u8);
|
||||
let p: Point = (41, 68);
|
||||
```
|
||||
|
||||
### Structures
|
||||
|
||||
@ -1660,6 +1663,7 @@ Implementations are defined with the keyword `impl`.
|
||||
|
||||
```
|
||||
# struct Point {x: f64, y: f64};
|
||||
# impl Copy for Point {}
|
||||
# type Surface = int;
|
||||
# struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
|
||||
# trait Shape { fn draw(&self, Surface); fn bounding_box(&self) -> BoundingBox; }
|
||||
@ -1669,6 +1673,8 @@ struct Circle {
|
||||
center: Point,
|
||||
}
|
||||
|
||||
impl Copy for Circle {}
|
||||
|
||||
impl Shape for Circle {
|
||||
fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
|
||||
fn bounding_box(&self) -> BoundingBox {
|
||||
@ -1684,7 +1690,20 @@ methods in such an implementation can only be used as direct calls on the
|
||||
values of the type that the implementation targets. In such an implementation,
|
||||
the trait type and `for` after `impl` are omitted. Such implementations are
|
||||
limited to nominal types (enums, structs), and the implementation must appear
|
||||
in the same module or a sub-module as the `self` type.
|
||||
in the same module or a sub-module as the `self` type:
|
||||
|
||||
```
|
||||
struct Point {x: int, y: int}
|
||||
|
||||
impl Point {
|
||||
fn log(&self) {
|
||||
println!("Point is at ({}, {})", self.x, self.y);
|
||||
}
|
||||
}
|
||||
|
||||
let my_point = Point {x: 10, y:11};
|
||||
my_point.log();
|
||||
```
|
||||
|
||||
When a trait _is_ specified in an `impl`, all methods declared as part of the
|
||||
trait must be implemented, with matching types and type parameter counts.
|
||||
@ -1778,6 +1797,7 @@ default visibility with the `priv` keyword. When an item is declared as `pub`,
|
||||
it can be thought of as being accessible to the outside world. For example:
|
||||
|
||||
```
|
||||
# #![allow(missing_copy_implementations)]
|
||||
# fn main() {}
|
||||
// Declare a private struct
|
||||
struct Foo;
|
||||
@ -1943,7 +1963,7 @@ An example of attributes:
|
||||
|
||||
```{.rust}
|
||||
// General metadata applied to the enclosing module or crate.
|
||||
#![license = "BSD"]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// A function marked as a unit test
|
||||
#[test]
|
||||
@ -2528,10 +2548,6 @@ The currently implemented features of the reference compiler are:
|
||||
* `default_type_params` - Allows use of default type parameters. The future of
|
||||
this feature is uncertain.
|
||||
|
||||
* `if_let` - Allows use of the `if let` syntax.
|
||||
|
||||
* `while_let` - Allows use of the `while let` syntax.
|
||||
|
||||
* `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
|
||||
are inherently unstable and no promise about them is made.
|
||||
|
||||
@ -2618,8 +2634,6 @@ The currently implemented features of the reference compiler are:
|
||||
which is considered wildly unsafe and will be
|
||||
obsoleted by language improvements.
|
||||
|
||||
* `tuple_indexing` - Allows use of tuple indexing (expressions like `expr.0`)
|
||||
|
||||
* `associated_types` - Allows type aliases in traits. Experimental.
|
||||
|
||||
If a feature is promoted to a language feature, then all existing programs will
|
||||
@ -3124,8 +3138,8 @@ as
|
||||
```
|
||||
|
||||
Operators at the same precedence level are evaluated left-to-right. [Unary
|
||||
operators](#unary-operator-expressions) have the same precedence level and it
|
||||
is stronger than any of the binary operators'.
|
||||
operators](#unary-operator-expressions) have the same precedence level and are
|
||||
stronger than any of the binary operators.
|
||||
|
||||
### Grouped expressions
|
||||
|
||||
@ -3163,7 +3177,7 @@ Some examples of call expressions:
|
||||
# fn add(x: int, y: int) -> int { 0 }
|
||||
|
||||
let x: int = add(1, 2);
|
||||
let pi: Option<f32> = from_str("3.14");
|
||||
let pi: Option<f32> = "3.14".parse();
|
||||
```
|
||||
|
||||
### Lambda expressions
|
||||
@ -3821,8 +3835,6 @@ x = bo(5,7);
|
||||
```{.ebnf .notation}
|
||||
closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
|
||||
[ ':' bound-list ] [ '->' type ]
|
||||
procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')'
|
||||
[ ':' bound-list ] [ '->' type ]
|
||||
lifetime-list := lifetime | lifetime ',' lifetime-list
|
||||
arg-list := ident ':' type | ident ':' type ',' arg-list
|
||||
bound-list := bound | bound '+' bound-list
|
||||
@ -3831,8 +3843,6 @@ bound := path | lifetime
|
||||
|
||||
The type of a closure mapping an input of type `A` to an output of type `B` is
|
||||
`|A| -> B`. A closure with no arguments or return values has type `||`.
|
||||
Similarly, a procedure mapping `A` to `B` is `proc(A) -> B` and a no-argument
|
||||
and no-return value closure has type `proc()`.
|
||||
|
||||
An example of creating and calling a closure:
|
||||
|
||||
@ -3855,30 +3865,6 @@ call_closure(closure_no_args, closure_args);
|
||||
|
||||
```
|
||||
|
||||
Unlike closures, procedures may only be invoked once, but own their
|
||||
environment, and are allowed to move out of their environment. Procedures are
|
||||
allocated on the heap (unlike closures). An example of creating and calling a
|
||||
procedure:
|
||||
|
||||
```rust
|
||||
let string = "Hello".to_string();
|
||||
|
||||
// Creates a new procedure, passing it to the `spawn` function.
|
||||
spawn(proc() {
|
||||
println!("{} world!", string);
|
||||
});
|
||||
|
||||
// the variable `string` has been moved into the previous procedure, so it is
|
||||
// no longer usable.
|
||||
|
||||
|
||||
// Create an invoke a procedure. Note that the procedure is *moved* when
|
||||
// invoked, so it cannot be invoked again.
|
||||
let f = proc(n: int) { n + 22 };
|
||||
println!("answer: {}", f(20));
|
||||
|
||||
```
|
||||
|
||||
### Object types
|
||||
|
||||
Every trait item (see [traits](#traits)) defines a type with the same name as
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
* Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
* file at the top-level directory of this distribution and at
|
||||
* http://rust-lang.org/COPYRIGHT.
|
||||
* With elements taken from Bootstrap v3.0.2 (MIT licensed).
|
||||
@ -209,7 +209,6 @@ pre {
|
||||
code {
|
||||
padding: 0 2px;
|
||||
color: #8D1A38;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
pre code {
|
||||
padding: 0;
|
||||
|
@ -210,11 +210,11 @@ that one can still write things like `#[deriving(Eq)]`).
|
||||
# // what's actually being documented.
|
||||
# fn fib(n: int) { n + 2 }
|
||||
|
||||
spawn(proc() { fib(200); })
|
||||
spawn(move || { fib(200); })
|
||||
```
|
||||
~~~
|
||||
|
||||
The documentation online would look like `spawn(proc() { fib(200); })`, but when
|
||||
The documentation online would look like `spawn(move || { fib(200); })`, but when
|
||||
testing this code, the `fib` function will be included (so it can compile).
|
||||
|
||||
## Running tests (advanced)
|
||||
|
@ -8,12 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![no_start]
|
||||
|
||||
#[cfg(rustdoc)]
|
||||
extern crate "rustdoc" as this;
|
||||
|
||||
#[cfg(rustc)]
|
||||
extern crate "rustc_trans" as this;
|
||||
extern crate "rustc_driver" as this;
|
||||
|
||||
fn main() { this::main() }
|
||||
|
@ -31,9 +31,6 @@
|
||||
(modify-syntax-entry ?\" "\"" table)
|
||||
(modify-syntax-entry ?\\ "\\" table)
|
||||
|
||||
;; _ is a word-char
|
||||
(modify-syntax-entry ?_ "w" table)
|
||||
|
||||
;; Comments
|
||||
(modify-syntax-entry ?/ ". 124b" table)
|
||||
(modify-syntax-entry ?* ". 23" table)
|
||||
@ -177,7 +174,7 @@
|
||||
"if" "impl" "in"
|
||||
"let" "loop"
|
||||
"match" "mod" "move" "mut"
|
||||
"priv" "proc" "pub"
|
||||
"priv" "pub"
|
||||
"ref" "return"
|
||||
"self" "static" "struct" "super"
|
||||
"true" "trait" "type"
|
||||
@ -397,7 +394,7 @@ This is written mainly to be used as `beginning-of-defun-function' for Rust.
|
||||
Don't move to the beginning of the line. `beginning-of-defun',
|
||||
which calls this, does that afterwards."
|
||||
(interactive "p")
|
||||
(re-search-backward (concat "^\\(" rust-top-item-beg-re "\\)\\b")
|
||||
(re-search-backward (concat "^\\(" rust-top-item-beg-re "\\)\\_>")
|
||||
nil 'move (or arg 1)))
|
||||
|
||||
(defun rust-end-of-defun ()
|
||||
|
@ -54,13 +54,14 @@ def rust_pretty_printer_lookup_function(val):
|
||||
return RustStructPrinter(val, false)
|
||||
|
||||
if enum_member_count == 1:
|
||||
if enum_members[0].name == None:
|
||||
first_variant_name = enum_members[0].name
|
||||
if first_variant_name == None:
|
||||
# This is a singleton enum
|
||||
return rust_pretty_printer_lookup_function(val[enum_members[0]])
|
||||
else:
|
||||
assert enum_members[0].name.startswith("RUST$ENCODED$ENUM$")
|
||||
assert first_variant_name.startswith("RUST$ENCODED$ENUM$")
|
||||
# This is a space-optimized enum
|
||||
last_separator_index = enum_members[0].name.rfind("$")
|
||||
last_separator_index = first_variant_name.rfind("$")
|
||||
second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index)
|
||||
disr_field_index = first_variant_name[second_last_separator_index + 1 :
|
||||
last_separator_index]
|
||||
@ -68,7 +69,12 @@ def rust_pretty_printer_lookup_function(val):
|
||||
|
||||
sole_variant_val = val[enum_members[0]]
|
||||
disr_field = get_field_at_index(sole_variant_val, disr_field_index)
|
||||
discriminant = int(sole_variant_val[disr_field])
|
||||
discriminant = sole_variant_val[disr_field]
|
||||
|
||||
# If the discriminant field is a fat pointer we have to consider the
|
||||
# first word as the true discriminant
|
||||
if discriminant.type.code == gdb.TYPE_CODE_STRUCT:
|
||||
discriminant = discriminant[get_field_at_index(discriminant, 0)]
|
||||
|
||||
if discriminant == 0:
|
||||
null_variant_name = first_variant_name[last_separator_index + 1:]
|
||||
@ -173,7 +179,7 @@ class RustCStyleEnumPrinter:
|
||||
|
||||
class IdentityPrinter:
|
||||
def __init__(self, string):
|
||||
self.string
|
||||
self.string = string
|
||||
|
||||
def to_string(self):
|
||||
return self.string
|
||||
|
@ -270,6 +270,7 @@
|
||||
'|"|
|
||||
\\|n|r|t|0|
|
||||
x\%{hex_digit}{2}|
|
||||
u{\%{hex_digit}{1,6}}|
|
||||
u\%{hex_digit}{4}|
|
||||
U\%{hex_digit}{8}
|
||||
</define-regex>
|
||||
|
@ -1,519 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
msg() {
|
||||
echo "install: $1"
|
||||
}
|
||||
|
||||
step_msg() {
|
||||
msg
|
||||
msg "$1"
|
||||
msg
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "install: WARNING: $1"
|
||||
}
|
||||
|
||||
err() {
|
||||
echo "install: error: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
need_ok() {
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
err "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
if command -v $1 >/dev/null 2>&1
|
||||
then msg "found $1"
|
||||
else err "need $1"
|
||||
fi
|
||||
}
|
||||
|
||||
putvar() {
|
||||
local T
|
||||
eval T=\$$1
|
||||
eval TLEN=\${#$1}
|
||||
if [ $TLEN -gt 35 ]
|
||||
then
|
||||
printf "install: %-20s := %.35s ...\n" $1 "$T"
|
||||
else
|
||||
printf "install: %-20s := %s %s\n" $1 "$T" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
valopt() {
|
||||
VAL_OPTIONS="$VAL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
local DEFAULT=$2
|
||||
shift
|
||||
shift
|
||||
local DOC="$*"
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
|
||||
local V="CFG_${UOP}"
|
||||
eval $V="$DEFAULT"
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if echo "$arg" | grep -q -- "--$OP="
|
||||
then
|
||||
val=$(echo "$arg" | cut -f2 -d=)
|
||||
eval $V=$val
|
||||
fi
|
||||
done
|
||||
putvar $V
|
||||
else
|
||||
if [ -z "$DEFAULT" ]
|
||||
then
|
||||
DEFAULT="<none>"
|
||||
fi
|
||||
OP="${OP}=[${DEFAULT}]"
|
||||
printf " --%-30s %s\n" "$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
opt() {
|
||||
BOOL_OPTIONS="$BOOL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
local DEFAULT=$2
|
||||
shift
|
||||
shift
|
||||
local DOC="$*"
|
||||
local FLAG=""
|
||||
|
||||
if [ $DEFAULT -eq 0 ]
|
||||
then
|
||||
FLAG="enable"
|
||||
else
|
||||
FLAG="disable"
|
||||
DOC="don't $DOC"
|
||||
fi
|
||||
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if [ "$arg" = "--${FLAG}-${OP}" ]
|
||||
then
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
|
||||
local V="CFG_${FLAG}_${OP}"
|
||||
eval $V=1
|
||||
putvar $V
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ ! -z "$META" ]
|
||||
then
|
||||
OP="$OP=<$META>"
|
||||
fi
|
||||
printf " --%-30s %s\n" "$FLAG-$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
flag() {
|
||||
BOOL_OPTIONS="$BOOL_OPTIONS $1"
|
||||
|
||||
local OP=$1
|
||||
shift
|
||||
local DOC="$*"
|
||||
|
||||
if [ $HELP -eq 0 ]
|
||||
then
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
if [ "$arg" = "--${OP}" ]
|
||||
then
|
||||
OP=$(echo $OP | tr 'a-z-' 'A-Z_')
|
||||
local V="CFG_${OP}"
|
||||
eval $V=1
|
||||
putvar $V
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ ! -z "$META" ]
|
||||
then
|
||||
OP="$OP=<$META>"
|
||||
fi
|
||||
printf " --%-30s %s\n" "$OP" "$DOC"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_opt () {
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
isArgValid=0
|
||||
for option in $BOOL_OPTIONS
|
||||
do
|
||||
if test --disable-$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
if test --enable-$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
if test --$option = $arg
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
done
|
||||
for option in $VAL_OPTIONS
|
||||
do
|
||||
if echo "$arg" | grep -q -- "--$option="
|
||||
then
|
||||
isArgValid=1
|
||||
fi
|
||||
done
|
||||
if [ "$arg" = "--help" ]
|
||||
then
|
||||
echo
|
||||
echo "No more help available for Configure options,"
|
||||
echo "check the Wiki or join our IRC channel"
|
||||
break
|
||||
else
|
||||
if test $isArgValid -eq 0
|
||||
then
|
||||
err "Option '$arg' is not recognized"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
absolutify() {
|
||||
FILE_PATH="${1}"
|
||||
FILE_PATH_DIRNAME="$(dirname ${FILE_PATH})"
|
||||
FILE_PATH_BASENAME="$(basename ${FILE_PATH})"
|
||||
FILE_ABS_PATH="$(cd ${FILE_PATH_DIRNAME} && pwd)"
|
||||
FILE_PATH="${FILE_ABS_PATH}/${FILE_PATH_BASENAME}"
|
||||
# This is the return value
|
||||
ABSOLUTIFIED="${FILE_PATH}"
|
||||
}
|
||||
|
||||
msg "looking for install programs"
|
||||
need_cmd mkdir
|
||||
need_cmd printf
|
||||
need_cmd cut
|
||||
need_cmd grep
|
||||
need_cmd uname
|
||||
need_cmd tr
|
||||
need_cmd sed
|
||||
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)"
|
||||
CFG_SELF="$0"
|
||||
CFG_ARGS="$@"
|
||||
|
||||
HELP=0
|
||||
if [ "$1" = "--help" ]
|
||||
then
|
||||
HELP=1
|
||||
shift
|
||||
echo
|
||||
echo "Usage: $CFG_SELF [options]"
|
||||
echo
|
||||
echo "Options:"
|
||||
echo
|
||||
else
|
||||
step_msg "processing $CFG_SELF args"
|
||||
fi
|
||||
|
||||
# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE.
|
||||
# This logic is duplicated from configure in order to get the correct libdir
|
||||
# for Windows installs.
|
||||
CFG_OSTYPE=$(uname -s)
|
||||
|
||||
case $CFG_OSTYPE in
|
||||
|
||||
MINGW32*)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
;;
|
||||
|
||||
MINGW64*)
|
||||
# msys2, MSYSTEM=MINGW64
|
||||
CFG_OSTYPE=w64-mingw32
|
||||
;;
|
||||
|
||||
# Thad's Cygwin identifers below
|
||||
|
||||
# Vista 32 bit
|
||||
CYGWIN_NT-6.0)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
;;
|
||||
|
||||
# Vista 64 bit
|
||||
CYGWIN_NT-6.0-WOW64)
|
||||
CFG_OSTYPE=w64-mingw32
|
||||
;;
|
||||
|
||||
# Win 7 32 bit
|
||||
CYGWIN_NT-6.1)
|
||||
CFG_OSTYPE=pc-mingw32
|
||||
;;
|
||||
|
||||
# Win 7 64 bit
|
||||
CYGWIN_NT-6.1-WOW64)
|
||||
CFG_OSTYPE=w64-mingw32
|
||||
;;
|
||||
esac
|
||||
|
||||
OPTIONS=""
|
||||
BOOL_OPTIONS=""
|
||||
VAL_OPTIONS=""
|
||||
|
||||
# On windows we just store the libraries in the bin directory because
|
||||
# there's no rpath. This is where the build system itself puts libraries;
|
||||
# --libdir is used to configure the installation directory.
|
||||
# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk
|
||||
CFG_LIBDIR_RELATIVE=lib
|
||||
if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
|
||||
then
|
||||
CFG_LIBDIR_RELATIVE=bin
|
||||
fi
|
||||
|
||||
if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
|
||||
then
|
||||
CFG_LD_PATH_VAR=PATH
|
||||
CFG_OLD_LD_PATH_VAR=$PATH
|
||||
elif [ "$CFG_OSTYPE" = "Darwin" ]
|
||||
then
|
||||
CFG_LD_PATH_VAR=DYLD_LIBRARY_PATH
|
||||
CFG_OLD_LD_PATH_VAR=$DYLD_LIBRARY_PATH
|
||||
else
|
||||
CFG_LD_PATH_VAR=LD_LIBRARY_PATH
|
||||
CFG_OLD_LD_PATH_VAR=$LD_LIBRARY_PATH
|
||||
fi
|
||||
|
||||
flag uninstall "only uninstall from the installation prefix"
|
||||
opt verify 1 "verify that the installed binaries run correctly"
|
||||
valopt prefix "/usr/local" "set installation prefix"
|
||||
# NB This is exactly the same definition as in `configure`.
|
||||
valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries"
|
||||
case "$CFG_LIBDIR" in
|
||||
"$CFG_PREFIX"/*) CAT_INC=2;;
|
||||
"$CFG_PREFIX"*) CAT_INC=1;;
|
||||
*)
|
||||
err "libdir must begin with the prefix. Use --prefix to set it accordingly.";;
|
||||
esac
|
||||
CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-`
|
||||
|
||||
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
|
||||
|
||||
if [ $HELP -eq 1 ]
|
||||
then
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
step_msg "validating $CFG_SELF args"
|
||||
validate_opt
|
||||
|
||||
|
||||
# OK, let's get installing ...
|
||||
|
||||
# Sanity check: can we run the binaries?
|
||||
if [ -z "${CFG_DISABLE_VERIFY}" ]
|
||||
then
|
||||
# Don't do this if uninstalling. Failure here won't help in any way.
|
||||
if [ -z "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
msg "verifying platform can run binaries"
|
||||
export $CFG_LD_PATH_VAR="${CFG_SRC_DIR}/lib:$CFG_OLD_LD_PATH_VAR"
|
||||
"${CFG_SRC_DIR}/bin/rustc" --version > /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
err "can't execute rustc binary on this platform"
|
||||
fi
|
||||
export $CFG_LD_PATH_VAR=$CFG_OLD_LD_PATH_VAR
|
||||
fi
|
||||
fi
|
||||
|
||||
# Sanity check: can we can write to the destination?
|
||||
msg "verifying destination is writable"
|
||||
umask 022 && mkdir -p "${CFG_LIBDIR}"
|
||||
need_ok "can't write to destination. consider \`sudo\`."
|
||||
touch "${CFG_LIBDIR}/rust-install-probe" > /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
err "can't write to destination. consider \`sudo\`."
|
||||
fi
|
||||
rm -f "${CFG_LIBDIR}/rust-install-probe"
|
||||
need_ok "failed to remove install probe"
|
||||
|
||||
# Sanity check: don't install to the directory containing the installer.
|
||||
# That would surely cause chaos.
|
||||
msg "verifying destination is not the same as source"
|
||||
INSTALLER_DIR="$(cd $(dirname $0) && pwd)"
|
||||
PREFIX_DIR="$(cd ${CFG_PREFIX} && pwd)"
|
||||
if [ "${INSTALLER_DIR}" = "${PREFIX_DIR}" ]
|
||||
then
|
||||
err "can't install to same directory as installer"
|
||||
fi
|
||||
|
||||
# Using an absolute path to libdir in a few places so that the status
|
||||
# messages are consistently using absolute paths.
|
||||
absolutify "${CFG_LIBDIR}"
|
||||
ABS_LIBDIR="${ABSOLUTIFIED}"
|
||||
|
||||
# The file name of the manifest we're going to create during install
|
||||
INSTALLED_MANIFEST="${ABS_LIBDIR}/rustlib/manifest"
|
||||
|
||||
# First, uninstall from the installation prefix.
|
||||
# Errors are warnings - try to rm everything in the manifest even if some fail.
|
||||
if [ -f "${INSTALLED_MANIFEST}" ]
|
||||
then
|
||||
# Iterate through installed manifest and remove files
|
||||
while read p; do
|
||||
# The installed manifest contains absolute paths
|
||||
msg "removing $p"
|
||||
if [ -f "$p" ]
|
||||
then
|
||||
rm -f "$p"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
warn "failed to remove $p"
|
||||
fi
|
||||
else
|
||||
warn "supposedly installed file $p does not exist!"
|
||||
fi
|
||||
done < "${INSTALLED_MANIFEST}"
|
||||
|
||||
# If we fail to remove rustlib below, then the installed manifest will
|
||||
# still be full; the installed manifest needs to be empty before install.
|
||||
msg "removing ${INSTALLED_MANIFEST}"
|
||||
rm -f "${INSTALLED_MANIFEST}"
|
||||
# For the above reason, this is a hard error
|
||||
need_ok "failed to remove installed manifest"
|
||||
|
||||
# Remove 'rustlib' directory
|
||||
msg "removing ${ABS_LIBDIR}/rustlib"
|
||||
rm -Rf "${ABS_LIBDIR}/rustlib"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
warn "failed to remove rustlib"
|
||||
fi
|
||||
else
|
||||
# There's no manifest. If we were asked to uninstall, then that's a problem.
|
||||
if [ -n "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
err "unable to find installation manifest at ${CFG_LIBDIR}/rustlib"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we're only uninstalling then exit
|
||||
if [ -n "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
echo
|
||||
echo " Rust is uninstalled. Have a nice day."
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create the installed manifest, which we will fill in with absolute file paths
|
||||
mkdir -p "${CFG_LIBDIR}/rustlib"
|
||||
need_ok "failed to create rustlib"
|
||||
touch "${INSTALLED_MANIFEST}"
|
||||
need_ok "failed to create installed manifest"
|
||||
|
||||
# Now install, iterate through the new manifest and copy files
|
||||
while read p; do
|
||||
|
||||
# Decide the destination of the file
|
||||
FILE_INSTALL_PATH="${CFG_PREFIX}/$p"
|
||||
|
||||
if echo "$p" | grep "^${CFG_LIBDIR_RELATIVE}/" > /dev/null
|
||||
then
|
||||
pp=`echo $p | sed "s%^${CFG_LIBDIR_RELATIVE}/%%"`
|
||||
FILE_INSTALL_PATH="${CFG_LIBDIR}/$pp"
|
||||
fi
|
||||
|
||||
if echo "$p" | grep "^share/man/" > /dev/null
|
||||
then
|
||||
pp=`echo $p | sed 's/^share\/man\///'`
|
||||
FILE_INSTALL_PATH="${CFG_MANDIR}/$pp"
|
||||
fi
|
||||
|
||||
# Make sure there's a directory for it
|
||||
umask 022 && mkdir -p "$(dirname ${FILE_INSTALL_PATH})"
|
||||
need_ok "directory creation failed"
|
||||
|
||||
# Make the path absolute so we can uninstall it later without
|
||||
# starting from the installation cwd
|
||||
absolutify "${FILE_INSTALL_PATH}"
|
||||
FILE_INSTALL_PATH="${ABSOLUTIFIED}"
|
||||
|
||||
# Install the file
|
||||
msg "${FILE_INSTALL_PATH}"
|
||||
if echo "$p" | grep "^bin/" > /dev/null
|
||||
then
|
||||
install -m755 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}"
|
||||
else
|
||||
install -m644 "${CFG_SRC_DIR}/$p" "${FILE_INSTALL_PATH}"
|
||||
fi
|
||||
need_ok "file creation failed"
|
||||
|
||||
# Update the manifest
|
||||
echo "${FILE_INSTALL_PATH}" >> "${INSTALLED_MANIFEST}"
|
||||
need_ok "failed to update manifest"
|
||||
|
||||
# The manifest lists all files to install
|
||||
done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in"
|
||||
|
||||
# Run ldconfig to make dynamic libraries available to the linker
|
||||
if [ "$CFG_OSTYPE" = "Linux" ]
|
||||
then
|
||||
ldconfig
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
warn "failed to run ldconfig."
|
||||
warn "this may happen when not installing as root and may be fine"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Sanity check: can we run the installed binaries?
|
||||
#
|
||||
# As with the verification above, make sure the right LD_LIBRARY_PATH-equivalent
|
||||
# is in place. Try first without this variable, and if that fails try again with
|
||||
# the variable. If the second time tries, print a hopefully helpful message to
|
||||
# add something to the appropriate environment variable.
|
||||
if [ -z "${CFG_DISABLE_VERIFY}" ]
|
||||
then
|
||||
msg "verifying installed binaries are executable"
|
||||
"${CFG_PREFIX}/bin/rustc" --version 2> /dev/null 1> /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
export $CFG_LD_PATH_VAR="${CFG_PREFIX}/lib:$CFG_OLD_LD_PATH_VAR"
|
||||
"${CFG_PREFIX}/bin/rustc" --version > /dev/null
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
ERR="can't execute installed rustc binary. "
|
||||
ERR="${ERR}installation may be broken. "
|
||||
ERR="${ERR}if this is expected then rerun install.sh with \`--disable-verify\` "
|
||||
ERR="${ERR}or \`make install\` with \`--disable-verify-install\`"
|
||||
err "${ERR}"
|
||||
else
|
||||
echo
|
||||
echo " Note: please ensure '${CFG_PREFIX}/lib' is added to ${CFG_LD_PATH_VAR}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo " Rust is ready to roll."
|
||||
echo
|
||||
|
||||
|
@ -38,10 +38,8 @@ exceptions = [
|
||||
"rt/isaac/randport.cpp", # public domain
|
||||
"rt/isaac/rand.h", # public domain
|
||||
"rt/isaac/standard.h", # public domain
|
||||
"libsync/mpsc_queue.rs", # BSD
|
||||
"libsync/spsc_queue.rs", # BSD
|
||||
"libsync/mpmc_bounded_queue.rs", # BSD
|
||||
"libsync/mpsc_intrusive.rs", # BSD
|
||||
"libstd/comm/mpsc_queue.rs", # BSD
|
||||
"libstd/comm/spsc_queue.rs", # BSD
|
||||
"test/bench/shootout-binarytrees.rs", # BSD
|
||||
"test/bench/shootout-chameneos-redux.rs", # BSD
|
||||
"test/bench/shootout-fannkuch-redux.rs", # BSD
|
||||
|
@ -43,8 +43,6 @@ def print_struct_val(val, internal_dict):
|
||||
return print_struct_val_starting_from(0, val, internal_dict)
|
||||
|
||||
def print_vec_slice_val(val, internal_dict):
|
||||
output = "&["
|
||||
|
||||
length = val.GetChildAtIndex(1).GetValueAsUnsigned()
|
||||
|
||||
data_ptr_val = val.GetChildAtIndex(0)
|
||||
@ -56,16 +54,12 @@ def print_vec_slice_val(val, internal_dict):
|
||||
|
||||
start_address = data_ptr_val.GetValueAsUnsigned()
|
||||
|
||||
for i in range(length):
|
||||
def render_element(i):
|
||||
address = start_address + i * element_type_size
|
||||
element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type )
|
||||
output += print_val(element_val, internal_dict)
|
||||
element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type)
|
||||
return print_val(element_val, internal_dict)
|
||||
|
||||
if i != length - 1:
|
||||
output += ", "
|
||||
|
||||
output += "]"
|
||||
return output
|
||||
return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))
|
||||
|
||||
def print_struct_val_starting_from(field_start_index, val, internal_dict):
|
||||
'''
|
||||
@ -75,41 +69,39 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
|
||||
assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
|
||||
|
||||
t = val.GetType()
|
||||
has_field_names = type_has_field_names(t)
|
||||
type_name = extract_type_name(t.GetName())
|
||||
output = ""
|
||||
|
||||
if not type_name.startswith("("):
|
||||
# this is a tuple, so don't print the type name
|
||||
output += type_name
|
||||
|
||||
if has_field_names:
|
||||
output += " { \n"
|
||||
else:
|
||||
output += "("
|
||||
|
||||
num_children = val.num_children
|
||||
|
||||
for child_index in range(field_start_index, num_children):
|
||||
if has_field_names:
|
||||
field_name = t.GetFieldAtIndex(child_index).GetName()
|
||||
output += field_name + ": "
|
||||
if (num_children - field_start_index) == 0:
|
||||
# The only field of this struct is the enum discriminant
|
||||
return type_name
|
||||
|
||||
field_val = val.GetChildAtIndex(child_index)
|
||||
output += print_val(field_val, internal_dict)
|
||||
|
||||
if child_index != num_children - 1:
|
||||
output += ", "
|
||||
|
||||
if has_field_names:
|
||||
output += "\n"
|
||||
has_field_names = type_has_field_names(t)
|
||||
|
||||
if has_field_names:
|
||||
output += "}"
|
||||
template = "%(type_name)s {\n%(body)s\n}"
|
||||
separator = ", \n"
|
||||
else:
|
||||
output += ")"
|
||||
template = "%(type_name)s(%(body)s)"
|
||||
separator = ", "
|
||||
|
||||
return output
|
||||
if type_name.startswith("("):
|
||||
# this is a tuple, so don't print the type name
|
||||
type_name = ""
|
||||
|
||||
def render_child(child_index):
|
||||
this = ""
|
||||
if has_field_names:
|
||||
field_name = t.GetFieldAtIndex(child_index).GetName()
|
||||
this += field_name + ": "
|
||||
|
||||
field_val = val.GetChildAtIndex(child_index)
|
||||
return this + print_val(field_val, internal_dict)
|
||||
|
||||
body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
|
||||
|
||||
return template % {"type_name": type_name,
|
||||
"body": body}
|
||||
|
||||
|
||||
def print_enum_val(val, internal_dict):
|
||||
@ -117,7 +109,6 @@ def print_enum_val(val, internal_dict):
|
||||
|
||||
assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
|
||||
|
||||
|
||||
if val.num_children == 1:
|
||||
# This is either an enum with just one variant, or it is an Option-like enum
|
||||
# where the discriminant is encoded in a non-nullable pointer field. We find
|
||||
@ -147,9 +138,14 @@ def print_enum_val(val, internal_dict):
|
||||
return "<invalid enum encoding: %s>" % first_variant_name
|
||||
|
||||
# Read the discriminant
|
||||
disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index).GetValueAsUnsigned()
|
||||
disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index)
|
||||
|
||||
if disr_val == 0:
|
||||
# If the discriminant field is a fat pointer we have to consider the
|
||||
# first word as the true discriminant
|
||||
if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
|
||||
disr_val = disr_val.GetChildAtIndex(0)
|
||||
|
||||
if disr_val.GetValueAsUnsigned() == 0:
|
||||
# Null case: Print the name of the null-variant
|
||||
null_variant_name = first_variant_name[last_separator_index + 1:]
|
||||
return null_variant_name
|
||||
@ -243,3 +239,5 @@ def is_vec_slice(val):
|
||||
|
||||
type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
|
||||
return type_name.startswith("&[") and type_name.endswith("]")
|
||||
|
||||
# vi: sw=2:ts=2
|
||||
|
@ -8,6 +8,12 @@
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# Script parameters:
|
||||
# argv[1] = rust component root,
|
||||
# argv[2] = gcc component root,
|
||||
# argv[3] = target triple
|
||||
# The first two correspond to the two installable components defined in the setup script.
|
||||
|
||||
import sys, os, shutil, subprocess
|
||||
|
||||
def find_files(files, path):
|
||||
@ -22,7 +28,7 @@ def find_files(files, path):
|
||||
raise Exception("Could not find '%s' in %s" % (fname, path))
|
||||
return found
|
||||
|
||||
def make_win_dist(dist_root, target_triple):
|
||||
def make_win_dist(rust_root, gcc_root, target_triple):
|
||||
# Ask gcc where it keeps its stuff
|
||||
gcc_out = subprocess.check_output(["gcc.exe", "-print-search-dirs"])
|
||||
bin_path = os.environ["PATH"].split(os.pathsep)
|
||||
@ -90,29 +96,29 @@ def make_win_dist(dist_root, target_triple):
|
||||
target_libs = find_files(target_libs, lib_path)
|
||||
|
||||
# Copy runtime dlls next to rustc.exe
|
||||
dist_bin_dir = os.path.join(dist_root, "bin")
|
||||
dist_bin_dir = os.path.join(rust_root, "bin")
|
||||
for src in rustc_dlls:
|
||||
shutil.copy(src, dist_bin_dir)
|
||||
|
||||
# Copy platform tools to platform-specific bin directory
|
||||
target_bin_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "bin")
|
||||
target_bin_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "bin")
|
||||
if not os.path.exists(target_bin_dir):
|
||||
os.makedirs(target_bin_dir)
|
||||
for src in target_tools:
|
||||
shutil.copy(src, target_bin_dir)
|
||||
|
||||
# Copy platform libs to platform-spcific lib directory
|
||||
target_lib_dir = os.path.join(dist_root, "bin", "rustlib", target_triple, "lib")
|
||||
# Copy platform libs to platform-specific lib directory
|
||||
target_lib_dir = os.path.join(gcc_root, "bin", "rustlib", target_triple, "lib")
|
||||
if not os.path.exists(target_lib_dir):
|
||||
os.makedirs(target_lib_dir)
|
||||
for src in target_libs:
|
||||
shutil.copy(src, target_lib_dir)
|
||||
|
||||
# Copy license files
|
||||
lic_dir = os.path.join(dist_root, "bin", "third-party")
|
||||
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])
|
||||
make_win_dist(sys.argv[1], sys.argv[2], sys.argv[3])
|
||||
|
@ -19,6 +19,7 @@ f = open(sys.argv[1], 'wb')
|
||||
components = sys.argv[2].split(' ')
|
||||
components = [i for i in components if i] # ignore extra whitespaces
|
||||
enable_static = sys.argv[3]
|
||||
llconfig = sys.argv[4]
|
||||
|
||||
f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
@ -44,69 +45,47 @@ def run(args):
|
||||
sys.exit(1)
|
||||
return out
|
||||
|
||||
for llconfig in sys.argv[4:]:
|
||||
f.write("\n")
|
||||
f.write("\n")
|
||||
|
||||
out = run([llconfig, '--host-target'])
|
||||
arch, os = out.split('-', 1)
|
||||
arch = 'x86' if arch == 'i686' or arch == 'i386' else arch
|
||||
if 'darwin' in os:
|
||||
os = 'macos'
|
||||
elif 'linux' in os:
|
||||
os = 'linux'
|
||||
elif 'freebsd' in os:
|
||||
os = 'freebsd'
|
||||
elif 'dragonfly' in os:
|
||||
os = 'dragonfly'
|
||||
elif 'android' in os:
|
||||
os = 'android'
|
||||
elif 'win' in os or 'mingw' in os:
|
||||
os = 'windows'
|
||||
cfg = [
|
||||
"target_arch = \"" + arch + "\"",
|
||||
"target_os = \"" + os + "\"",
|
||||
]
|
||||
version = run([llconfig, '--version']).strip()
|
||||
|
||||
f.write("#[cfg(all(" + ', '.join(cfg) + "))]\n")
|
||||
# LLVM libs
|
||||
if version < '3.5':
|
||||
args = [llconfig, '--libs']
|
||||
else:
|
||||
args = [llconfig, '--libs', '--system-libs']
|
||||
|
||||
version = run([llconfig, '--version']).strip()
|
||||
args.extend(components)
|
||||
out = run(args)
|
||||
for lib in out.strip().replace("\n", ' ').split(' '):
|
||||
lib = lib.strip()[2:] # chop of the leading '-l'
|
||||
f.write("#[link(name = \"" + lib + "\"")
|
||||
# LLVM libraries are all static libraries
|
||||
if 'LLVM' in lib:
|
||||
f.write(", kind = \"static\"")
|
||||
f.write(")]\n")
|
||||
|
||||
# LLVM libs
|
||||
if version < '3.5':
|
||||
args = [llconfig, '--libs']
|
||||
else:
|
||||
args = [llconfig, '--libs', '--system-libs']
|
||||
args.extend(components)
|
||||
out = run(args)
|
||||
for lib in out.strip().replace("\n", ' ').split(' '):
|
||||
lib = lib.strip()[2:] # chop of the leading '-l'
|
||||
f.write("#[link(name = \"" + lib + "\"")
|
||||
# LLVM libraries are all static libraries
|
||||
if 'LLVM' in lib:
|
||||
f.write(", kind = \"static\"")
|
||||
f.write(")]\n")
|
||||
|
||||
# llvm-config before 3.5 didn't have a system-libs flag
|
||||
if version < '3.5':
|
||||
if os == 'win32':
|
||||
# llvm-config before 3.5 didn't have a system-libs flag
|
||||
if version < '3.5':
|
||||
if os == 'win32':
|
||||
f.write("#[link(name = \"imagehlp\")]")
|
||||
|
||||
# LLVM ldflags
|
||||
out = run([llconfig, '--ldflags'])
|
||||
for lib in out.strip().split(' '):
|
||||
if lib[:2] == "-l":
|
||||
f.write("#[link(name = \"" + lib[2:] + "\")]\n")
|
||||
# LLVM ldflags
|
||||
out = run([llconfig, '--ldflags'])
|
||||
for lib in out.strip().split(' '):
|
||||
if lib[:2] == "-l":
|
||||
f.write("#[link(name = \"" + lib[2:] + "\")]\n")
|
||||
|
||||
# C++ runtime library
|
||||
out = run([llconfig, '--cxxflags'])
|
||||
if enable_static == '1':
|
||||
assert('stdlib=libc++' not in out)
|
||||
f.write("#[link(name = \"stdc++\", kind = \"static\")]\n")
|
||||
else:
|
||||
if 'stdlib=libc++' in out:
|
||||
# C++ runtime library
|
||||
out = run([llconfig, '--cxxflags'])
|
||||
if enable_static == '1':
|
||||
assert('stdlib=libc++' not in out)
|
||||
f.write("#[link(name = \"stdc++\", kind = \"static\")]\n")
|
||||
else:
|
||||
if 'stdlib=libc++' in out:
|
||||
f.write("#[link(name = \"c++\")]\n")
|
||||
else:
|
||||
else:
|
||||
f.write("#[link(name = \"stdc++\")]\n")
|
||||
|
||||
# Attach everything to an extern block
|
||||
f.write("extern {}\n")
|
||||
# Attach everything to an extern block
|
||||
f.write("extern {}\n")
|
||||
|
@ -14,6 +14,7 @@ AppPublisherURL=http://www.rust-lang.org
|
||||
VersionInfoVersion={#CFG_VERSION_WIN}
|
||||
LicenseFile=LICENSE.txt
|
||||
|
||||
PrivilegesRequired=lowest
|
||||
DisableWelcomePage=true
|
||||
DisableProgramGroupPage=true
|
||||
DisableReadyPage=true
|
||||
@ -22,7 +23,7 @@ DisableStartupPrompt=true
|
||||
OutputDir=.\dist\
|
||||
SourceDir=.\
|
||||
OutputBaseFilename={#CFG_PACKAGE_NAME}-{#CFG_BUILD}
|
||||
DefaultDirName={pf32}\Rust
|
||||
DefaultDirName={sd}\Rust
|
||||
|
||||
Compression=lzma2/ultra
|
||||
InternalCompressLevel=ultra
|
||||
@ -37,13 +38,18 @@ Uninstallable=yes
|
||||
[Tasks]
|
||||
Name: modifypath; Description: &Add {app}\bin to your PATH (recommended)
|
||||
|
||||
[Components]
|
||||
Name: rust; Description: "Rust compiler and standard crates"; Types: full compact custom; Flags: fixed
|
||||
Name: gcc; Description: "Linker and platform libraries"; Types: full
|
||||
|
||||
[Files]
|
||||
Source: "tmp/dist/win/*.*" ; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
||||
Source: "tmp/dist/win/rust/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
|
||||
Source: "tmp/dist/win/gcc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: gcc
|
||||
|
||||
[Code]
|
||||
const
|
||||
ModPathName = 'modifypath';
|
||||
ModPathType = 'system';
|
||||
ModPathType = 'user';
|
||||
|
||||
function ModPathDir(): TArrayOfString;
|
||||
begin
|
||||
|
@ -63,7 +63,7 @@ def read_tests(f):
|
||||
def test_tostr(t):
|
||||
lineno, pat, text, groups = t
|
||||
options = map(group_tostr, groups)
|
||||
return 'mat!(match_%s, r"%s", r"%s", %s)' \
|
||||
return 'mat!{match_%s, r"%s", r"%s", %s}' \
|
||||
% (lineno, pat, '' if text == "NULL" else text, ', '.join(options))
|
||||
|
||||
|
||||
|
30
src/etc/rust-lldb
Executable file
30
src/etc/rust-lldb
Executable file
@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# Exit if anything fails
|
||||
set -e
|
||||
|
||||
# Create a tempfile containing the LLDB script we want to execute on startup
|
||||
TMPFILE=`mktemp /tmp/rust-lldb-commands.XXXXXX`
|
||||
|
||||
# Make sure to delete the tempfile no matter what
|
||||
trap "rm -f $TMPFILE; exit" INT TERM EXIT
|
||||
|
||||
# Find out where to look for the pretty printer Python module
|
||||
RUSTC_SYSROOT=`rustc --print sysroot`
|
||||
|
||||
# Write the LLDB script to the tempfile
|
||||
echo "command script import \"$RUSTC_SYSROOT/lib/rustlib/etc/lldb_rust_formatters.py\"" >> $TMPFILE
|
||||
echo "type summary add --no-value --python-function lldb_rust_formatters.print_val -x \".*\" --category Rust" >> $TMPFILE
|
||||
echo "type category enable Rust" >> $TMPFILE
|
||||
|
||||
# Call LLDB with the script added to the argument list
|
||||
lldb --source-before-file="$TMPFILE" "$@"
|
155
src/etc/rustup.sh
Normal file → Executable file
155
src/etc/rustup.sh
Normal file → Executable file
@ -188,7 +188,7 @@ flag() {
|
||||
fi
|
||||
}
|
||||
|
||||
validate_opt () {
|
||||
validate_opt() {
|
||||
for arg in $CFG_ARGS
|
||||
do
|
||||
isArgValid=0
|
||||
@ -242,6 +242,8 @@ create_tmp_dir() {
|
||||
}
|
||||
|
||||
probe_need CFG_CURL curl
|
||||
probe_need CFG_TAR tar
|
||||
probe_need CFG_FILE file
|
||||
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
|
||||
CFG_SELF="$0"
|
||||
@ -370,7 +372,7 @@ esac
|
||||
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
|
||||
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
|
||||
then
|
||||
file -L "$SHELL" | grep -q "x86[_-]64"
|
||||
"${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64"
|
||||
if [ $? != 0 ]; then
|
||||
CFG_CPUTYPE=i686
|
||||
fi
|
||||
@ -400,83 +402,106 @@ esac
|
||||
|
||||
msg "host triple: ${HOST_TRIPLE}"
|
||||
|
||||
PACKAGE_NAME=rust-nightly
|
||||
PACKAGE_NAME_AND_TRIPLE="${PACKAGE_NAME}-${HOST_TRIPLE}"
|
||||
TARBALL_NAME="${PACKAGE_NAME_AND_TRIPLE}.tar.gz"
|
||||
REMOTE_TARBALL="https://static.rust-lang.org/dist/${TARBALL_NAME}"
|
||||
TMP_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir' 2>/dev/null` || TMP_DIR=$(create_tmp_dir)
|
||||
LOCAL_TARBALL="${TMP_DIR}/${TARBALL_NAME}"
|
||||
LOCAL_INSTALL_DIR="${TMP_DIR}/${PACKAGE_NAME_AND_TRIPLE}"
|
||||
LOCAL_INSTALL_SCRIPT="${LOCAL_INSTALL_DIR}/install.sh"
|
||||
CFG_INSTALL_FLAGS=""
|
||||
if [ -n "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --uninstall"
|
||||
fi
|
||||
|
||||
if [ -n "${CFG_PREFIX}" ]
|
||||
then
|
||||
CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --prefix=${CFG_PREFIX}"
|
||||
fi
|
||||
|
||||
CFG_TMP_DIR=`mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir' 2>/dev/null` || CFG_TMP_DIR=$(create_tmp_dir)
|
||||
|
||||
RUST_URL="https://static.rust-lang.org/dist"
|
||||
RUST_PACKAGE_NAME=rust-nightly
|
||||
RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}"
|
||||
RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
|
||||
RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}"
|
||||
RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh"
|
||||
|
||||
CARGO_URL="https://static.rust-lang.org/cargo-dist"
|
||||
CARGO_PACKAGE_NAME=cargo-nightly
|
||||
CARGO_PACKAGE_NAME_AND_TRIPLE="${CARGO_PACKAGE_NAME}-${HOST_TRIPLE}"
|
||||
CARGO_TARBALL_NAME="${CARGO_PACKAGE_NAME_AND_TRIPLE}.tar.gz"
|
||||
CARGO_REMOTE_TARBALL="https://static.rust-lang.org/cargo-dist/${CARGO_TARBALL_NAME}"
|
||||
CARGO_LOCAL_TARBALL="${TMP_DIR}/${CARGO_TARBALL_NAME}"
|
||||
CARGO_LOCAL_INSTALL_DIR="${TMP_DIR}/${CARGO_PACKAGE_NAME_AND_TRIPLE}"
|
||||
CARGO_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${CARGO_PACKAGE_NAME_AND_TRIPLE}"
|
||||
CARGO_LOCAL_INSTALL_SCRIPT="${CARGO_LOCAL_INSTALL_DIR}/install.sh"
|
||||
|
||||
msg "downloading rust installer"
|
||||
"${CFG_CURL}" "${REMOTE_TARBALL}" > "${LOCAL_TARBALL}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
# Fetch the package.
|
||||
download_package() {
|
||||
remote_tarball="$1"
|
||||
local_tarball="$2"
|
||||
|
||||
msg "Downloading ${remote_tarball} to ${local_tarball}"
|
||||
|
||||
"${CFG_CURL}" -f -o "${local_tarball}" "${remote_tarball}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to download installer"
|
||||
fi
|
||||
|
||||
if [ -z "${CFG_DISABLE_CARGO}" ]; then
|
||||
msg "downloading cargo installer"
|
||||
"${CFG_CURL}" "${CARGO_REMOTE_TARBALL}" > "${CARGO_LOCAL_TARBALL}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
err "failed to download cargo installer"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Wrap all the commands needed to install a package.
|
||||
install_package() {
|
||||
tarball_name="$1"
|
||||
install_script="$2"
|
||||
|
||||
(cd "${TMP_DIR}" && tar xzf "${TARBALL_NAME}")
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
msg "Extracting ${tarball_name}"
|
||||
(cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${tarball_name}")
|
||||
if [ $? -ne 0 ]; then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to unpack installer"
|
||||
fi
|
||||
fi
|
||||
|
||||
MAYBE_UNINSTALL=
|
||||
if [ -n "${CFG_UNINSTALL}" ]
|
||||
then
|
||||
MAYBE_UNINSTALL="--uninstall"
|
||||
fi
|
||||
|
||||
MAYBE_PREFIX=
|
||||
if [ -n "${CFG_PREFIX}" ]
|
||||
then
|
||||
MAYBE_PREFIX="--prefix=${CFG_PREFIX}"
|
||||
fi
|
||||
|
||||
sh "${LOCAL_INSTALL_SCRIPT}" "${MAYBE_UNINSTALL}" "${MAYBE_PREFIX}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
sh "${install_script}" "${CFG_INSTALL_FLAGS}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
err "failed to install Rust"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z "${CFG_DISABLE_CARGO}" ]; then
|
||||
(cd "${TMP_DIR}" && tar xzf "${CARGO_TARBALL_NAME}")
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
err "failed to unpack cargo installer"
|
||||
# It's possible that curl could be interrupted partway though downloading
|
||||
# `rustup.sh`, truncating the file. This could be especially bad if we were in
|
||||
# the middle of a line that would run "rm -rf ". To protect against this, we
|
||||
# wrap up the `rustup.sh` destructive functionality in this helper function,
|
||||
# which we call as the last thing we do. This means we will not do anything
|
||||
# unless we have the entire file downloaded.
|
||||
install_packages() {
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
need_ok "failed to remove temporary installation directory"
|
||||
|
||||
mkdir -p "${CFG_TMP_DIR}"
|
||||
need_ok "failed to create create temporary installation directory"
|
||||
|
||||
RUST_LOCAL_TARBALL="${CFG_TMP_DIR}/${RUST_TARBALL_NAME}"
|
||||
CARGO_LOCAL_TARBALL="${CFG_TMP_DIR}/${CARGO_TARBALL_NAME}"
|
||||
|
||||
download_package \
|
||||
"${RUST_URL}/${RUST_TARBALL_NAME}" \
|
||||
"${RUST_LOCAL_TARBALL}"
|
||||
|
||||
if [ -z "${CFG_DISABLE_CARGO}" ]; then
|
||||
download_package \
|
||||
"${CARGO_URL}/${CARGO_TARBALL_NAME}" \
|
||||
"${CARGO_LOCAL_TARBALL}"
|
||||
fi
|
||||
|
||||
sh "${CARGO_LOCAL_INSTALL_SCRIPT}" "${MAYBE_UNINSTALL}" "${MAYBE_PREFIX}"
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
rm -Rf "${TMP_DIR}"
|
||||
err "failed to install Cargo"
|
||||
fi
|
||||
fi
|
||||
install_package \
|
||||
"${RUST_TARBALL_NAME}" \
|
||||
"${RUST_LOCAL_INSTALL_SCRIPT}"
|
||||
|
||||
rm -Rf "${TMP_DIR}"
|
||||
need_ok "couldn't rm temporary installation directory"
|
||||
if [ -z "${CFG_DISABLE_CARGO}" ]; then
|
||||
install_package \
|
||||
"${CARGO_TARBALL_NAME}" \
|
||||
"${CARGO_LOCAL_INSTALL_SCRIPT}"
|
||||
fi
|
||||
|
||||
rm -Rf "${CFG_TMP_DIR}"
|
||||
need_ok "couldn't rm temporary installation directory"
|
||||
}
|
||||
|
||||
install_packages
|
||||
|
@ -283,17 +283,13 @@ def load_east_asian_width(want_widths, except_cats):
|
||||
return widths
|
||||
|
||||
def escape_char(c):
|
||||
if c <= 0x7f:
|
||||
return "'\\x%2.2x'" % c
|
||||
if c <= 0xffff:
|
||||
return "'\\u%4.4x'" % c
|
||||
return "'\\U%8.8x'" % c
|
||||
return "'\\u{%x}'" % c
|
||||
|
||||
def emit_bsearch_range_table(f):
|
||||
f.write("""
|
||||
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
|
||||
use core::cmp::{Equal, Less, Greater};
|
||||
use core::slice::SlicePrelude;
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
use core::slice::SliceExt;
|
||||
r.binary_search(|&(lo,hi)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
@ -350,23 +346,23 @@ def emit_regex_module(f, cats, w_data):
|
||||
def emit_conversions_module(f, lowerupper, upperlower):
|
||||
f.write("pub mod conversions {")
|
||||
f.write("""
|
||||
use core::cmp::{Equal, Less, Greater};
|
||||
use core::slice::SlicePrelude;
|
||||
use core::tuple::Tuple2;
|
||||
use core::option::{Option, Some, None};
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
use core::slice::SliceExt;
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
use core::slice;
|
||||
|
||||
pub fn to_lower(c: char) -> char {
|
||||
match bsearch_case_table(c, LuLl_table) {
|
||||
None => c,
|
||||
Some(index) => LuLl_table[index].val1()
|
||||
Some(index) => LuLl_table[index].1
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_upper(c: char) -> char {
|
||||
match bsearch_case_table(c, LlLu_table) {
|
||||
None => c,
|
||||
Some(index) => LlLu_table[index].val1()
|
||||
Some(index) => LlLu_table[index].1
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,8 +372,8 @@ def emit_conversions_module(f, lowerupper, upperlower):
|
||||
else if key < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
slice::Found(i) => Some(i),
|
||||
slice::NotFound(_) => None,
|
||||
slice::BinarySearchResult::Found(i) => Some(i),
|
||||
slice::BinarySearchResult::NotFound(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,7 +386,8 @@ def emit_conversions_module(f, lowerupper, upperlower):
|
||||
|
||||
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
|
||||
f.write("""pub mod grapheme {
|
||||
use core::slice::SlicePrelude;
|
||||
use core::kinds::Copy;
|
||||
use core::slice::SliceExt;
|
||||
pub use self::GraphemeCat::*;
|
||||
use core::slice;
|
||||
|
||||
@ -402,18 +399,20 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats):
|
||||
f.write(" GC_" + cat + ",\n")
|
||||
f.write(""" }
|
||||
|
||||
impl Copy for GraphemeCat {}
|
||||
|
||||
fn bsearch_range_value_table(c: char, r: &'static [(char, char, GraphemeCat)]) -> GraphemeCat {
|
||||
use core::cmp::{Equal, Less, Greater};
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
match r.binary_search(|&(lo, hi, _)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
slice::Found(idx) => {
|
||||
slice::BinarySearchResult::Found(idx) => {
|
||||
let (_, _, cat) = r[idx];
|
||||
cat
|
||||
}
|
||||
slice::NotFound(_) => GC_Any
|
||||
slice::BinarySearchResult::NotFound(_) => GC_Any
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,22 +429,23 @@ def emit_grapheme_module(f, grapheme_table, grapheme_cats):
|
||||
|
||||
def emit_charwidth_module(f, width_table):
|
||||
f.write("pub mod charwidth {\n")
|
||||
f.write(" use core::option::{Option, Some, None};\n")
|
||||
f.write(" use core::slice::SlicePrelude;\n")
|
||||
f.write(" use core::option::Option;\n")
|
||||
f.write(" use core::option::Option::{Some, None};\n")
|
||||
f.write(" use core::slice::SliceExt;\n")
|
||||
f.write(" use core::slice;\n")
|
||||
f.write("""
|
||||
fn bsearch_range_value_table(c: char, is_cjk: bool, r: &'static [(char, char, u8, u8)]) -> u8 {
|
||||
use core::cmp::{Equal, Less, Greater};
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
match r.binary_search(|&(lo, hi, _, _)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
slice::Found(idx) => {
|
||||
slice::BinarySearchResult::Found(idx) => {
|
||||
let (_, _, r_ncjk, r_cjk) = r[idx];
|
||||
if is_cjk { r_cjk } else { r_ncjk }
|
||||
}
|
||||
slice::NotFound(_) => 1
|
||||
slice::BinarySearchResult::NotFound(_) => 1
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -530,19 +530,19 @@ def emit_norm_module(f, canon, compat, combine, norm_props):
|
||||
|
||||
f.write("""
|
||||
fn bsearch_range_value_table(c: char, r: &'static [(char, char, u8)]) -> u8 {
|
||||
use core::cmp::{Equal, Less, Greater};
|
||||
use core::slice::SlicePrelude;
|
||||
use core::cmp::Ordering::{Equal, Less, Greater};
|
||||
use core::slice::SliceExt;
|
||||
use core::slice;
|
||||
match r.binary_search(|&(lo, hi, _)| {
|
||||
if lo <= c && c <= hi { Equal }
|
||||
else if hi < c { Less }
|
||||
else { Greater }
|
||||
}) {
|
||||
slice::Found(idx) => {
|
||||
slice::BinarySearchResult::Found(idx) => {
|
||||
let (_, _, result) = r[idx];
|
||||
result
|
||||
}
|
||||
slice::NotFound(_) => 0
|
||||
slice::BinarySearchResult::NotFound(_) => 0
|
||||
}
|
||||
}\n
|
||||
""")
|
||||
@ -611,7 +611,7 @@ if __name__ == "__main__":
|
||||
unicode_version = re.search(pattern, readme.read()).groups()
|
||||
rf.write("""
|
||||
/// The version of [Unicode](http://www.unicode.org/)
|
||||
/// that the `UnicodeChar` and `UnicodeStrSlice` traits are based on.
|
||||
/// that the `UnicodeChar` and `UnicodeStrPrelude` traits are based on.
|
||||
pub const UNICODE_VERSION: (uint, uint, uint) = (%s, %s, %s);
|
||||
""" % unicode_version)
|
||||
(canon_decomp, compat_decomp, gencats, combines,
|
||||
|
@ -24,7 +24,7 @@ syn keyword rustKeyword continue
|
||||
syn keyword rustKeyword extern nextgroup=rustExternCrate,rustObsoleteExternMod skipwhite skipempty
|
||||
syn keyword rustKeyword fn nextgroup=rustFuncName skipwhite skipempty
|
||||
syn keyword rustKeyword for in if impl let
|
||||
syn keyword rustKeyword loop once proc pub
|
||||
syn keyword rustKeyword loop once pub
|
||||
syn keyword rustKeyword return super
|
||||
syn keyword rustKeyword unsafe virtual where while
|
||||
syn keyword rustKeyword use nextgroup=rustModPath skipwhite skipempty
|
||||
@ -90,7 +90,7 @@ syn keyword rustTrait Clone
|
||||
syn keyword rustTrait PartialEq PartialOrd Eq Ord
|
||||
syn keyword rustEnum Ordering Equiv
|
||||
syn keyword rustEnumVariant Less Equal Greater
|
||||
syn keyword rustTrait FromIterator Extend ExactSize
|
||||
syn keyword rustTrait FromIterator Extend ExactSizeIterator
|
||||
syn keyword rustTrait Iterator DoubleEndedIterator
|
||||
syn keyword rustTrait RandomAccessIterator CloneableIterator
|
||||
syn keyword rustTrait OrdIterator MutableDoubleEndedIterator
|
||||
@ -151,6 +151,7 @@ syn match rustMacro '#\w\(\w\)*' contains=rustAssert,rustPanic
|
||||
syn match rustEscapeError display contained /\\./
|
||||
syn match rustEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
|
||||
syn match rustEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/
|
||||
syn match rustEscapeUnicode display contained /\\u{\x\{1,6}}/
|
||||
syn match rustStringContinuation display contained /\\\n\s*/
|
||||
syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeError,rustStringContinuation
|
||||
syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell
|
||||
@ -187,7 +188,7 @@ syn match rustCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/
|
||||
" The groups negated here add up to 0-255 but nothing else (they do not seem to go beyond ASCII).
|
||||
syn match rustCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/
|
||||
syn match rustCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=rustEscape,rustEscapeError,rustCharacterInvalid,rustCharacterInvalidUnicode
|
||||
syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid
|
||||
syn match rustCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\|u{\x\{1,6}}\)\)'/ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustCharacterInvalid
|
||||
|
||||
syn region rustCommentLine start="//" end="$" contains=rustTodo,@Spell
|
||||
syn region rustCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=rustTodo,@Spell
|
||||
|
@ -173,10 +173,10 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
|
||||
);
|
||||
|
||||
let m = re.captures(s).expect(format!("The regex didn't match {}", s).as_slice());
|
||||
let start = m.name("start");
|
||||
let end = m.name("end");
|
||||
let toknum = m.name("toknum");
|
||||
let content = m.name("content");
|
||||
let start = m.name("start").unwrap_or("");
|
||||
let end = m.name("end").unwrap_or("");
|
||||
let toknum = m.name("toknum").unwrap_or("");
|
||||
let content = m.name("content").unwrap_or("");
|
||||
|
||||
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
|
||||
toknum).as_slice());
|
||||
|
@ -10,10 +10,65 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
//! Concurrency-enabled mechanisms for sharing mutable and/or immutable state
|
||||
//! between tasks.
|
||||
//! Threadsafe reference-counted boxes (the `Arc<T>` type).
|
||||
//!
|
||||
//! The `Arc<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 `Send` because
|
||||
//! it uses atomic reference counting.
|
||||
//!
|
||||
//! If you do not need thread-safety, and just need shared ownership, consider the [`Rc<T>`
|
||||
//! type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but does not use atomics, making it
|
||||
//! both thread-unsafe as well as significantly faster when updating the reference count.
|
||||
//!
|
||||
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A
|
||||
//! `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but will return `None` if the value
|
||||
//! has already been dropped.
|
||||
//!
|
||||
//! For example, a tree with parent pointers can be represented by putting the nodes behind strong
|
||||
//! `Arc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Sharing some immutable data between tasks:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::sync::Arc;
|
||||
//! use std::thread::Thread;
|
||||
//!
|
||||
//! let five = Arc::new(5i);
|
||||
//!
|
||||
//! for i in range(0u, 10) {
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! Thread::spawn(move || {
|
||||
//! println!("{}", five);
|
||||
//! }).detach();
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Sharing mutable data safely between tasks with a `Mutex`:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::sync::{Arc, Mutex};
|
||||
//! use std::thread::Thread;
|
||||
//!
|
||||
//! let five = Arc::new(Mutex::new(5i));
|
||||
//!
|
||||
//! for _ in range(0u, 10) {
|
||||
//! let five = five.clone();
|
||||
//!
|
||||
//! Thread::spawn(move || {
|
||||
//! let mut number = five.lock();
|
||||
//!
|
||||
//! *number += 1;
|
||||
//!
|
||||
//! println!("{}", *number); // prints 6
|
||||
//! }).detach();
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use core::atomic;
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::clone::Clone;
|
||||
use core::fmt::{mod, Show};
|
||||
use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering};
|
||||
@ -22,7 +77,8 @@ use core::kinds::{Sync, Send};
|
||||
use core::mem::{min_align_of, size_of, drop};
|
||||
use core::mem;
|
||||
use core::ops::{Drop, Deref};
|
||||
use core::option::{Some, None, Option};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
use core::ptr::RawPtr;
|
||||
use core::ptr;
|
||||
use heap::deallocate;
|
||||
@ -31,12 +87,12 @@ use heap::deallocate;
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// In this example, a large vector of floats is shared between several tasks.
|
||||
/// With simple pipes, without `Arc`, a copy would have to be made for each
|
||||
/// task.
|
||||
/// In this example, a large vector of floats is shared between several tasks. With simple pipes,
|
||||
/// without `Arc`, a copy would have to be made for each task.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::sync::Arc;
|
||||
/// use std::thread::Thread;
|
||||
///
|
||||
/// fn main() {
|
||||
/// let numbers = Vec::from_fn(100, |i| i as f32);
|
||||
@ -45,11 +101,11 @@ use heap::deallocate;
|
||||
/// for _ in range(0u, 10) {
|
||||
/// let child_numbers = shared_numbers.clone();
|
||||
///
|
||||
/// spawn(proc() {
|
||||
/// Thread::spawn(move || {
|
||||
/// let local_numbers = child_numbers.as_slice();
|
||||
///
|
||||
/// // Work with the local numbers
|
||||
/// });
|
||||
/// }).detach();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -63,8 +119,8 @@ pub struct Arc<T> {
|
||||
|
||||
/// A weak pointer to an `Arc`.
|
||||
///
|
||||
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
|
||||
/// used to break cycles between `Arc` pointers.
|
||||
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles
|
||||
/// between `Arc` pointers.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
pub struct Weak<T> {
|
||||
@ -80,7 +136,15 @@ struct ArcInner<T> {
|
||||
}
|
||||
|
||||
impl<T: Sync + Send> Arc<T> {
|
||||
/// Creates an atomically reference counted wrapper.
|
||||
/// Constructs a new `Arc<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new(data: T) -> Arc<T> {
|
||||
@ -94,11 +158,17 @@ impl<T: Sync + Send> Arc<T> {
|
||||
Arc { _ptr: unsafe { mem::transmute(x) } }
|
||||
}
|
||||
|
||||
/// Downgrades a strong pointer to a weak pointer.
|
||||
/// Downgrades the `Arc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// Weak pointers will not keep the data alive. Once all strong references
|
||||
/// to the underlying data have been dropped, the data itself will be
|
||||
/// destroyed.
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
// See the clone() impl for why this is relaxed
|
||||
@ -110,33 +180,48 @@ impl<T: Sync + Send> Arc<T> {
|
||||
impl<T> Arc<T> {
|
||||
#[inline]
|
||||
fn inner(&self) -> &ArcInner<T> {
|
||||
// This unsafety is ok because while this arc is alive we're guaranteed
|
||||
// that the inner pointer is valid. Furthermore, we know that the
|
||||
// `ArcInner` structure itself is `Sync` because the inner data is
|
||||
// `Sync` as well, so we're ok loaning out an immutable pointer to
|
||||
// these contents.
|
||||
// This unsafety is ok because while this arc is alive we're guaranteed that the inner
|
||||
// pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync`
|
||||
// because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer
|
||||
// to these contents.
|
||||
unsafe { &*self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "waiting on stability of Clone"]
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn weak_count<T>(this: &Arc<T>) -> uint { this.inner().weak.load(atomic::SeqCst) - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count<T>(this: &Arc<T>) -> uint { this.inner().strong.load(atomic::SeqCst) }
|
||||
|
||||
#[stable]
|
||||
impl<T> Clone for Arc<T> {
|
||||
/// Duplicate an atomically reference counted wrapper.
|
||||
/// Makes a clone of the `Arc<T>`.
|
||||
///
|
||||
/// The resulting two `Arc` objects will point to the same underlying data
|
||||
/// object. However, one of the `Arc` objects can be sent to another task,
|
||||
/// allowing them to share the underlying data.
|
||||
/// This increases the strong reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Arc<T> {
|
||||
// Using a relaxed ordering is alright here, as knowledge of the
|
||||
// original reference prevents other threads from erroneously deleting
|
||||
// the object.
|
||||
// Using a relaxed ordering is alright here, as knowledge of the original reference
|
||||
// prevents other threads from erroneously deleting the object.
|
||||
//
|
||||
// As explained in the [Boost documentation][1], Increasing the
|
||||
// reference counter can always be done with memory_order_relaxed: New
|
||||
// references to an object can only be formed from an existing
|
||||
// reference, and passing an existing reference from one thread to
|
||||
// another must already provide any required synchronization.
|
||||
// As explained in the [Boost documentation][1], Increasing the reference counter can
|
||||
// always be done with memory_order_relaxed: New references to an object can only be formed
|
||||
// from an existing reference, and passing an existing reference from one thread to another
|
||||
// must already provide any required synchronization.
|
||||
//
|
||||
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
|
||||
self.inner().strong.fetch_add(1, atomic::Relaxed);
|
||||
@ -144,6 +229,12 @@ impl<T> Clone for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BorrowFrom<Arc<T>> for T {
|
||||
fn borrow_from(owned: &Arc<T>) -> &T {
|
||||
&**owned
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Deref is experimental."]
|
||||
impl<T> Deref<T> for Arc<T> {
|
||||
#[inline]
|
||||
@ -153,26 +244,33 @@ impl<T> Deref<T> for Arc<T> {
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + Clone> Arc<T> {
|
||||
/// Acquires a mutable pointer to the inner contents by guaranteeing that
|
||||
/// the reference count is one (no sharing is possible).
|
||||
/// Make a mutable reference from the given `Arc<T>`.
|
||||
///
|
||||
/// This is also referred to as a copy-on-write operation because the inner
|
||||
/// data is cloned if the reference count is greater than one.
|
||||
/// This is also referred to as a copy-on-write operation because the inner data is cloned if
|
||||
/// the reference count is greater than one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let mut five = Arc::new(5i);
|
||||
///
|
||||
/// let mut_five = five.make_unique();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn make_unique(&mut self) -> &mut T {
|
||||
// Note that we hold a strong reference, which also counts as
|
||||
// a weak reference, so we only clone if there is an
|
||||
// additional reference of either kind.
|
||||
// Note that we hold a strong reference, which also counts as a weak reference, so we only
|
||||
// clone if there is an additional reference of either kind.
|
||||
if self.inner().strong.load(atomic::SeqCst) != 1 ||
|
||||
self.inner().weak.load(atomic::SeqCst) != 1 {
|
||||
*self = Arc::new((**self).clone())
|
||||
}
|
||||
// This unsafety is ok because we're guaranteed that the pointer
|
||||
// returned is the *only* pointer that will ever be returned to T. Our
|
||||
// reference count is guaranteed to be 1 at this point, and we required
|
||||
// the Arc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
// This unsafety is ok because we're guaranteed that the pointer returned is the *only*
|
||||
// pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at
|
||||
// this point, and we required the Arc itself to be `mut`, so we're returning the only
|
||||
// possible reference to the inner data.
|
||||
let inner = unsafe { &mut *self._ptr };
|
||||
&mut inner.data
|
||||
}
|
||||
@ -181,38 +279,59 @@ impl<T: Send + Sync + Clone> Arc<T> {
|
||||
#[unsafe_destructor]
|
||||
#[experimental = "waiting on stability of Drop"]
|
||||
impl<T: Sync + Send> Drop for Arc<T> {
|
||||
/// Drops the `Arc<T>`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference count becomes zero
|
||||
/// and the only other references are `Weak<T>` ones, `drop`s the inner value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explict drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
// This structure has #[unsafe_no_drop_flag], so this drop glue may run
|
||||
// more than once (but it is guaranteed to be zeroed after the first if
|
||||
// it's run more than once)
|
||||
// This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but
|
||||
// it is guaranteed to be zeroed after the first if it's run more than once)
|
||||
if self._ptr.is_null() { return }
|
||||
|
||||
// Because `fetch_sub` is already atomic, we do not need to synchronize
|
||||
// with other threads unless we are going to delete the object. This
|
||||
// same logic applies to the below `fetch_sub` to the `weak` count.
|
||||
// Because `fetch_sub` is already atomic, we do not need to synchronize with other threads
|
||||
// unless we are going to delete the object. This same logic applies to the below
|
||||
// `fetch_sub` to the `weak` count.
|
||||
if self.inner().strong.fetch_sub(1, atomic::Release) != 1 { return }
|
||||
|
||||
// This fence is needed to prevent reordering of use of the data and
|
||||
// deletion of the data. Because it is marked `Release`, the
|
||||
// decreasing of the reference count synchronizes with this `Acquire`
|
||||
// fence. This means that use of the data happens before decreasing
|
||||
// the reference count, which happens before this fence, which
|
||||
// happens before the deletion of the data.
|
||||
// This fence is needed to prevent reordering of use of the data and deletion of the data.
|
||||
// Because it is marked `Release`, the decreasing of the reference count synchronizes with
|
||||
// this `Acquire` fence. This means that use of the data happens before decreasing the
|
||||
// reference count, which happens before this fence, which happens before the deletion of
|
||||
// the data.
|
||||
//
|
||||
// As explained in the [Boost documentation][1],
|
||||
//
|
||||
// It is important to enforce any possible access to the object in
|
||||
// one thread (through an existing reference) to *happen before*
|
||||
// deleting the object in a different thread. This is achieved by a
|
||||
// "release" operation after dropping a reference (any access to the
|
||||
// object through this reference must obviously happened before),
|
||||
// and an "acquire" operation before deleting the object.
|
||||
// > It is important to enforce any possible access to the object in one thread (through an
|
||||
// > existing reference) to *happen before* deleting the object in a different thread. This
|
||||
// > is achieved by a "release" operation after dropping a reference (any access to the
|
||||
// > object through this reference must obviously happened before), and an "acquire"
|
||||
// > operation before deleting the object.
|
||||
//
|
||||
// [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html)
|
||||
atomic::fence(atomic::Acquire);
|
||||
|
||||
// Destroy the data at this time, even though we may not free the box
|
||||
// allocation itself (there may still be weak pointers lying around).
|
||||
// Destroy the data at this time, even though we may not free the box allocation itself
|
||||
// (there may still be weak pointers lying around).
|
||||
unsafe { drop(ptr::read(&self.inner().data)); }
|
||||
|
||||
if self.inner().weak.fetch_sub(1, atomic::Release) == 1 {
|
||||
@ -225,14 +344,26 @@ impl<T: Sync + Send> Drop for Arc<T> {
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
impl<T: Sync + Send> Weak<T> {
|
||||
/// Attempts to upgrade this weak reference to a strong reference.
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// This method will not upgrade this reference if the strong reference count has already
|
||||
/// reached 0, but if there are still other active strong references this function will return
|
||||
/// a new strong reference to the data.
|
||||
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was destroyed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// let strong_five: Option<Arc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
pub fn upgrade(&self) -> Option<Arc<T>> {
|
||||
// We use a CAS loop to increment the strong count instead of a
|
||||
// fetch_add because once the count hits 0 is must never be above 0.
|
||||
// We use a CAS loop to increment the strong count instead of a fetch_add because once the
|
||||
// count hits 0 is must never be above 0.
|
||||
let inner = self.inner();
|
||||
loop {
|
||||
let n = inner.strong.load(atomic::SeqCst);
|
||||
@ -251,6 +382,19 @@ impl<T: Sync + Send> Weak<T> {
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
impl<T: Sync + Send> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let weak_five = Arc::new(5i).downgrade();
|
||||
///
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Weak<T> {
|
||||
// See comments in Arc::clone() for why this is relaxed
|
||||
@ -262,13 +406,37 @@ impl<T: Sync + Send> Clone for Weak<T> {
|
||||
#[unsafe_destructor]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
impl<T: Sync + Send> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Arc::new(5i);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explict drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Arc::new(5i);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
// see comments above for why this check is here
|
||||
if self._ptr.is_null() { return }
|
||||
|
||||
// If we find out that we were the last weak pointer, then its time to
|
||||
// deallocate the data entirely. See the discussion in Arc::drop() about
|
||||
// the memory orderings
|
||||
// If we find out that we were the last weak pointer, then its time to deallocate the data
|
||||
// entirely. See the discussion in Arc::drop() about the memory orderings
|
||||
if self.inner().weak.fetch_sub(1, atomic::Release) == 1 {
|
||||
atomic::fence(atomic::Acquire);
|
||||
unsafe { deallocate(self._ptr as *mut u8, size_of::<ArcInner<T>>(),
|
||||
@ -279,18 +447,114 @@ impl<T: Sync + Send> Drop for Weak<T> {
|
||||
|
||||
#[unstable = "waiting on PartialEq"]
|
||||
impl<T: PartialEq> PartialEq for Arc<T> {
|
||||
/// Equality for two `Arc<T>`s.
|
||||
///
|
||||
/// Two `Arc<T>`s are equal if their inner value are equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five == Arc::new(5i);
|
||||
/// ```
|
||||
fn eq(&self, other: &Arc<T>) -> bool { *(*self) == *(*other) }
|
||||
|
||||
/// Inequality for two `Arc<T>`s.
|
||||
///
|
||||
/// Two `Arc<T>`s are unequal if their inner value are unequal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five != Arc::new(5i);
|
||||
/// ```
|
||||
fn ne(&self, other: &Arc<T>) -> bool { *(*self) != *(*other) }
|
||||
}
|
||||
#[unstable = "waiting on PartialOrd"]
|
||||
impl<T: PartialOrd> PartialOrd for Arc<T> {
|
||||
/// Partial comparison for two `Arc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `partial_cmp()` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five.partial_cmp(&Arc::new(5i));
|
||||
/// ```
|
||||
fn partial_cmp(&self, other: &Arc<T>) -> Option<Ordering> {
|
||||
(**self).partial_cmp(&**other)
|
||||
}
|
||||
|
||||
/// Less-than comparison for two `Arc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `<` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five < Arc::new(5i);
|
||||
/// ```
|
||||
fn lt(&self, other: &Arc<T>) -> bool { *(*self) < *(*other) }
|
||||
|
||||
/// 'Less-than or equal to' comparison for two `Arc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `<=` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five <= Arc::new(5i);
|
||||
/// ```
|
||||
fn le(&self, other: &Arc<T>) -> bool { *(*self) <= *(*other) }
|
||||
fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
|
||||
|
||||
/// Greater-than comparison for two `Arc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `>` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five > Arc::new(5i);
|
||||
/// ```
|
||||
fn gt(&self, other: &Arc<T>) -> bool { *(*self) > *(*other) }
|
||||
|
||||
/// 'Greater-than or equal to' comparison for two `Arc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `>=` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// let five = Arc::new(5i);
|
||||
///
|
||||
/// five >= Arc::new(5i);
|
||||
/// ```
|
||||
fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
|
||||
}
|
||||
#[unstable = "waiting on Ord"]
|
||||
impl<T: Ord> Ord for Arc<T> {
|
||||
@ -305,7 +569,9 @@ impl<T: fmt::Show> fmt::Show for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<T: Default + Sync + Send> Default for Arc<T> {
|
||||
#[stable]
|
||||
fn default() -> Arc<T> { Arc::new(Default::default()) }
|
||||
}
|
||||
|
||||
@ -316,12 +582,13 @@ mod tests {
|
||||
use std::comm::channel;
|
||||
use std::mem::drop;
|
||||
use std::ops::Drop;
|
||||
use std::option::{Option, Some, None};
|
||||
use std::option::Option;
|
||||
use std::option::Option::{Some, None};
|
||||
use std::str::Str;
|
||||
use std::sync::atomic;
|
||||
use std::task;
|
||||
use std::vec::Vec;
|
||||
use super::{Arc, Weak};
|
||||
use super::{Arc, Weak, weak_count, strong_count};
|
||||
use std::sync::Mutex;
|
||||
|
||||
struct Canary(*mut atomic::AtomicUint);
|
||||
@ -346,7 +613,7 @@ mod tests {
|
||||
|
||||
let (tx, rx) = channel();
|
||||
|
||||
task::spawn(proc() {
|
||||
task::spawn(move || {
|
||||
let arc_v: Arc<Vec<int>> = rx.recv();
|
||||
assert_eq!((*arc_v)[3], 4);
|
||||
});
|
||||
@ -465,10 +732,53 @@ mod tests {
|
||||
drop(arc_weak);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strong_count() {
|
||||
let a = Arc::new(0u32);
|
||||
assert!(strong_count(&a) == 1);
|
||||
let w = a.downgrade();
|
||||
assert!(strong_count(&a) == 1);
|
||||
let b = w.upgrade().expect("");
|
||||
assert!(strong_count(&b) == 2);
|
||||
assert!(strong_count(&a) == 2);
|
||||
drop(w);
|
||||
drop(a);
|
||||
assert!(strong_count(&b) == 1);
|
||||
let c = b.clone();
|
||||
assert!(strong_count(&b) == 2);
|
||||
assert!(strong_count(&c) == 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_count() {
|
||||
let a = Arc::new(0u32);
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 0);
|
||||
let w = a.downgrade();
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 1);
|
||||
let x = w.clone();
|
||||
assert!(weak_count(&a) == 2);
|
||||
drop(w);
|
||||
drop(x);
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 0);
|
||||
let c = a.clone();
|
||||
assert!(strong_count(&a) == 2);
|
||||
assert!(weak_count(&a) == 0);
|
||||
let d = c.downgrade();
|
||||
assert!(weak_count(&c) == 1);
|
||||
assert!(strong_count(&c) == 2);
|
||||
|
||||
drop(a);
|
||||
drop(c);
|
||||
drop(d);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_arc() {
|
||||
let a = Arc::new(5u32);
|
||||
assert!(format!("{}", a).as_slice() == "5")
|
||||
assert!(format!("{}", a) == "5")
|
||||
}
|
||||
|
||||
// Make sure deriving works with Arc<T>
|
||||
|
@ -15,12 +15,14 @@ use core::clone::Clone;
|
||||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::intrinsics;
|
||||
use core::hash::{mod, Hash};
|
||||
use core::kinds::Sized;
|
||||
use core::mem;
|
||||
use core::option::Option;
|
||||
use core::raw::TraitObject;
|
||||
use core::result::{Ok, Err, Result};
|
||||
use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
/// A value that represents the global exchange heap. This is the default
|
||||
/// place that the `box` keyword allocates into when no place is supplied.
|
||||
@ -44,15 +46,19 @@ pub static HEAP: () = ();
|
||||
#[unstable = "custom allocators will add an additional type parameter (with default)"]
|
||||
pub struct Box<T>(*mut T);
|
||||
|
||||
#[stable]
|
||||
impl<T: Default> Default for Box<T> {
|
||||
#[stable]
|
||||
fn default() -> Box<T> { box Default::default() }
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<T> Default for Box<[T]> {
|
||||
#[stable]
|
||||
fn default() -> Box<[T]> { box [] }
|
||||
}
|
||||
|
||||
#[unstable]
|
||||
#[stable]
|
||||
impl<T: Clone> Clone for Box<T> {
|
||||
/// Returns a copy of the owned box.
|
||||
#[inline]
|
||||
@ -93,6 +99,14 @@ impl<Sized? T: Ord> Ord for Box<T> {
|
||||
}
|
||||
impl<Sized? T: Eq> Eq for Box<T> {}
|
||||
|
||||
impl<S: hash::Writer, Sized? T: Hash<S>> Hash<S> for Box<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Extension methods for an owning `Any` trait object.
|
||||
#[unstable = "post-DST and coherence changes, this will not be a trait but \
|
||||
rather a direct `impl` on `Box<Any>`"]
|
||||
@ -104,17 +118,14 @@ pub trait BoxAny {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl BoxAny for Box<Any+'static> {
|
||||
impl BoxAny for Box<Any> {
|
||||
#[inline]
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any+'static>> {
|
||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject =
|
||||
*mem::transmute::<&Box<Any>, &TraitObject>(&self);
|
||||
|
||||
// Prevent destructor on self being run
|
||||
intrinsics::forget(self);
|
||||
mem::transmute::<Box<Any>, TraitObject>(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Ok(mem::transmute(to.data))
|
||||
@ -137,6 +148,14 @@ impl fmt::Show for Box<Any+'static> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Sized? T> Deref<T> for Box<T> {
|
||||
fn deref(&self) -> &T { &**self }
|
||||
}
|
||||
|
||||
impl<Sized? T> DerefMut<T> for Box<T> {
|
||||
fn deref_mut(&mut self) -> &mut T { &mut **self }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
@ -173,14 +192,20 @@ mod test {
|
||||
let b = box Test as Box<Any>;
|
||||
let a_str = a.to_str();
|
||||
let b_str = b.to_str();
|
||||
assert_eq!(a_str.as_slice(), "Box<Any>");
|
||||
assert_eq!(b_str.as_slice(), "Box<Any>");
|
||||
assert_eq!(a_str, "Box<Any>");
|
||||
assert_eq!(b_str, "Box<Any>");
|
||||
|
||||
let a = &8u as &Any;
|
||||
let b = &Test as &Any;
|
||||
let s = format!("{}", a);
|
||||
assert_eq!(s.as_slice(), "&Any");
|
||||
assert_eq!(s, "&Any");
|
||||
let s = format!("{}", b);
|
||||
assert_eq!(s.as_slice(), "&Any");
|
||||
assert_eq!(s, "&Any");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref() {
|
||||
fn homura<T: Deref<i32>>(_: T) { }
|
||||
homura(box 765i32);
|
||||
}
|
||||
}
|
||||
|
@ -123,9 +123,62 @@ const MIN_ALIGN: uint = 8;
|
||||
target_arch = "x86_64"))]
|
||||
const MIN_ALIGN: uint = 16;
|
||||
|
||||
#[cfg(jemalloc)]
|
||||
#[cfg(external_funcs)]
|
||||
mod imp {
|
||||
use core::option::{None, Option};
|
||||
extern {
|
||||
fn rust_allocate(size: uint, align: uint) -> *mut u8;
|
||||
fn rust_deallocate(ptr: *mut u8, old_size: uint, align: uint);
|
||||
fn rust_reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8;
|
||||
fn rust_reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint,
|
||||
align: uint) -> uint;
|
||||
fn rust_usable_size(size: uint, align: uint) -> uint;
|
||||
fn rust_stats_print();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
|
||||
rust_allocate(size, align)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint,
|
||||
align: uint) -> uint {
|
||||
rust_reallocate_inplace(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn deallocate(ptr: *mut u8, old_size: uint, align: uint) {
|
||||
rust_deallocate(ptr, old_size, align)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: uint, size: uint,
|
||||
align: uint) -> uint {
|
||||
rust_reallocate_inplace(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn usable_size(size: uint, align: uint) -> uint {
|
||||
unsafe { rust_usable_size(size, align) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stats_print() {
|
||||
unsafe { rust_stats_print() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(external_crate)]
|
||||
mod imp {
|
||||
extern crate external;
|
||||
pub use self::external::{allocate, deallocate, reallocate_inplace, reallocate};
|
||||
pub use self::external::{usable_size, stats_print};
|
||||
}
|
||||
|
||||
#[cfg(all(not(external_funcs), not(external_crate), jemalloc))]
|
||||
mod imp {
|
||||
use core::option::Option;
|
||||
use core::option::Option::None;
|
||||
use core::ptr::{null_mut, null};
|
||||
use core::num::Int;
|
||||
use libc::{c_char, c_int, c_void, size_t};
|
||||
@ -199,7 +252,7 @@ mod imp {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(not(jemalloc), unix))]
|
||||
#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), unix))]
|
||||
mod imp {
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
@ -260,7 +313,7 @@ mod imp {
|
||||
pub fn stats_print() {}
|
||||
}
|
||||
|
||||
#[cfg(all(not(jemalloc), windows))]
|
||||
#[cfg(all(not(external_funcs), not(external_crate), not(jemalloc), windows))]
|
||||
mod imp {
|
||||
use libc::{c_void, size_t};
|
||||
use libc;
|
||||
|
@ -58,14 +58,13 @@
|
||||
|
||||
#![crate_name = "alloc"]
|
||||
#![experimental]
|
||||
#![license = "MIT/ASL2"]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
||||
|
||||
#![no_std]
|
||||
#![feature(lang_items, phase, unsafe_destructor)]
|
||||
#![feature(lang_items, phase, unsafe_destructor, default_type_params)]
|
||||
|
||||
#[phase(plugin, link)]
|
||||
extern crate core;
|
||||
|
@ -8,27 +8,25 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Task-local reference-counted boxes (the `Rc` type).
|
||||
//! Task-local reference-counted boxes (the `Rc<T>` type).
|
||||
//!
|
||||
//! The `Rc` 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 avoids the overhead of atomic reference counting.
|
||||
//! 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
|
||||
//! avoids the overhead of atomic reference counting.
|
||||
//!
|
||||
//! The `downgrade` method can be used to create a non-owning `Weak` pointer to the
|
||||
//! box. A `Weak` pointer can be upgraded to an `Rc` pointer, but will return
|
||||
//! `None` if the value has already been freed.
|
||||
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A
|
||||
//! `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but will return `None` if the value
|
||||
//! has already been dropped.
|
||||
//!
|
||||
//! For example, a tree with parent pointers can be represented by putting the
|
||||
//! nodes behind strong `Rc` pointers, and then storing the parent pointers as
|
||||
//! `Weak` pointers.
|
||||
//! For example, a tree with parent pointers can be represented by putting the nodes behind strong
|
||||
//! `Rc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`.
|
||||
//! We want to have our `Gadget`s point to their `Owner`. We can't do this with
|
||||
//! unique ownership, because more than one gadget may belong to the same
|
||||
//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s, and
|
||||
//! have the `Owner` kept alive as long as any `Gadget` points at it.
|
||||
//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. We want to have our
|
||||
//! `Gadget`s point to their `Owner`. We can't do this with unique ownership, because more than one
|
||||
//! gadget may belong to the same `Owner`. `Rc<T>` allows us to share an `Owner` between multiple
|
||||
//! `Gadget`s, and have the `Owner` remain allocated as long as any `Gadget` points at it.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::rc::Rc;
|
||||
@ -51,7 +49,7 @@
|
||||
//! );
|
||||
//!
|
||||
//! // Create Gadgets belonging to gadget_owner. To increment the reference
|
||||
//! // count we clone the Rc object.
|
||||
//! // count we clone the `Rc<T>` object.
|
||||
//! let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() };
|
||||
//! let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() };
|
||||
//!
|
||||
@ -60,8 +58,8 @@
|
||||
//! // Despite dropping gadget_owner, we're still able to print out the name of
|
||||
//! // the Owner of the Gadgets. This is because we've only dropped the
|
||||
//! // reference count object, not the Owner it wraps. As long as there are
|
||||
//! // other Rc objects pointing at the same Owner, it will stay alive. Notice
|
||||
//! // that the Rc wrapper around Gadget.owner gets automatically dereferenced
|
||||
//! // other `Rc<T>` objects pointing at the same Owner, it will remain allocated. Notice
|
||||
//! // that the `Rc<T>` wrapper around Gadget.owner gets automatically dereferenced
|
||||
//! // for us.
|
||||
//! println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
|
||||
//! println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
|
||||
@ -72,23 +70,19 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! If our requirements change, and we also need to be able to traverse from
|
||||
//! Owner → Gadget, we will run into problems: an `Rc` pointer from Owner → Gadget
|
||||
//! introduces a cycle between the objects. This means that their reference counts
|
||||
//! can never reach 0, and the objects will stay alive: a memory leak. In order to
|
||||
//! get around this, we can use `Weak` pointers. These are reference counted
|
||||
//! pointers that don't keep an object alive if there are no normal `Rc` (or
|
||||
//! *strong*) pointers left.
|
||||
//! If our requirements change, and we also need to be able to traverse from Owner → Gadget, we
|
||||
//! will run into problems: an `Rc<T>` pointer from Owner → Gadget introduces a cycle between the
|
||||
//! objects. This means that their reference counts can never reach 0, and the objects will remain
|
||||
//! allocated: a memory leak. In order to get around this, we can use `Weak<T>` pointers. These
|
||||
//! pointers don't contribute to the total count.
|
||||
//!
|
||||
//! Rust actually makes it somewhat difficult to produce this loop in the first
|
||||
//! place: in order to end up with two objects that point at each other, one of
|
||||
//! them needs to be mutable. This is problematic because `Rc` enforces memory
|
||||
//! safety by only giving out shared references to the object it wraps, and these
|
||||
//! don't allow direct mutation. We need to wrap the part of the object we wish to
|
||||
//! mutate in a `RefCell`, which provides *interior mutability*: a method to
|
||||
//! achieve mutability through a shared reference. `RefCell` enforces Rust's
|
||||
//! borrowing rules at runtime. Read the `Cell` documentation for more details on
|
||||
//! interior mutability.
|
||||
//! Rust actually makes it somewhat difficult to produce this loop in the first place: in order to
|
||||
//! end up with two objects that point at each other, one of them needs to be mutable. This is
|
||||
//! problematic because `Rc<T>` enforces memory safety by only giving out shared references to the
|
||||
//! object it wraps, and these don't allow direct mutation. We need to wrap the part of the object
|
||||
//! we wish to mutate in a `RefCell`, which provides *interior mutability*: a method to achieve
|
||||
//! mutability through a shared reference. `RefCell` enforces Rust's borrowing rules at runtime.
|
||||
//! Read the `Cell` documentation for more details on interior mutability.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::rc::Rc;
|
||||
@ -131,7 +125,7 @@
|
||||
//! for gadget_opt in gadget_owner.gadgets.borrow().iter() {
|
||||
//!
|
||||
//! // gadget_opt is a Weak<Gadget>. Since weak pointers can't guarantee
|
||||
//! // that their object is still alive, we need to call upgrade() on them
|
||||
//! // that their object is still allocated, we need to call upgrade() on them
|
||||
//! // to turn them into a strong reference. This returns an Option, which
|
||||
//! // contains a reference to our object if it still exists.
|
||||
//! let gadget = gadget_opt.upgrade().unwrap();
|
||||
@ -139,7 +133,7 @@
|
||||
//! }
|
||||
//!
|
||||
//! // At the end of the method, gadget_owner, gadget1 and gadget2 get
|
||||
//! // destroyed. There are now no strong (Rc) references to the gadgets.
|
||||
//! // destroyed. There are now no strong (`Rc<T>`) references to the gadgets.
|
||||
//! // Once they get destroyed, the Gadgets get destroyed. This zeroes the
|
||||
//! // reference count on Gadget Man, so he gets destroyed as well.
|
||||
//! }
|
||||
@ -147,18 +141,22 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::cell::Cell;
|
||||
use core::clone::Clone;
|
||||
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{mod, Hash};
|
||||
use core::kinds::marker;
|
||||
use core::mem::{transmute, min_align_of, size_of, forget};
|
||||
use core::ops::{Deref, Drop};
|
||||
use core::option::{Option, Some, None};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
use core::ptr;
|
||||
use core::ptr::RawPtr;
|
||||
use core::result::{Result, Ok, Err};
|
||||
use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
|
||||
use heap::deallocate;
|
||||
|
||||
@ -169,27 +167,35 @@ struct RcBox<T> {
|
||||
}
|
||||
|
||||
/// An immutable reference-counted pointer type.
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more details.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable]
|
||||
pub struct Rc<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
// FIXME #12808: strange names to try to avoid interfering with field accesses of the contained
|
||||
// type via Deref
|
||||
_ptr: *mut RcBox<T>,
|
||||
_nosend: marker::NoSend,
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
|
||||
impl<T> Rc<T> {
|
||||
/// Constructs a new reference-counted pointer.
|
||||
/// Constructs a new `Rc<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn new(value: T) -> Rc<T> {
|
||||
unsafe {
|
||||
Rc {
|
||||
// there is an implicit weak pointer owned by all the
|
||||
// strong pointers, which ensures that the weak
|
||||
// destructor never frees the allocation while the
|
||||
// strong destructor is running, even if the weak
|
||||
// pointer is stored inside the strong one.
|
||||
// there is an implicit weak pointer owned by all the strong pointers, which
|
||||
// ensures that the weak destructor never frees the allocation while the strong
|
||||
// destructor is running, even if the weak pointer is stored inside the strong one.
|
||||
_ptr: transmute(box RcBox {
|
||||
value: value,
|
||||
strong: Cell::new(1),
|
||||
@ -201,7 +207,17 @@ impl<T> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Downgrades the reference-counted pointer to a weak reference.
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[experimental = "Weak pointers may not belong in this module"]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
@ -213,28 +229,46 @@ impl<T> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the `Rc` currently has unique ownership.
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn weak_count<T>(this: &Rc<T>) -> uint { this.weak() - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count<T>(this: &Rc<T>) -> uint { this.strong() }
|
||||
|
||||
/// Returns true if there are no other `Rc` or `Weak<T>` values that share the same inner value.
|
||||
///
|
||||
/// Unique ownership means that there are no other `Rc` or `Weak` values
|
||||
/// that share the same contents.
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc;
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// rc::is_unique(&five);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn is_unique<T>(rc: &Rc<T>) -> bool {
|
||||
// note that we hold both a strong and a weak reference
|
||||
rc.strong() == 1 && rc.weak() == 1
|
||||
weak_count(rc) == 0 && strong_count(rc) == 1
|
||||
}
|
||||
|
||||
/// Unwraps the contained value if the `Rc` has unique ownership.
|
||||
/// Unwraps the contained value if the `Rc<T>` is unique.
|
||||
///
|
||||
/// If the `Rc` does not have unique ownership, `Err` is returned with the
|
||||
/// same `Rc`.
|
||||
/// If the `Rc<T>` is not unique, an `Err` is returned with the same `Rc<T>`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::{mod, Rc};
|
||||
///
|
||||
/// let x = Rc::new(3u);
|
||||
/// assert_eq!(rc::try_unwrap(x), Ok(3u));
|
||||
///
|
||||
/// let x = Rc::new(4u);
|
||||
/// let _y = x.clone();
|
||||
/// assert_eq!(rc::try_unwrap(x), Err(Rc::new(4u)));
|
||||
@ -257,18 +291,19 @@ pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the contained value if the `Rc` has
|
||||
/// unique ownership.
|
||||
/// Returns a mutable reference to the contained value if the `Rc<T>` is unique.
|
||||
///
|
||||
/// Returns `None` if the `Rc` does not have unique ownership.
|
||||
/// Returns `None` if the `Rc<T>` is not unique.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::{mod, Rc};
|
||||
///
|
||||
/// let mut x = Rc::new(3u);
|
||||
/// *rc::get_mut(&mut x).unwrap() = 4u;
|
||||
/// assert_eq!(*x, 4u);
|
||||
///
|
||||
/// let _y = x.clone();
|
||||
/// assert!(rc::get_mut(&mut x).is_none());
|
||||
/// ```
|
||||
@ -284,30 +319,43 @@ pub fn get_mut<'a, T>(rc: &'a mut Rc<T>) -> Option<&'a mut T> {
|
||||
}
|
||||
|
||||
impl<T: Clone> Rc<T> {
|
||||
/// Acquires a mutable pointer to the inner contents by guaranteeing that
|
||||
/// the reference count is one (no sharing is possible).
|
||||
/// Make a mutable reference from the given `Rc<T>`.
|
||||
///
|
||||
/// This is also referred to as a copy-on-write operation because the inner
|
||||
/// data is cloned if the reference count is greater than one.
|
||||
/// This is also referred to as a copy-on-write operation because the inner data is cloned if
|
||||
/// the reference count is greater than one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let mut five = Rc::new(5i);
|
||||
///
|
||||
/// let mut_five = five.make_unique();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn make_unique(&mut self) -> &mut T {
|
||||
if !is_unique(self) {
|
||||
*self = Rc::new((**self).clone())
|
||||
}
|
||||
// This unsafety is ok because we're guaranteed that the pointer
|
||||
// returned is the *only* pointer that will ever be returned to T. Our
|
||||
// reference count is guaranteed to be 1 at this point, and we required
|
||||
// the Rc itself to be `mut`, so we're returning the only possible
|
||||
// reference to the inner data.
|
||||
// This unsafety is ok because we're guaranteed that the pointer returned is the *only*
|
||||
// pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at
|
||||
// this point, and we required the `Rc<T>` itself to be `mut`, so we're returning the only
|
||||
// possible reference to the inner value.
|
||||
let inner = unsafe { &mut *self._ptr };
|
||||
&mut inner.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BorrowFrom<Rc<T>> for T {
|
||||
fn borrow_from(owned: &Rc<T>) -> &T {
|
||||
&**owned
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Deref is experimental."]
|
||||
impl<T> Deref<T> for Rc<T> {
|
||||
/// Borrows the value contained in the reference-counted pointer.
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &T {
|
||||
&self.inner().value
|
||||
@ -317,6 +365,30 @@ impl<T> Deref<T> for Rc<T> {
|
||||
#[unsafe_destructor]
|
||||
#[experimental = "Drop is experimental."]
|
||||
impl<T> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference count becomes zero
|
||||
/// and the only other references are `Weak<T>` ones, `drop`s the inner value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explict drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self._ptr.is_null() {
|
||||
@ -324,8 +396,8 @@ impl<T> Drop for Rc<T> {
|
||||
if self.strong() == 0 {
|
||||
ptr::read(&**self); // destroy the contained object
|
||||
|
||||
// remove the implicit "strong weak" pointer now
|
||||
// that we've destroyed the contents.
|
||||
// remove the implicit "strong weak" pointer now that we've destroyed the
|
||||
// contents.
|
||||
self.dec_weak();
|
||||
|
||||
if self.weak() == 0 {
|
||||
@ -338,8 +410,21 @@ impl<T> Drop for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "Clone is unstable."]
|
||||
#[stable]
|
||||
impl<T> Clone for Rc<T> {
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
///
|
||||
/// This increases the strong reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
@ -349,7 +434,18 @@ impl<T> Clone for Rc<T> {
|
||||
|
||||
#[stable]
|
||||
impl<T: Default> Default for Rc<T> {
|
||||
/// Creates a new `Rc<T>`, with the `Default` value for `T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
/// use std::default::Default;
|
||||
///
|
||||
/// let x: Rc<int> = Default::default();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn default() -> Rc<T> {
|
||||
Rc::new(Default::default())
|
||||
}
|
||||
@ -357,8 +453,35 @@ impl<T: Default> Default for Rc<T> {
|
||||
|
||||
#[unstable = "PartialEq is unstable."]
|
||||
impl<T: PartialEq> PartialEq for Rc<T> {
|
||||
/// Equality for two `Rc<T>`s.
|
||||
///
|
||||
/// Two `Rc<T>`s are equal if their inner value are equal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five == Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
|
||||
|
||||
/// Inequality for two `Rc<T>`s.
|
||||
///
|
||||
/// Two `Rc<T>`s are unequal if their inner value are unequal.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five != Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
|
||||
}
|
||||
@ -368,30 +491,116 @@ impl<T: Eq> Eq for Rc<T> {}
|
||||
|
||||
#[unstable = "PartialOrd is unstable."]
|
||||
impl<T: PartialOrd> PartialOrd for Rc<T> {
|
||||
/// Partial comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `partial_cmp()` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five.partial_cmp(&Rc::new(5i));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Rc<T>) -> Option<Ordering> {
|
||||
(**self).partial_cmp(&**other)
|
||||
}
|
||||
|
||||
/// Less-than comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `<` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five < Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn lt(&self, other: &Rc<T>) -> bool { **self < **other }
|
||||
|
||||
/// 'Less-than or equal to' comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `<=` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five <= Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn le(&self, other: &Rc<T>) -> bool { **self <= **other }
|
||||
|
||||
/// Greater-than comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `>` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five > Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn gt(&self, other: &Rc<T>) -> bool { **self > **other }
|
||||
|
||||
/// 'Greater-than or equal to' comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `>=` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five >= Rc::new(5i);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
|
||||
}
|
||||
|
||||
#[unstable = "Ord is unstable."]
|
||||
impl<T: Ord> Ord for Rc<T> {
|
||||
/// Comparison for two `Rc<T>`s.
|
||||
///
|
||||
/// The two are compared by calling `cmp()` on their inner values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// five.partial_cmp(&Rc::new(5i));
|
||||
/// ```
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
|
||||
}
|
||||
|
||||
// FIXME (#18248) Make `T` `Sized?`
|
||||
impl<S: hash::Writer, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Show is experimental."]
|
||||
impl<T: fmt::Show> fmt::Show for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@ -399,7 +608,11 @@ impl<T: fmt::Show> fmt::Show for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A weak reference to a reference-counted pointer.
|
||||
/// A weak version of `Rc<T>`.
|
||||
///
|
||||
/// Weak references do not count when determining if the inner value should be dropped.
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
pub struct Weak<T> {
|
||||
@ -414,8 +627,21 @@ pub struct Weak<T> {
|
||||
impl<T> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was
|
||||
/// destroyed.
|
||||
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was destroyed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5i);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
if self.strong() == 0 {
|
||||
None
|
||||
@ -429,12 +655,37 @@ impl<T> Weak<T> {
|
||||
#[unsafe_destructor]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
impl<T> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5i);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explict drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5i);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self._ptr.is_null() {
|
||||
self.dec_weak();
|
||||
// the weak count starts at 1, and will only go to
|
||||
// zero if all the strong pointers have disappeared.
|
||||
// the weak count starts at 1, and will only go to zero if all the strong pointers
|
||||
// have disappeared.
|
||||
if self.weak() == 0 {
|
||||
deallocate(self._ptr as *mut u8, size_of::<RcBox<T>>(),
|
||||
min_align_of::<RcBox<T>>())
|
||||
@ -446,6 +697,19 @@ impl<T> Drop for Weak<T> {
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
impl<T> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let weak_five = Rc::new(5i).downgrade();
|
||||
///
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
@ -489,10 +753,11 @@ impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
#[cfg(test)]
|
||||
#[allow(experimental)]
|
||||
mod tests {
|
||||
use super::{Rc, Weak};
|
||||
use super::{Rc, Weak, weak_count, strong_count};
|
||||
use std::cell::RefCell;
|
||||
use std::option::{Option, Some, None};
|
||||
use std::result::{Err, Ok};
|
||||
use std::option::Option;
|
||||
use std::option::Option::{Some, None};
|
||||
use std::result::Result::{Err, Ok};
|
||||
use std::mem::drop;
|
||||
use std::clone::Clone;
|
||||
|
||||
@ -566,6 +831,40 @@ mod tests {
|
||||
assert!(super::is_unique(&x));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strong_count() {
|
||||
let a = Rc::new(0u32);
|
||||
assert!(strong_count(&a) == 1);
|
||||
let w = a.downgrade();
|
||||
assert!(strong_count(&a) == 1);
|
||||
let b = w.upgrade().expect("upgrade of live rc failed");
|
||||
assert!(strong_count(&b) == 2);
|
||||
assert!(strong_count(&a) == 2);
|
||||
drop(w);
|
||||
drop(a);
|
||||
assert!(strong_count(&b) == 1);
|
||||
let c = b.clone();
|
||||
assert!(strong_count(&b) == 2);
|
||||
assert!(strong_count(&c) == 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_count() {
|
||||
let a = Rc::new(0u32);
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 0);
|
||||
let w = a.downgrade();
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 1);
|
||||
drop(w);
|
||||
assert!(strong_count(&a) == 1);
|
||||
assert!(weak_count(&a) == 0);
|
||||
let c = a.clone();
|
||||
assert!(strong_count(&a) == 2);
|
||||
assert!(weak_count(&a) == 0);
|
||||
drop(c);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_unwrap() {
|
||||
let x = Rc::new(3u);
|
||||
|
@ -23,12 +23,12 @@
|
||||
#![experimental]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![license = "MIT/ASL2"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
||||
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
extern crate alloc;
|
||||
@ -210,7 +210,7 @@ impl Arena {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn alloc_copy<T>(&self, op: || -> T) -> &mut T {
|
||||
fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
|
||||
unsafe {
|
||||
let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
|
||||
mem::min_align_of::<T>());
|
||||
@ -264,7 +264,7 @@ impl Arena {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn alloc_noncopy<T>(&self, op: || -> T) -> &mut T {
|
||||
fn alloc_noncopy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
|
||||
unsafe {
|
||||
let tydesc = get_tydesc::<T>();
|
||||
let (ty_ptr, ptr) =
|
||||
@ -288,7 +288,7 @@ impl Arena {
|
||||
/// Allocates a new item in the arena, using `op` to initialize the value,
|
||||
/// and returns a reference to it.
|
||||
#[inline]
|
||||
pub fn alloc<T>(&self, op: || -> T) -> &mut T {
|
||||
pub fn alloc<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
|
||||
unsafe {
|
||||
if intrinsics::needs_drop::<T>() {
|
||||
self.alloc_noncopy(op)
|
||||
@ -340,7 +340,7 @@ fn test_arena_destructors_fail() {
|
||||
arena.alloc(|| { [0u8, 1u8, 2u8] });
|
||||
}
|
||||
// Now, panic while allocating
|
||||
arena.alloc::<Rc<int>>(|| {
|
||||
arena.alloc::<Rc<int>, _>(|| {
|
||||
panic!();
|
||||
});
|
||||
}
|
||||
@ -467,7 +467,7 @@ impl<T> TypedArena<T> {
|
||||
}
|
||||
|
||||
let ptr: &mut T = unsafe {
|
||||
let ptr: &mut T = mem::transmute(self.ptr);
|
||||
let ptr: &mut T = mem::transmute(self.ptr.clone());
|
||||
ptr::write(ptr, object);
|
||||
self.ptr.set(self.ptr.get().offset(1));
|
||||
ptr
|
||||
|
@ -8,14 +8,19 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::prelude::*;
|
||||
use prelude::*;
|
||||
use std::rand;
|
||||
use std::rand::Rng;
|
||||
use test::Bencher;
|
||||
|
||||
pub fn insert_rand_n<M>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
insert: |&mut M, uint|,
|
||||
remove: |&mut M, uint|) {
|
||||
pub fn insert_rand_n<M, I, R>(n: uint,
|
||||
map: &mut M,
|
||||
b: &mut Bencher,
|
||||
mut insert: I,
|
||||
mut remove: R) where
|
||||
I: FnMut(&mut M, uint),
|
||||
R: FnMut(&mut M, uint),
|
||||
{
|
||||
// setup
|
||||
let mut rng = rand::weak_rng();
|
||||
|
||||
@ -31,9 +36,14 @@ pub fn insert_rand_n<M>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn insert_seq_n<M>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
insert: |&mut M, uint|,
|
||||
remove: |&mut M, uint|) {
|
||||
pub fn insert_seq_n<M, I, R>(n: uint,
|
||||
map: &mut M,
|
||||
b: &mut Bencher,
|
||||
mut insert: I,
|
||||
mut remove: R) where
|
||||
I: FnMut(&mut M, uint),
|
||||
R: FnMut(&mut M, uint),
|
||||
{
|
||||
// setup
|
||||
for i in range(0u, n) {
|
||||
insert(map, i * 2);
|
||||
@ -48,9 +58,14 @@ pub fn insert_seq_n<M>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_rand_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
insert: |&mut M, uint|,
|
||||
find: |&M, uint| -> T) {
|
||||
pub fn find_rand_n<M, T, I, F>(n: uint,
|
||||
map: &mut M,
|
||||
b: &mut Bencher,
|
||||
mut insert: I,
|
||||
mut find: F) where
|
||||
I: FnMut(&mut M, uint),
|
||||
F: FnMut(&M, uint) -> T,
|
||||
{
|
||||
// setup
|
||||
let mut rng = rand::weak_rng();
|
||||
let mut keys = Vec::from_fn(n, |_| rng.gen::<uint>() % n);
|
||||
@ -70,9 +85,14 @@ pub fn find_rand_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_seq_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
|
||||
insert: |&mut M, uint|,
|
||||
find: |&M, uint| -> T) {
|
||||
pub fn find_seq_n<M, T, I, F>(n: uint,
|
||||
map: &mut M,
|
||||
b: &mut Bencher,
|
||||
mut insert: I,
|
||||
mut find: F) where
|
||||
I: FnMut(&mut M, uint),
|
||||
F: FnMut(&M, uint) -> T,
|
||||
{
|
||||
// setup
|
||||
for i in range(0u, n) {
|
||||
insert(map, i);
|
||||
|
@ -10,12 +10,12 @@
|
||||
|
||||
//! A priority queue implemented with a binary heap.
|
||||
//!
|
||||
//! Insertions have `O(log n)` time complexity and checking or popping the largest element is
|
||||
//! `O(1)`. Converting a vector to a priority queue can be done in-place, and has `O(n)`
|
||||
//! Insertion and popping the largest element have `O(log n)` time complexity. Checking the largest
|
||||
//! element is `O(1)`. Converting a vector to a priority queue can be done in-place, and has `O(n)`
|
||||
//! complexity. A priority queue can also be converted to a sorted vector in-place, allowing it to
|
||||
//! be used for an `O(n log n)` in-place heapsort.
|
||||
//!
|
||||
//! # Example
|
||||
//! # Examples
|
||||
//!
|
||||
//! This is a larger example which implements [Dijkstra's algorithm][dijkstra]
|
||||
//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
|
||||
@ -29,7 +29,7 @@
|
||||
//! use std::collections::BinaryHeap;
|
||||
//! use std::uint;
|
||||
//!
|
||||
//! #[deriving(Eq, PartialEq)]
|
||||
//! #[deriving(Copy, Eq, PartialEq)]
|
||||
//! struct State {
|
||||
//! cost: uint,
|
||||
//! position: uint
|
||||
@ -68,15 +68,15 @@
|
||||
//! // dist[node] = current shortest distance from `start` to `node`
|
||||
//! let mut dist = Vec::from_elem(adj_list.len(), uint::MAX);
|
||||
//!
|
||||
//! let mut pq = BinaryHeap::new();
|
||||
//! let mut heap = BinaryHeap::new();
|
||||
//!
|
||||
//! // We're at `start`, with a zero cost
|
||||
//! dist[start] = 0u;
|
||||
//! pq.push(State { cost: 0u, position: start });
|
||||
//! heap.push(State { cost: 0u, position: start });
|
||||
//!
|
||||
//! // Examine the frontier with lower cost nodes first (min-heap)
|
||||
//! loop {
|
||||
//! let State { cost, position } = match pq.pop() {
|
||||
//! let State { cost, position } = match heap.pop() {
|
||||
//! None => break, // empty
|
||||
//! Some(s) => s
|
||||
//! };
|
||||
@ -94,7 +94,7 @@
|
||||
//!
|
||||
//! // If so, add it to the frontier and continue
|
||||
//! if next.cost < dist[next.position] {
|
||||
//! pq.push(next);
|
||||
//! heap.push(next);
|
||||
//! // Relaxation, we have now found a better way
|
||||
//! dist[next.position] = next.cost;
|
||||
//! }
|
||||
@ -160,9 +160,7 @@ use core::mem::{zeroed, replace, swap};
|
||||
use core::ptr;
|
||||
|
||||
use slice;
|
||||
use vec::Vec;
|
||||
|
||||
// FIXME(conventions): implement into_iter
|
||||
use vec::{mod, Vec};
|
||||
|
||||
/// A priority queue implemented with a binary heap.
|
||||
///
|
||||
@ -172,19 +170,21 @@ pub struct BinaryHeap<T> {
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<T: Ord> Default for BinaryHeap<T> {
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn default() -> BinaryHeap<T> { BinaryHeap::new() }
|
||||
}
|
||||
|
||||
impl<T: Ord> BinaryHeap<T> {
|
||||
/// Creates an empty `BinaryHeap` as a max-heap.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let pq: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> BinaryHeap<T> { BinaryHeap{data: vec!(),} }
|
||||
@ -194,11 +194,11 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// so that the `BinaryHeap` does not have to be reallocated
|
||||
/// until it contains at least that many values.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let pq: BinaryHeap<uint> = BinaryHeap::with_capacity(10u);
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::with_capacity(10u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn with_capacity(capacity: uint) -> BinaryHeap<T> {
|
||||
@ -208,11 +208,11 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// Creates a `BinaryHeap` from a vector. This is sometimes called
|
||||
/// `heapifying` the vector.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let pq = BinaryHeap::from_vec(vec![9i, 1, 2, 7, 3, 2]);
|
||||
/// let heap = BinaryHeap::from_vec(vec![9i, 1, 2, 7, 3, 2]);
|
||||
/// ```
|
||||
pub fn from_vec(xs: Vec<T>) -> BinaryHeap<T> {
|
||||
let mut q = BinaryHeap{data: xs,};
|
||||
@ -227,51 +227,73 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// An iterator visiting all values in underlying vector, in
|
||||
/// arbitrary order.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
|
||||
///
|
||||
/// // Print 1, 2, 3, 4 in arbitrary order
|
||||
/// for x in heap.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter { iter: self.data.iter() }
|
||||
}
|
||||
|
||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||
/// the binary heap in arbitrary order. The binary heap cannot be used
|
||||
/// after calling this.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let pq = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
|
||||
///
|
||||
/// // Print 1, 2, 3, 4 in arbitrary order
|
||||
/// for x in pq.iter() {
|
||||
/// for x in pq.into_iter() {
|
||||
/// // x has type int, not &int
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> Items<'a, T> {
|
||||
Items { iter: self.data.iter() }
|
||||
pub fn into_iter(self) -> IntoIter<T> {
|
||||
IntoIter { iter: self.data.into_iter() }
|
||||
}
|
||||
|
||||
/// Returns the greatest item in a queue, or `None` if it is empty.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::new();
|
||||
/// assert_eq!(pq.top(), None);
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// assert_eq!(heap.peek(), None);
|
||||
///
|
||||
/// pq.push(1i);
|
||||
/// pq.push(5i);
|
||||
/// pq.push(2i);
|
||||
/// assert_eq!(pq.top(), Some(&5i));
|
||||
/// heap.push(1i);
|
||||
/// heap.push(5i);
|
||||
/// heap.push(2i);
|
||||
/// assert_eq!(heap.peek(), Some(&5i));
|
||||
///
|
||||
/// ```
|
||||
pub fn top<'a>(&'a self) -> Option<&'a T> {
|
||||
if self.is_empty() { None } else { Some(&self.data[0]) }
|
||||
#[stable]
|
||||
pub fn peek(&self) -> Option<&T> {
|
||||
self.data.get(0)
|
||||
}
|
||||
|
||||
/// Returns the number of elements the queue can hold without reallocating.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let pq: BinaryHeap<uint> = BinaryHeap::with_capacity(100u);
|
||||
/// assert!(pq.capacity() >= 100u);
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::with_capacity(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn capacity(&self) -> uint { self.data.capacity() }
|
||||
@ -287,14 +309,14 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// Panics if the new capacity overflows `uint`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// pq.reserve_exact(100u);
|
||||
/// assert!(pq.capacity() >= 100u);
|
||||
/// let mut heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// heap.reserve_exact(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn reserve_exact(&mut self, additional: uint) { self.data.reserve_exact(additional) }
|
||||
@ -306,14 +328,14 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// Panics if the new capacity overflows `uint`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// pq.reserve(100u);
|
||||
/// assert!(pq.capacity() >= 100u);
|
||||
/// let mut heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// heap.reserve(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn reserve(&mut self, additional: uint) {
|
||||
@ -329,16 +351,16 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// Removes the greatest item from a queue and returns it, or `None` if it
|
||||
/// is empty.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::from_vec(vec![1i, 3]);
|
||||
/// let mut heap = BinaryHeap::from_vec(vec![1i, 3]);
|
||||
///
|
||||
/// assert_eq!(pq.pop(), Some(3i));
|
||||
/// assert_eq!(pq.pop(), Some(1i));
|
||||
/// assert_eq!(pq.pop(), None);
|
||||
/// assert_eq!(heap.pop(), Some(3i));
|
||||
/// assert_eq!(heap.pop(), Some(1i));
|
||||
/// assert_eq!(heap.pop(), None);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
@ -356,48 +378,54 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
|
||||
/// Pushes an item onto the queue.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::new();
|
||||
/// pq.push(3i);
|
||||
/// pq.push(5i);
|
||||
/// pq.push(1i);
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.push(3i);
|
||||
/// heap.push(5i);
|
||||
/// heap.push(1i);
|
||||
///
|
||||
/// assert_eq!(pq.len(), 3);
|
||||
/// assert_eq!(pq.top(), Some(&5i));
|
||||
/// assert_eq!(heap.len(), 3);
|
||||
/// assert_eq!(heap.peek(), Some(&5i));
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn push(&mut self, item: T) {
|
||||
let old_len = self.len();
|
||||
self.data.push(item);
|
||||
let new_len = self.len() - 1;
|
||||
self.siftup(0, new_len);
|
||||
self.siftup(0, old_len);
|
||||
}
|
||||
|
||||
/// Pushes an item onto a queue then pops the greatest item off the queue in
|
||||
/// an optimized fashion.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::new();
|
||||
/// pq.push(1i);
|
||||
/// pq.push(5i);
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.push(1i);
|
||||
/// heap.push(5i);
|
||||
///
|
||||
/// assert_eq!(pq.push_pop(3i), 5);
|
||||
/// assert_eq!(pq.push_pop(9i), 9);
|
||||
/// assert_eq!(pq.len(), 2);
|
||||
/// assert_eq!(pq.top(), Some(&3i));
|
||||
/// assert_eq!(heap.push_pop(3i), 5);
|
||||
/// assert_eq!(heap.push_pop(9i), 9);
|
||||
/// assert_eq!(heap.len(), 2);
|
||||
/// assert_eq!(heap.peek(), Some(&3i));
|
||||
/// ```
|
||||
pub fn push_pop(&mut self, mut item: T) -> T {
|
||||
if !self.is_empty() && *self.top().unwrap() > item {
|
||||
swap(&mut item, &mut self.data[0]);
|
||||
self.siftdown(0);
|
||||
match self.data.get_mut(0) {
|
||||
None => return item,
|
||||
Some(top) => if *top > item {
|
||||
swap(&mut item, top);
|
||||
} else {
|
||||
return item;
|
||||
},
|
||||
}
|
||||
|
||||
self.siftdown(0);
|
||||
item
|
||||
}
|
||||
|
||||
@ -405,17 +433,17 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// an optimized fashion. The push is done regardless of whether the queue
|
||||
/// was empty.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::new();
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
///
|
||||
/// assert_eq!(pq.replace(1i), None);
|
||||
/// assert_eq!(pq.replace(3i), Some(1i));
|
||||
/// assert_eq!(pq.len(), 1);
|
||||
/// assert_eq!(pq.top(), Some(&3i));
|
||||
/// assert_eq!(heap.replace(1i), None);
|
||||
/// assert_eq!(heap.replace(3i), Some(1i));
|
||||
/// assert_eq!(heap.len(), 1);
|
||||
/// assert_eq!(heap.peek(), Some(&3i));
|
||||
/// ```
|
||||
pub fn replace(&mut self, mut item: T) -> Option<T> {
|
||||
if !self.is_empty() {
|
||||
@ -431,45 +459,44 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// Consumes the `BinaryHeap` and returns the underlying vector
|
||||
/// in arbitrary order.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let pq = BinaryHeap::from_vec(vec![1i, 2, 3, 4, 5, 6, 7]);
|
||||
/// let vec = pq.into_vec();
|
||||
/// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4, 5, 6, 7]);
|
||||
/// let vec = heap.into_vec();
|
||||
///
|
||||
/// // Will print in some order
|
||||
/// for x in vec.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn into_vec(self) -> Vec<T> { let BinaryHeap{data: v} = self; v }
|
||||
pub fn into_vec(self) -> Vec<T> { self.data }
|
||||
|
||||
/// Consumes the `BinaryHeap` and returns a vector in sorted
|
||||
/// (ascending) order.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut pq = BinaryHeap::from_vec(vec![1i, 2, 4, 5, 7]);
|
||||
/// pq.push(6);
|
||||
/// pq.push(3);
|
||||
/// let mut heap = BinaryHeap::from_vec(vec![1i, 2, 4, 5, 7]);
|
||||
/// heap.push(6);
|
||||
/// heap.push(3);
|
||||
///
|
||||
/// let vec = pq.into_sorted_vec();
|
||||
/// let vec = heap.into_sorted_vec();
|
||||
/// assert_eq!(vec, vec![1i, 2, 3, 4, 5, 6, 7]);
|
||||
/// ```
|
||||
pub fn into_sorted_vec(self) -> Vec<T> {
|
||||
let mut q = self;
|
||||
let mut end = q.len();
|
||||
pub fn into_sorted_vec(mut self) -> Vec<T> {
|
||||
let mut end = self.len();
|
||||
while end > 1 {
|
||||
end -= 1;
|
||||
q.data.as_mut_slice().swap(0, end);
|
||||
q.siftdown_range(0, end)
|
||||
self.data.swap(0, end);
|
||||
self.siftdown_range(0, end)
|
||||
}
|
||||
q.into_vec()
|
||||
self.into_vec()
|
||||
}
|
||||
|
||||
// The implementations of siftup and siftdown use unsafe blocks in
|
||||
@ -530,28 +557,83 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Clears the queue, returning an iterator over the removed elements.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
|
||||
Drain {
|
||||
iter: self.data.drain(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Drops all items from the queue.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn clear(&mut self) { self.data.truncate(0) }
|
||||
pub fn clear(&mut self) { self.drain(); }
|
||||
}
|
||||
|
||||
/// `BinaryHeap` iterator.
|
||||
pub struct Items <'a, T:'a> {
|
||||
iter: slice::Items<'a, T>,
|
||||
pub struct Iter <'a, T: 'a> {
|
||||
iter: slice::Iter<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for Items<'a, T> {
|
||||
impl<'a, T> Iterator<&'a T> for Iter<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(&'a T)> { self.iter.next() }
|
||||
fn next(&mut self) -> Option<&'a T> { self.iter.next() }
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl<'a, T> DoubleEndedIterator<&'a T> for Iter<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
impl<'a, T> ExactSizeIterator<&'a T> for Iter<'a, T> {}
|
||||
|
||||
/// An iterator that moves out of a `BinaryHeap`.
|
||||
pub struct IntoIter<T> {
|
||||
iter: vec::IntoIter<T>,
|
||||
}
|
||||
|
||||
impl<T> Iterator<T> for IntoIter<T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> { self.iter.next() }
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl<T> DoubleEndedIterator<T> for IntoIter<T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
impl<T> ExactSizeIterator<T> for IntoIter<T> {}
|
||||
|
||||
/// An iterator that drains a `BinaryHeap`.
|
||||
pub struct Drain<'a, T: 'a> {
|
||||
iter: vec::Drain<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Iterator<T> for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> { self.iter.next() }
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> DoubleEndedIterator<T> for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> ExactSizeIterator<T> for Drain<'a, T> {}
|
||||
|
||||
impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
|
||||
fn from_iter<Iter: Iterator<T>>(mut iter: Iter) -> BinaryHeap<T> {
|
||||
let vec: Vec<T> = iter.collect();
|
||||
BinaryHeap::from_vec(vec)
|
||||
fn from_iter<Iter: Iterator<T>>(iter: Iter) -> BinaryHeap<T> {
|
||||
BinaryHeap::from_vec(iter.collect())
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,31 +651,77 @@ impl<T: Ord> Extend<T> for BinaryHeap<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::prelude::*;
|
||||
use prelude::*;
|
||||
|
||||
use super::BinaryHeap;
|
||||
use vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_iterator() {
|
||||
let data = vec!(5i, 9, 3);
|
||||
let iterout = [9i, 5, 3];
|
||||
let pq = BinaryHeap::from_vec(data);
|
||||
let heap = BinaryHeap::from_vec(data);
|
||||
let mut i = 0;
|
||||
for el in pq.iter() {
|
||||
for el in heap.iter() {
|
||||
assert_eq!(*el, iterout[i]);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_top_and_pop() {
|
||||
fn test_iterator_reverse() {
|
||||
let data = vec!(5i, 9, 3);
|
||||
let iterout = vec!(3i, 5, 9);
|
||||
let pq = BinaryHeap::from_vec(data);
|
||||
|
||||
let v: Vec<int> = pq.iter().rev().map(|&x| x).collect();
|
||||
assert_eq!(v, iterout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let data = vec!(5i, 9, 3);
|
||||
let iterout = vec!(9i, 5, 3);
|
||||
let pq = BinaryHeap::from_vec(data);
|
||||
|
||||
let v: Vec<int> = pq.into_iter().collect();
|
||||
assert_eq!(v, iterout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter_size_hint() {
|
||||
let data = vec!(5i, 9);
|
||||
let pq = BinaryHeap::from_vec(data);
|
||||
|
||||
let mut it = pq.into_iter();
|
||||
|
||||
assert_eq!(it.size_hint(), (2, Some(2)));
|
||||
assert_eq!(it.next(), Some(9i));
|
||||
|
||||
assert_eq!(it.size_hint(), (1, Some(1)));
|
||||
assert_eq!(it.next(), Some(5i));
|
||||
|
||||
assert_eq!(it.size_hint(), (0, Some(0)));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter_reverse() {
|
||||
let data = vec!(5i, 9, 3);
|
||||
let iterout = vec!(3i, 5, 9);
|
||||
let pq = BinaryHeap::from_vec(data);
|
||||
|
||||
let v: Vec<int> = pq.into_iter().rev().collect();
|
||||
assert_eq!(v, iterout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peek_and_pop() {
|
||||
let data = vec!(2u, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1);
|
||||
let mut sorted = data.clone();
|
||||
sorted.sort();
|
||||
let mut heap = BinaryHeap::from_vec(data);
|
||||
while !heap.is_empty() {
|
||||
assert_eq!(heap.top().unwrap(), sorted.last().unwrap());
|
||||
assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
|
||||
assert_eq!(heap.pop().unwrap(), sorted.pop().unwrap());
|
||||
}
|
||||
}
|
||||
@ -602,44 +730,44 @@ mod tests {
|
||||
fn test_push() {
|
||||
let mut heap = BinaryHeap::from_vec(vec!(2i, 4, 9));
|
||||
assert_eq!(heap.len(), 3);
|
||||
assert!(*heap.top().unwrap() == 9);
|
||||
assert!(*heap.peek().unwrap() == 9);
|
||||
heap.push(11);
|
||||
assert_eq!(heap.len(), 4);
|
||||
assert!(*heap.top().unwrap() == 11);
|
||||
assert!(*heap.peek().unwrap() == 11);
|
||||
heap.push(5);
|
||||
assert_eq!(heap.len(), 5);
|
||||
assert!(*heap.top().unwrap() == 11);
|
||||
assert!(*heap.peek().unwrap() == 11);
|
||||
heap.push(27);
|
||||
assert_eq!(heap.len(), 6);
|
||||
assert!(*heap.top().unwrap() == 27);
|
||||
assert!(*heap.peek().unwrap() == 27);
|
||||
heap.push(3);
|
||||
assert_eq!(heap.len(), 7);
|
||||
assert!(*heap.top().unwrap() == 27);
|
||||
assert!(*heap.peek().unwrap() == 27);
|
||||
heap.push(103);
|
||||
assert_eq!(heap.len(), 8);
|
||||
assert!(*heap.top().unwrap() == 103);
|
||||
assert!(*heap.peek().unwrap() == 103);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_unique() {
|
||||
let mut heap = BinaryHeap::from_vec(vec!(box 2i, box 4, box 9));
|
||||
assert_eq!(heap.len(), 3);
|
||||
assert!(*heap.top().unwrap() == box 9);
|
||||
assert!(*heap.peek().unwrap() == box 9);
|
||||
heap.push(box 11);
|
||||
assert_eq!(heap.len(), 4);
|
||||
assert!(*heap.top().unwrap() == box 11);
|
||||
assert!(*heap.peek().unwrap() == box 11);
|
||||
heap.push(box 5);
|
||||
assert_eq!(heap.len(), 5);
|
||||
assert!(*heap.top().unwrap() == box 11);
|
||||
assert!(*heap.peek().unwrap() == box 11);
|
||||
heap.push(box 27);
|
||||
assert_eq!(heap.len(), 6);
|
||||
assert!(*heap.top().unwrap() == box 27);
|
||||
assert!(*heap.peek().unwrap() == box 27);
|
||||
heap.push(box 3);
|
||||
assert_eq!(heap.len(), 7);
|
||||
assert!(*heap.top().unwrap() == box 27);
|
||||
assert!(*heap.peek().unwrap() == box 27);
|
||||
heap.push(box 103);
|
||||
assert_eq!(heap.len(), 8);
|
||||
assert!(*heap.top().unwrap() == box 103);
|
||||
assert!(*heap.peek().unwrap() == box 103);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -676,8 +804,8 @@ mod tests {
|
||||
v.sort();
|
||||
data.sort();
|
||||
|
||||
assert_eq!(v.as_slice(), data.as_slice());
|
||||
assert_eq!(heap.into_sorted_vec().as_slice(), data.as_slice());
|
||||
assert_eq!(v, data);
|
||||
assert_eq!(heap.into_sorted_vec(), data);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -699,30 +827,40 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_empty_pop() {
|
||||
let mut heap: BinaryHeap<int> = BinaryHeap::new();
|
||||
let mut heap = BinaryHeap::<int>::new();
|
||||
assert!(heap.pop().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_top() {
|
||||
let empty: BinaryHeap<int> = BinaryHeap::new();
|
||||
assert!(empty.top().is_none());
|
||||
fn test_empty_peek() {
|
||||
let empty = BinaryHeap::<int>::new();
|
||||
assert!(empty.peek().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_replace() {
|
||||
let mut heap: BinaryHeap<int> = BinaryHeap::new();
|
||||
heap.replace(5).is_none();
|
||||
let mut heap = BinaryHeap::<int>::new();
|
||||
assert!(heap.replace(5).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = vec!(9u, 8, 7, 6, 5, 4, 3, 2, 1);
|
||||
|
||||
let mut q: BinaryHeap<uint> = xs.as_slice().iter().rev().map(|&x| x).collect();
|
||||
let mut q: BinaryHeap<uint> = xs.iter().rev().map(|&x| x).collect();
|
||||
|
||||
for &x in xs.iter() {
|
||||
assert_eq!(q.pop().unwrap(), x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_drain() {
|
||||
let mut q: BinaryHeap<_> =
|
||||
[9u, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
|
||||
|
||||
assert_eq!(q.drain().take(5).count(), 5);
|
||||
|
||||
assert!(q.is_empty());
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,16 +13,15 @@
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use btree_map::{BTreeMap, Keys, MoveEntries};
|
||||
use btree_map::{BTreeMap, Keys};
|
||||
use std::hash::Hash;
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::default::Default;
|
||||
use core::{iter, fmt};
|
||||
use core::iter::Peekable;
|
||||
use core::fmt;
|
||||
use core::iter::{Peekable, Map};
|
||||
use core::fmt::Show;
|
||||
|
||||
// FIXME(conventions): implement bounded iterators
|
||||
// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub
|
||||
|
||||
/// A set based on a B-Tree.
|
||||
///
|
||||
@ -34,37 +33,49 @@ pub struct BTreeSet<T>{
|
||||
}
|
||||
|
||||
/// An iterator over a BTreeSet's items.
|
||||
pub type Items<'a, T> = Keys<'a, T, ()>;
|
||||
pub struct Iter<'a, T: 'a> {
|
||||
iter: Keys<'a, T, ()>
|
||||
}
|
||||
|
||||
/// An owning iterator over a BTreeSet's items.
|
||||
pub type MoveItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
|
||||
pub struct IntoIter<T> {
|
||||
iter: Map<(T, ()), T, ::btree_map::IntoIter<T, ()>, fn((T, ())) -> T>
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set difference (in-order).
|
||||
pub struct DifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, Items<'a, T>>,
|
||||
b: Peekable<&'a T, Items<'a, T>>,
|
||||
pub struct Difference<'a, T:'a> {
|
||||
a: Peekable<&'a T, Iter<'a, T>>,
|
||||
b: Peekable<&'a T, Iter<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set symmetric difference (in-order).
|
||||
pub struct SymDifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, Items<'a, T>>,
|
||||
b: Peekable<&'a T, Items<'a, T>>,
|
||||
pub struct SymmetricDifference<'a, T:'a> {
|
||||
a: Peekable<&'a T, Iter<'a, T>>,
|
||||
b: Peekable<&'a T, Iter<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set intersection (in-order).
|
||||
pub struct IntersectionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, Items<'a, T>>,
|
||||
b: Peekable<&'a T, Items<'a, T>>,
|
||||
pub struct Intersection<'a, T:'a> {
|
||||
a: Peekable<&'a T, Iter<'a, T>>,
|
||||
b: Peekable<&'a T, Iter<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set union (in-order).
|
||||
pub struct UnionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, Items<'a, T>>,
|
||||
b: Peekable<&'a T, Items<'a, T>>,
|
||||
pub struct Union<'a, T:'a> {
|
||||
a: Peekable<&'a T, Iter<'a, T>>,
|
||||
b: Peekable<&'a T, Iter<'a, T>>,
|
||||
}
|
||||
|
||||
impl<T: Ord> BTreeSet<T> {
|
||||
/// Makes a new BTreeSet with a reasonable choice of B.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut set: BTreeSet<int> = BTreeSet::new();
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> BTreeSet<T> {
|
||||
BTreeSet { map: BTreeMap::new() }
|
||||
@ -80,48 +91,143 @@ impl<T: Ord> BTreeSet<T> {
|
||||
|
||||
impl<T> BTreeSet<T> {
|
||||
/// Gets an iterator over the BTreeSet's contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let set: BTreeSet<uint> = [1u, 2, 3, 4].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// for x in set.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let v: Vec<uint> = set.iter().map(|&x| x).collect();
|
||||
/// assert_eq!(v, vec![1u,2,3,4]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> Items<'a, T> {
|
||||
self.map.keys()
|
||||
pub fn iter<'a>(&'a self) -> Iter<'a, T> {
|
||||
Iter { iter: self.map.keys() }
|
||||
}
|
||||
|
||||
/// Gets an iterator for moving out the BtreeSet's contents.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let set: BTreeSet<uint> = [1u, 2, 3, 4].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// let v: Vec<uint> = set.into_iter().collect();
|
||||
/// assert_eq!(v, vec![1u,2,3,4]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn into_iter(self) -> MoveItems<T> {
|
||||
self.map.into_iter().map(|(k, _)| k)
|
||||
pub fn into_iter(self) -> IntoIter<T> {
|
||||
fn first<A, B>((a, _): (A, B)) -> A { a }
|
||||
let first: fn((T, ())) -> T = first; // coerce to fn pointer
|
||||
|
||||
IntoIter { iter: self.map.into_iter().map(first) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> BTreeSet<T> {
|
||||
/// Visits the values representing the difference, in ascending order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut a = BTreeSet::new();
|
||||
/// a.insert(1u);
|
||||
/// a.insert(2u);
|
||||
///
|
||||
/// let mut b = BTreeSet::new();
|
||||
/// b.insert(2u);
|
||||
/// b.insert(3u);
|
||||
///
|
||||
/// let diff: Vec<uint> = a.difference(&b).cloned().collect();
|
||||
/// assert_eq!(diff, vec![1u]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> DifferenceItems<'a, T> {
|
||||
DifferenceItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> Difference<'a, T> {
|
||||
Difference{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the symmetric difference, in ascending order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut a = BTreeSet::new();
|
||||
/// a.insert(1u);
|
||||
/// a.insert(2u);
|
||||
///
|
||||
/// let mut b = BTreeSet::new();
|
||||
/// b.insert(2u);
|
||||
/// b.insert(3u);
|
||||
///
|
||||
/// let sym_diff: Vec<uint> = a.symmetric_difference(&b).cloned().collect();
|
||||
/// assert_eq!(sym_diff, vec![1u,3]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn symmetric_difference<'a>(&'a self, other: &'a BTreeSet<T>)
|
||||
-> SymDifferenceItems<'a, T> {
|
||||
SymDifferenceItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
-> SymmetricDifference<'a, T> {
|
||||
SymmetricDifference{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the intersection, in ascending order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut a = BTreeSet::new();
|
||||
/// a.insert(1u);
|
||||
/// a.insert(2u);
|
||||
///
|
||||
/// let mut b = BTreeSet::new();
|
||||
/// b.insert(2u);
|
||||
/// b.insert(3u);
|
||||
///
|
||||
/// let intersection: Vec<uint> = a.intersection(&b).cloned().collect();
|
||||
/// assert_eq!(intersection, vec![2u]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn intersection<'a>(&'a self, other: &'a BTreeSet<T>)
|
||||
-> IntersectionItems<'a, T> {
|
||||
IntersectionItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
-> Intersection<'a, T> {
|
||||
Intersection{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the union, in ascending order.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let mut a = BTreeSet::new();
|
||||
/// a.insert(1u);
|
||||
///
|
||||
/// let mut b = BTreeSet::new();
|
||||
/// b.insert(2u);
|
||||
///
|
||||
/// let union: Vec<uint> = a.union(&b).cloned().collect();
|
||||
/// assert_eq!(union, vec![1u,2]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn union<'a>(&'a self, other: &'a BTreeSet<T>) -> UnionItems<'a, T> {
|
||||
UnionItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
pub fn union<'a>(&'a self, other: &'a BTreeSet<T>) -> Union<'a, T> {
|
||||
Union{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Return the number of elements in the set
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -136,7 +242,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
|
||||
/// Returns true if the set contains no elements
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -151,7 +257,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
|
||||
/// Clears the set, removing all values.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -172,7 +278,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
/// but the ordering on the borrowed form *must* match the
|
||||
/// ordering on the value type.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -189,7 +295,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
/// Returns `true` if the set has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -210,7 +316,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
|
||||
/// Returns `true` if the set is a subset of another.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -252,7 +358,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
|
||||
/// Returns `true` if the set is a superset of another.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -277,7 +383,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
/// Adds a value to the set. Returns `true` if the value was not already
|
||||
/// present in the set.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -300,7 +406,7 @@ impl<T: Ord> BTreeSet<T> {
|
||||
/// but the ordering on the borrowed form *must* match the
|
||||
/// ordering on the value type.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
@ -334,12 +440,98 @@ impl<T: Ord> Extend<T> for BTreeSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<T: Ord> Default for BTreeSet<T> {
|
||||
#[stable]
|
||||
fn default() -> BTreeSet<T> {
|
||||
BTreeSet::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet<T>, BTreeSet<T>> for &'a BTreeSet<T> {
|
||||
/// Returns the difference of `self` and `rhs` as a new `BTreeSet<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let a: BTreeSet<int> = vec![1, 2, 3].into_iter().collect();
|
||||
/// let b: BTreeSet<int> = vec![3, 4, 5].into_iter().collect();
|
||||
///
|
||||
/// let result: BTreeSet<int> = &a - &b;
|
||||
/// let result_vec: Vec<int> = result.into_iter().collect();
|
||||
/// assert_eq!(result_vec, vec![1, 2]);
|
||||
/// ```
|
||||
fn sub(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
|
||||
self.difference(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet<T>, BTreeSet<T>> for &'a BTreeSet<T> {
|
||||
/// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let a: BTreeSet<int> = vec![1, 2, 3].into_iter().collect();
|
||||
/// let b: BTreeSet<int> = vec![2, 3, 4].into_iter().collect();
|
||||
///
|
||||
/// let result: BTreeSet<int> = &a ^ &b;
|
||||
/// let result_vec: Vec<int> = result.into_iter().collect();
|
||||
/// assert_eq!(result_vec, vec![1, 4]);
|
||||
/// ```
|
||||
fn bitxor(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
|
||||
self.symmetric_difference(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet<T>, BTreeSet<T>> for &'a BTreeSet<T> {
|
||||
/// Returns the intersection of `self` and `rhs` as a new `BTreeSet<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let a: BTreeSet<int> = vec![1, 2, 3].into_iter().collect();
|
||||
/// let b: BTreeSet<int> = vec![2, 3, 4].into_iter().collect();
|
||||
///
|
||||
/// let result: BTreeSet<int> = &a & &b;
|
||||
/// let result_vec: Vec<int> = result.into_iter().collect();
|
||||
/// assert_eq!(result_vec, vec![2, 3]);
|
||||
/// ```
|
||||
fn bitand(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
|
||||
self.intersection(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet<T>, BTreeSet<T>> for &'a BTreeSet<T> {
|
||||
/// Returns the union of `self` and `rhs` as a new `BTreeSet<T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BTreeSet;
|
||||
///
|
||||
/// let a: BTreeSet<int> = vec![1, 2, 3].into_iter().collect();
|
||||
/// let b: BTreeSet<int> = vec![3, 4, 5].into_iter().collect();
|
||||
///
|
||||
/// let result: BTreeSet<int> = &a | &b;
|
||||
/// let result_vec: Vec<int> = result.into_iter().collect();
|
||||
/// assert_eq!(result_vec, vec![1, 2, 3, 4, 5]);
|
||||
/// ```
|
||||
fn bitor(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
|
||||
self.union(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Show> Show for BTreeSet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{{"));
|
||||
@ -353,6 +545,25 @@ impl<T: Show> Show for BTreeSet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for Iter<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> { self.iter.next() }
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
impl<'a, T> DoubleEndedIterator<&'a T> for Iter<'a, T> {
|
||||
fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back() }
|
||||
}
|
||||
impl<'a, T> ExactSizeIterator<&'a T> for Iter<'a, T> {}
|
||||
|
||||
|
||||
impl<T> Iterator<T> for IntoIter<T> {
|
||||
fn next(&mut self) -> Option<T> { self.iter.next() }
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
impl<T> DoubleEndedIterator<T> for IntoIter<T> {
|
||||
fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
|
||||
}
|
||||
impl<T> ExactSizeIterator<T> for IntoIter<T> {}
|
||||
|
||||
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
|
||||
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
|
||||
short: Ordering, long: Ordering) -> Ordering {
|
||||
@ -363,7 +574,7 @@ fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for DifferenceItems<'a, T> {
|
||||
impl<'a, T: Ord> Iterator<&'a T> for Difference<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) {
|
||||
@ -375,7 +586,7 @@ impl<'a, T: Ord> Iterator<&'a T> for DifferenceItems<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for SymDifferenceItems<'a, T> {
|
||||
impl<'a, T: Ord> Iterator<&'a T> for SymmetricDifference<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
|
||||
@ -387,7 +598,7 @@ impl<'a, T: Ord> Iterator<&'a T> for SymDifferenceItems<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for IntersectionItems<'a, T> {
|
||||
impl<'a, T: Ord> Iterator<&'a T> for Intersection<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
let o_cmp = match (self.a.peek(), self.b.peek()) {
|
||||
@ -405,7 +616,7 @@ impl<'a, T: Ord> Iterator<&'a T> for IntersectionItems<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for UnionItems<'a, T> {
|
||||
impl<'a, T: Ord> Iterator<&'a T> for Union<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
|
||||
@ -420,7 +631,7 @@ impl<'a, T: Ord> Iterator<&'a T> for UnionItems<'a, T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::prelude::*;
|
||||
use prelude::*;
|
||||
|
||||
use super::BTreeSet;
|
||||
use std::hash;
|
||||
@ -451,10 +662,23 @@ mod test {
|
||||
assert!(hash::hash(&x) == hash::hash(&y));
|
||||
}
|
||||
|
||||
fn check(a: &[int],
|
||||
b: &[int],
|
||||
expected: &[int],
|
||||
f: |&BTreeSet<int>, &BTreeSet<int>, f: |&int| -> bool| -> bool) {
|
||||
struct Counter<'a, 'b> {
|
||||
i: &'a mut uint,
|
||||
expected: &'b [int],
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnMut(&'c int) -> bool for Counter<'a, 'b> {
|
||||
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c int,)) -> bool {
|
||||
assert_eq!(x, self.expected[*self.i]);
|
||||
*self.i += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn check<F>(a: &[int], b: &[int], expected: &[int], f: F) where
|
||||
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
|
||||
F: FnOnce(&BTreeSet<int>, &BTreeSet<int>, Counter) -> bool,
|
||||
{
|
||||
let mut set_a = BTreeSet::new();
|
||||
let mut set_b = BTreeSet::new();
|
||||
|
||||
@ -462,11 +686,7 @@ mod test {
|
||||
for y in b.iter() { assert!(set_b.insert(*y)) }
|
||||
|
||||
let mut i = 0;
|
||||
f(&set_a, &set_b, |x| {
|
||||
assert_eq!(*x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
@ -580,7 +800,7 @@ mod test {
|
||||
|
||||
let set_str = format!("{}", set);
|
||||
|
||||
assert!(set_str == "{1, 2}".to_string());
|
||||
assert_eq!(format!("{}", empty), "{}".to_string());
|
||||
assert!(set_str == "{1, 2}");
|
||||
assert_eq!(format!("{}", empty), "{}");
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,8 @@
|
||||
|
||||
//! A doubly-linked list with owned nodes.
|
||||
//!
|
||||
//! The `DList` allows pushing and popping elements at either end.
|
||||
//!
|
||||
//! `DList` implements the trait `Deque`. It should be imported with
|
||||
//! `use collections::Deque`.
|
||||
//! The `DList` allows pushing and popping elements at either end and is thus
|
||||
//! efficiently usable as a double-ended queue.
|
||||
|
||||
// DList is constructed like a singly-linked list over the field `next`.
|
||||
// including the last link being None; each Node owns its `next` field.
|
||||
@ -39,7 +37,12 @@ pub struct DList<T> {
|
||||
}
|
||||
|
||||
type Link<T> = Option<Box<Node<T>>>;
|
||||
struct Rawlink<T> { p: *mut T }
|
||||
|
||||
struct Rawlink<T> {
|
||||
p: *mut T,
|
||||
}
|
||||
|
||||
impl<T> Copy for Rawlink<T> {}
|
||||
|
||||
struct Node<T> {
|
||||
next: Link<T>,
|
||||
@ -48,19 +51,21 @@ struct Node<T> {
|
||||
}
|
||||
|
||||
/// An iterator over references to the items of a `DList`.
|
||||
pub struct Items<'a, T:'a> {
|
||||
pub struct Iter<'a, T:'a> {
|
||||
head: &'a Link<T>,
|
||||
tail: Rawlink<Node<T>>,
|
||||
nelem: uint,
|
||||
}
|
||||
|
||||
// FIXME #11820: the &'a Option<> of the Link stops clone working.
|
||||
impl<'a, T> Clone for Items<'a, T> {
|
||||
fn clone(&self) -> Items<'a, T> { *self }
|
||||
impl<'a, T> Clone for Iter<'a, T> {
|
||||
fn clone(&self) -> Iter<'a, T> { *self }
|
||||
}
|
||||
|
||||
impl<'a,T> Copy for Iter<'a,T> {}
|
||||
|
||||
/// An iterator over mutable references to the items of a `DList`.
|
||||
pub struct MutItems<'a, T:'a> {
|
||||
pub struct IterMut<'a, T:'a> {
|
||||
list: &'a mut DList<T>,
|
||||
head: Rawlink<Node<T>>,
|
||||
tail: Rawlink<Node<T>>,
|
||||
@ -69,7 +74,7 @@ pub struct MutItems<'a, T:'a> {
|
||||
|
||||
/// An iterator over mutable references to the items of a `DList`.
|
||||
#[deriving(Clone)]
|
||||
pub struct MoveItems<T> {
|
||||
pub struct IntoIter<T> {
|
||||
list: DList<T>
|
||||
}
|
||||
|
||||
@ -187,8 +192,10 @@ impl<T> DList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<T> Default for DList<T> {
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn default() -> DList<T> { DList::new() }
|
||||
}
|
||||
|
||||
@ -204,7 +211,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// If the list is empty, does nothing.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -231,7 +238,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// If the list is empty, does nothing.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -258,7 +265,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -299,7 +306,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -328,7 +335,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// This operation should compute in O(N) time.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -346,18 +353,16 @@ impl<T> DList<T> {
|
||||
/// println!("{}", e); // prints 2, then 4, then 11, then 7, then 8
|
||||
/// }
|
||||
/// ```
|
||||
pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) {
|
||||
{
|
||||
let mut it = self.iter_mut();
|
||||
loop {
|
||||
match it.peek_next() {
|
||||
None => break,
|
||||
Some(x) => if f(x, &elt) { break }
|
||||
}
|
||||
it.next();
|
||||
pub fn insert_when<F>(&mut self, elt: T, mut f: F) where F: FnMut(&T, &T) -> bool {
|
||||
let mut it = self.iter_mut();
|
||||
loop {
|
||||
match it.peek_next() {
|
||||
None => break,
|
||||
Some(x) => if f(x, &elt) { break }
|
||||
}
|
||||
it.insert_next(elt);
|
||||
it.next();
|
||||
}
|
||||
it.insert_next(elt);
|
||||
}
|
||||
|
||||
/// Merges `other` into this `DList`, using the function `f`.
|
||||
@ -366,7 +371,7 @@ impl<T> DList<T> {
|
||||
/// put `a` in the result if `f(a, b)` is true, and otherwise `b`.
|
||||
///
|
||||
/// This operation should compute in O(max(N, M)) time.
|
||||
pub fn merge(&mut self, mut other: DList<T>, f: |&T, &T| -> bool) {
|
||||
pub fn merge<F>(&mut self, mut other: DList<T>, mut f: F) where F: FnMut(&T, &T) -> bool {
|
||||
{
|
||||
let mut it = self.iter_mut();
|
||||
loop {
|
||||
@ -389,19 +394,19 @@ impl<T> DList<T> {
|
||||
/// Provides a forward iterator.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> Items<'a, T> {
|
||||
Items{nelem: self.len(), head: &self.list_head, tail: self.list_tail}
|
||||
pub fn iter<'a>(&'a self) -> Iter<'a, T> {
|
||||
Iter{nelem: self.len(), head: &self.list_head, tail: self.list_tail}
|
||||
}
|
||||
|
||||
/// Provides a forward iterator with mutable references.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> {
|
||||
pub fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> {
|
||||
let head_raw = match self.list_head {
|
||||
Some(ref mut h) => Rawlink::some(&mut **h),
|
||||
None => Rawlink::none(),
|
||||
};
|
||||
MutItems{
|
||||
IterMut{
|
||||
nelem: self.len(),
|
||||
head: head_raw,
|
||||
tail: self.list_tail,
|
||||
@ -412,8 +417,8 @@ impl<T> DList<T> {
|
||||
/// Consumes the list into an iterator yielding elements by value.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn into_iter(self) -> MoveItems<T> {
|
||||
MoveItems{list: self}
|
||||
pub fn into_iter(self) -> IntoIter<T> {
|
||||
IntoIter{list: self}
|
||||
}
|
||||
|
||||
/// Returns `true` if the `DList` is empty.
|
||||
@ -446,7 +451,7 @@ impl<T> DList<T> {
|
||||
/// Provides a reference to the front element, or `None` if the list is
|
||||
/// empty.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn front(&self) -> Option<&T> {
|
||||
self.list_head.as_ref().map(|head| &head.value)
|
||||
}
|
||||
@ -454,7 +459,7 @@ impl<T> DList<T> {
|
||||
/// Provides a mutable reference to the front element, or `None` if the list
|
||||
/// is empty.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn front_mut(&mut self) -> Option<&mut T> {
|
||||
self.list_head.as_mut().map(|head| &mut head.value)
|
||||
}
|
||||
@ -462,7 +467,7 @@ impl<T> DList<T> {
|
||||
/// Provides a reference to the back element, or `None` if the list is
|
||||
/// empty.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn back(&self) -> Option<&T> {
|
||||
self.list_tail.resolve_immut().as_ref().map(|tail| &tail.value)
|
||||
}
|
||||
@ -470,7 +475,7 @@ impl<T> DList<T> {
|
||||
/// Provides a mutable reference to the back element, or `None` if the list
|
||||
/// is empty.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
#[stable]
|
||||
pub fn back_mut(&mut self) -> Option<&mut T> {
|
||||
self.list_tail.resolve().map(|tail| &mut tail.value)
|
||||
}
|
||||
@ -500,7 +505,7 @@ impl<T> DList<T> {
|
||||
|
||||
/// Appends an element to the back of a list
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -524,7 +529,7 @@ impl<T> DList<T> {
|
||||
/// Removes the last element from a list and returns it, or `None` if
|
||||
/// it is empty.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::collections::DList;
|
||||
@ -574,7 +579,7 @@ impl<T> Drop for DList<T> {
|
||||
}
|
||||
|
||||
|
||||
impl<'a, A> Iterator<&'a A> for Items<'a, A> {
|
||||
impl<'a, A> Iterator<&'a A> for Iter<'a, A> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a A> {
|
||||
if self.nelem == 0 {
|
||||
@ -593,7 +598,7 @@ impl<'a, A> Iterator<&'a A> for Items<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> DoubleEndedIterator<&'a A> for Items<'a, A> {
|
||||
impl<'a, A> DoubleEndedIterator<&'a A> for Iter<'a, A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a A> {
|
||||
if self.nelem == 0 {
|
||||
@ -607,9 +612,9 @@ impl<'a, A> DoubleEndedIterator<&'a A> for Items<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> ExactSize<&'a A> for Items<'a, A> {}
|
||||
impl<'a, A> ExactSizeIterator<&'a A> for Iter<'a, A> {}
|
||||
|
||||
impl<'a, A> Iterator<&'a mut A> for MutItems<'a, A> {
|
||||
impl<'a, A> Iterator<&'a mut A> for IterMut<'a, A> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a mut A> {
|
||||
if self.nelem == 0 {
|
||||
@ -631,7 +636,7 @@ impl<'a, A> Iterator<&'a mut A> for MutItems<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> DoubleEndedIterator<&'a mut A> for MutItems<'a, A> {
|
||||
impl<'a, A> DoubleEndedIterator<&'a mut A> for IterMut<'a, A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<&'a mut A> {
|
||||
if self.nelem == 0 {
|
||||
@ -645,7 +650,7 @@ impl<'a, A> DoubleEndedIterator<&'a mut A> for MutItems<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> ExactSize<&'a mut A> for MutItems<'a, A> {}
|
||||
impl<'a, A> ExactSizeIterator<&'a mut A> for IterMut<'a, A> {}
|
||||
|
||||
/// Allows mutating a `DList` while iterating.
|
||||
pub trait ListInsertion<A> {
|
||||
@ -659,8 +664,8 @@ pub trait ListInsertion<A> {
|
||||
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A>;
|
||||
}
|
||||
|
||||
// private methods for MutItems
|
||||
impl<'a, A> MutItems<'a, A> {
|
||||
// private methods for IterMut
|
||||
impl<'a, A> IterMut<'a, A> {
|
||||
fn insert_next_node(&mut self, mut ins_node: Box<Node<A>>) {
|
||||
// Insert before `self.head` so that it is between the
|
||||
// previously yielded element and self.head.
|
||||
@ -682,14 +687,14 @@ impl<'a, A> MutItems<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A> ListInsertion<A> for MutItems<'a, A> {
|
||||
impl<'a, A> ListInsertion<A> for IterMut<'a, A> {
|
||||
#[inline]
|
||||
fn insert_next(&mut self, elt: A) {
|
||||
self.insert_next_node(box Node::new(elt))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn peek_next<'a>(&'a mut self) -> Option<&'a mut A> {
|
||||
fn peek_next(&mut self) -> Option<&mut A> {
|
||||
if self.nelem == 0 {
|
||||
return None
|
||||
}
|
||||
@ -697,7 +702,7 @@ impl<'a, A> ListInsertion<A> for MutItems<'a, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Iterator<A> for MoveItems<A> {
|
||||
impl<A> Iterator<A> for IntoIter<A> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> { self.list.pop_front() }
|
||||
|
||||
@ -707,7 +712,7 @@ impl<A> Iterator<A> for MoveItems<A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> DoubleEndedIterator<A> for MoveItems<A> {
|
||||
impl<A> DoubleEndedIterator<A> for IntoIter<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> { self.list.pop_back() }
|
||||
}
|
||||
@ -753,6 +758,7 @@ impl<A: Ord> Ord for DList<A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<A: Clone> Clone for DList<A> {
|
||||
fn clone(&self) -> DList<A> {
|
||||
self.iter().map(|x| x.clone()).collect()
|
||||
@ -783,14 +789,14 @@ impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::prelude::*;
|
||||
use prelude::*;
|
||||
use std::rand;
|
||||
use std::hash;
|
||||
use std::task::spawn;
|
||||
use test::Bencher;
|
||||
use test;
|
||||
|
||||
use super::{DList, Node, ListInsertion};
|
||||
use vec::Vec;
|
||||
|
||||
pub fn check_links<T>(list: &DList<T>) {
|
||||
let mut len = 0u;
|
||||
@ -926,7 +932,7 @@ mod tests {
|
||||
let mut m = list_from(v.as_slice());
|
||||
m.prepend(list_from(u.as_slice()));
|
||||
check_links(&m);
|
||||
u.extend(v.as_slice().iter().map(|&b| b));
|
||||
u.extend(v.iter().map(|&b| b));
|
||||
assert_eq!(u.len(), m.len());
|
||||
for elt in u.into_iter() {
|
||||
assert_eq!(m.pop_front(), Some(elt))
|
||||
@ -945,7 +951,7 @@ mod tests {
|
||||
let mut m = list_from(v.as_slice());
|
||||
m.rotate_backward(); check_links(&m);
|
||||
m.rotate_forward(); check_links(&m);
|
||||
assert_eq!(v.iter().collect::<Vec<&int>>(), m.iter().collect());
|
||||
assert_eq!(v.iter().collect::<Vec<&int>>(), m.iter().collect::<Vec<_>>());
|
||||
m.rotate_forward(); check_links(&m);
|
||||
m.rotate_forward(); check_links(&m);
|
||||
m.pop_front(); check_links(&m);
|
||||
@ -953,7 +959,7 @@ mod tests {
|
||||
m.rotate_backward(); check_links(&m);
|
||||
m.push_front(9); check_links(&m);
|
||||
m.rotate_forward(); check_links(&m);
|
||||
assert_eq!(vec![3i,9,5,1,2], m.into_iter().collect());
|
||||
assert_eq!(vec![3i,9,5,1,2], m.into_iter().collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1130,10 +1136,10 @@ mod tests {
|
||||
#[test]
|
||||
fn test_send() {
|
||||
let n = list_from(&[1i,2,3]);
|
||||
spawn(proc() {
|
||||
spawn(move || {
|
||||
check_links(&n);
|
||||
let a: &[_] = &[&1,&2,&3];
|
||||
assert_eq!(a, n.iter().collect::<Vec<&int>>().as_slice());
|
||||
assert_eq!(a, n.iter().collect::<Vec<&int>>());
|
||||
});
|
||||
}
|
||||
|
||||
@ -1224,12 +1230,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let list: DList<int> = range(0i, 10).collect();
|
||||
assert!(list.to_string().as_slice() == "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
|
||||
assert!(list.to_string() == "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
|
||||
|
||||
let list: DList<&str> = vec!["just", "one", "test", "more"].iter()
|
||||
.map(|&s| s)
|
||||
.collect();
|
||||
assert!(list.to_string().as_slice() == "[just, one, test, more]");
|
||||
assert!(list.to_string() == "[just, one, test, more]");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -20,13 +20,15 @@ use core::num::Int;
|
||||
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
/// A specialized `Set` implementation to use enum types.
|
||||
/// A specialized set implementation to use enum types.
|
||||
pub struct EnumSet<E> {
|
||||
// We must maintain the invariant that no bits are set
|
||||
// for which no variant exists
|
||||
bits: uint
|
||||
}
|
||||
|
||||
impl<E> Copy for EnumSet<E> {}
|
||||
|
||||
impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(fmt, "{{"));
|
||||
@ -42,27 +44,25 @@ impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
An interface for casting C-like enum to uint and back.
|
||||
A typically implementation is as below.
|
||||
|
||||
```{rust,ignore}
|
||||
#[repr(uint)]
|
||||
enum Foo {
|
||||
A, B, C
|
||||
}
|
||||
|
||||
impl CLike for Foo {
|
||||
fn to_uint(&self) -> uint {
|
||||
*self as uint
|
||||
}
|
||||
|
||||
fn from_uint(v: uint) -> Foo {
|
||||
unsafe { mem::transmute(v) }
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
/// An interface for casting C-like enum to uint and back.
|
||||
/// A typically implementation is as below.
|
||||
///
|
||||
/// ```{rust,ignore}
|
||||
/// #[repr(uint)]
|
||||
/// enum Foo {
|
||||
/// A, B, C
|
||||
/// }
|
||||
///
|
||||
/// impl CLike for Foo {
|
||||
/// fn to_uint(&self) -> uint {
|
||||
/// *self as uint
|
||||
/// }
|
||||
///
|
||||
/// fn from_uint(v: uint) -> Foo {
|
||||
/// unsafe { mem::transmute(v) }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait CLike {
|
||||
/// Converts a C-like enum to a `uint`.
|
||||
fn to_uint(&self) -> uint;
|
||||
@ -178,48 +178,48 @@ impl<E:CLike> EnumSet<E> {
|
||||
|
||||
/// Returns an iterator over an `EnumSet`.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter(&self) -> Items<E> {
|
||||
Items::new(self.bits)
|
||||
pub fn iter(&self) -> Iter<E> {
|
||||
Iter::new(self.bits)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
||||
fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
||||
fn sub(self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits & !e.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
||||
fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
||||
fn bitor(self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits | e.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
||||
fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
||||
fn bitand(self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits & e.bits}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E:CLike> BitXor<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
|
||||
fn bitxor(&self, e: &EnumSet<E>) -> EnumSet<E> {
|
||||
fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
|
||||
EnumSet {bits: self.bits ^ e.bits}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over an EnumSet
|
||||
pub struct Items<E> {
|
||||
pub struct Iter<E> {
|
||||
index: uint,
|
||||
bits: uint,
|
||||
}
|
||||
|
||||
impl<E:CLike> Items<E> {
|
||||
fn new(bits: uint) -> Items<E> {
|
||||
Items { index: 0, bits: bits }
|
||||
impl<E:CLike> Iter<E> {
|
||||
fn new(bits: uint) -> Iter<E> {
|
||||
Iter { index: 0, bits: bits }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E:CLike> Iterator<E> for Items<E> {
|
||||
impl<E:CLike> Iterator<E> for Iter<E> {
|
||||
fn next(&mut self) -> Option<E> {
|
||||
if self.bits == 0 {
|
||||
return None;
|
||||
@ -259,13 +259,13 @@ impl<E:CLike> Extend<E> for EnumSet<E> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::prelude::*;
|
||||
use self::Foo::*;
|
||||
use std::mem;
|
||||
use prelude::*;
|
||||
use core::mem;
|
||||
|
||||
use super::{EnumSet, CLike};
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
#[deriving(Copy, PartialEq, Show)]
|
||||
#[repr(uint)]
|
||||
enum Foo {
|
||||
A, B, C
|
||||
@ -290,11 +290,11 @@ mod test {
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let mut e = EnumSet::new();
|
||||
assert_eq!("{}", e.to_string().as_slice());
|
||||
assert_eq!("{}", e.to_string());
|
||||
e.insert(A);
|
||||
assert_eq!("{A}", e.to_string().as_slice());
|
||||
assert_eq!("{A}", e.to_string());
|
||||
e.insert(C);
|
||||
assert_eq!("{A, C}", e.to_string().as_slice());
|
||||
assert_eq!("{A, C}", e.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -373,7 +373,7 @@ mod test {
|
||||
|
||||
assert!(e1.is_subset(&e2));
|
||||
assert!(e2.is_superset(&e1));
|
||||
assert!(!e3.is_superset(&e2))
|
||||
assert!(!e3.is_superset(&e2));
|
||||
assert!(!e2.is_superset(&e3))
|
||||
}
|
||||
|
||||
@ -399,24 +399,24 @@ mod test {
|
||||
fn test_iterator() {
|
||||
let mut e1: EnumSet<Foo> = EnumSet::new();
|
||||
|
||||
let elems: Vec<Foo> = e1.iter().collect();
|
||||
assert!(elems.is_empty())
|
||||
let elems: ::vec::Vec<Foo> = e1.iter().collect();
|
||||
assert!(elems.is_empty());
|
||||
|
||||
e1.insert(A);
|
||||
let elems = e1.iter().collect();
|
||||
assert_eq!(vec![A], elems)
|
||||
let elems: ::vec::Vec<_> = e1.iter().collect();
|
||||
assert_eq!(vec![A], elems);
|
||||
|
||||
e1.insert(C);
|
||||
let elems = e1.iter().collect();
|
||||
assert_eq!(vec![A,C], elems)
|
||||
let elems: ::vec::Vec<_> = e1.iter().collect();
|
||||
assert_eq!(vec![A,C], elems);
|
||||
|
||||
e1.insert(C);
|
||||
let elems = e1.iter().collect();
|
||||
assert_eq!(vec![A,C], elems)
|
||||
let elems: ::vec::Vec<_> = e1.iter().collect();
|
||||
assert_eq!(vec![A,C], elems);
|
||||
|
||||
e1.insert(B);
|
||||
let elems = e1.iter().collect();
|
||||
assert_eq!(vec![A,B,C], elems)
|
||||
let elems: ::vec::Vec<_> = e1.iter().collect();
|
||||
assert_eq!(vec![A,B,C], elems);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -433,42 +433,43 @@ mod test {
|
||||
e2.insert(C);
|
||||
|
||||
let e_union = e1 | e2;
|
||||
let elems = e_union.iter().collect();
|
||||
assert_eq!(vec![A,B,C], elems)
|
||||
let elems: ::vec::Vec<_> = e_union.iter().collect();
|
||||
assert_eq!(vec![A,B,C], elems);
|
||||
|
||||
let e_intersection = e1 & e2;
|
||||
let elems = e_intersection.iter().collect();
|
||||
assert_eq!(vec![C], elems)
|
||||
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
|
||||
assert_eq!(vec![C], elems);
|
||||
|
||||
// Another way to express intersection
|
||||
let e_intersection = e1 - (e1 - e2);
|
||||
let elems = e_intersection.iter().collect();
|
||||
assert_eq!(vec![C], elems)
|
||||
let elems: ::vec::Vec<_> = e_intersection.iter().collect();
|
||||
assert_eq!(vec![C], elems);
|
||||
|
||||
let e_subtract = e1 - e2;
|
||||
let elems = e_subtract.iter().collect();
|
||||
assert_eq!(vec![A], elems)
|
||||
let elems: ::vec::Vec<_> = e_subtract.iter().collect();
|
||||
assert_eq!(vec![A], elems);
|
||||
|
||||
// Bitwise XOR of two sets, aka symmetric difference
|
||||
let e_symmetric_diff = e1 ^ e2;
|
||||
let elems = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems)
|
||||
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems);
|
||||
|
||||
// Another way to express symmetric difference
|
||||
let e_symmetric_diff = (e1 - e2) | (e2 - e1);
|
||||
let elems = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems)
|
||||
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems);
|
||||
|
||||
// Yet another way to express symmetric difference
|
||||
let e_symmetric_diff = (e1 | e2) - (e1 & e2);
|
||||
let elems = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems)
|
||||
let elems: ::vec::Vec<_> = e_symmetric_diff.iter().collect();
|
||||
assert_eq!(vec![A,B], elems);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_overflow() {
|
||||
#[allow(dead_code)]
|
||||
#[deriving(Copy)]
|
||||
#[repr(uint)]
|
||||
enum Bar {
|
||||
V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
|
||||
@ -479,6 +480,7 @@ mod test {
|
||||
V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
|
||||
V60, V61, V62, V63, V64, V65, V66, V67, V68, V69,
|
||||
}
|
||||
|
||||
impl CLike for Bar {
|
||||
fn to_uint(&self) -> uint {
|
||||
*self as uint
|
||||
|
@ -1,385 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* Generic hashing support.
|
||||
*
|
||||
* This module provides a generic way to compute the hash of a value. The
|
||||
* simplest way to make a type hashable is to use `#[deriving(Hash)]`:
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ```rust
|
||||
* use std::hash;
|
||||
* use std::hash::Hash;
|
||||
*
|
||||
* #[deriving(Hash)]
|
||||
* struct Person {
|
||||
* id: uint,
|
||||
* name: String,
|
||||
* phone: u64,
|
||||
* }
|
||||
*
|
||||
* let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 };
|
||||
* let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 };
|
||||
*
|
||||
* assert!(hash::hash(&person1) != hash::hash(&person2));
|
||||
* ```
|
||||
*
|
||||
* If you need more control over how a value is hashed, you need to implement
|
||||
* the trait `Hash`:
|
||||
*
|
||||
* ```rust
|
||||
* use std::hash;
|
||||
* use std::hash::Hash;
|
||||
* use std::hash::sip::SipState;
|
||||
*
|
||||
* struct Person {
|
||||
* id: uint,
|
||||
* name: String,
|
||||
* phone: u64,
|
||||
* }
|
||||
*
|
||||
* impl Hash for Person {
|
||||
* fn hash(&self, state: &mut SipState) {
|
||||
* self.id.hash(state);
|
||||
* self.phone.hash(state);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 };
|
||||
* let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 };
|
||||
*
|
||||
* assert!(hash::hash(&person1) == hash::hash(&person2));
|
||||
* ```
|
||||
*/
|
||||
|
||||
#![allow(unused_must_use)]
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::intrinsics::TypeId;
|
||||
use core::mem;
|
||||
use core::num::Int;
|
||||
|
||||
use vec::Vec;
|
||||
|
||||
/// Reexport the `sip::hash` function as our default hasher.
|
||||
pub use self::sip::hash as hash;
|
||||
|
||||
pub mod sip;
|
||||
|
||||
/// A hashable type. The `S` type parameter is an abstract hash state that is
|
||||
/// used by the `Hash` to compute the hash. It defaults to
|
||||
/// `std::hash::sip::SipState`.
|
||||
pub trait Hash<S = sip::SipState> for Sized? {
|
||||
/// Computes the hash of a value.
|
||||
fn hash(&self, state: &mut S);
|
||||
}
|
||||
|
||||
/// A trait that computes a hash for a value. The main users of this trait are
|
||||
/// containers like `HashMap`, which need a generic way hash multiple types.
|
||||
pub trait Hasher<S> {
|
||||
/// Compute the hash of a value.
|
||||
fn hash<Sized? T: Hash<S>>(&self, value: &T) -> u64;
|
||||
}
|
||||
|
||||
pub trait Writer {
|
||||
fn write(&mut self, bytes: &[u8]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
macro_rules! impl_hash {
|
||||
($ty:ident, $uty:ident) => {
|
||||
impl<S: Writer> Hash<S> for $ty {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
let a: [u8, ..::core::$ty::BYTES] = unsafe {
|
||||
mem::transmute((*self as $uty).to_le() as $ty)
|
||||
};
|
||||
state.write(a.as_slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_hash!(u8, u8)
|
||||
impl_hash!(u16, u16)
|
||||
impl_hash!(u32, u32)
|
||||
impl_hash!(u64, u64)
|
||||
impl_hash!(uint, uint)
|
||||
impl_hash!(i8, u8)
|
||||
impl_hash!(i16, u16)
|
||||
impl_hash!(i32, u32)
|
||||
impl_hash!(i64, u64)
|
||||
impl_hash!(int, uint)
|
||||
|
||||
impl<S: Writer> Hash<S> for bool {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u8).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for char {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u32).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for str {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(self.as_bytes());
|
||||
0xffu8.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_hash_tuple(
|
||||
() => (
|
||||
impl<S: Writer> Hash<S> for () {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(&[]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
( $($name:ident)+) => (
|
||||
impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) {
|
||||
#[inline]
|
||||
#[allow(non_snake_case)]
|
||||
fn hash(&self, state: &mut S) {
|
||||
match *self {
|
||||
($(ref $name,)*) => {
|
||||
$(
|
||||
$name.hash(state);
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
impl_hash_tuple!()
|
||||
impl_hash_tuple!(A)
|
||||
impl_hash_tuple!(A B)
|
||||
impl_hash_tuple!(A B C)
|
||||
impl_hash_tuple!(A B C D)
|
||||
impl_hash_tuple!(A B C D E)
|
||||
impl_hash_tuple!(A B C D E F)
|
||||
impl_hash_tuple!(A B C D E F G)
|
||||
impl_hash_tuple!(A B C D E F G H)
|
||||
impl_hash_tuple!(A B C D E F G H I)
|
||||
impl_hash_tuple!(A B C D E F G H I J)
|
||||
impl_hash_tuple!(A B C D E F G H I J K)
|
||||
impl_hash_tuple!(A B C D E F G H I J K L)
|
||||
|
||||
impl<S: Writer, T: Hash<S>> Hash<S> for [T] {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.len().hash(state);
|
||||
for elt in self.iter() {
|
||||
elt.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<S: Writer, T: Hash<S>> Hash<S> for Vec<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.as_slice().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: Writer, Sized? T: Hash<S>> Hash<S> for &'a T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: Writer, Sized? T: Hash<S>> Hash<S> for &'a mut T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, Sized? T: Hash<S>> Hash<S> for Box<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (#18248) Make `T` `Sized?`
|
||||
impl<S: Writer, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T: Hash<S>> Hash<S> for Option<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
match *self {
|
||||
Some(ref x) => {
|
||||
0u8.hash(state);
|
||||
x.hash(state);
|
||||
}
|
||||
None => {
|
||||
1u8.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T> Hash<S> for *const T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
// NB: raw-pointer Hash does _not_ dereference
|
||||
// to the target; it just gives you the pointer-bytes.
|
||||
(*self as uint).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T> Hash<S> for *mut T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
// NB: raw-pointer Hash does _not_ dereference
|
||||
// to the target; it just gives you the pointer-bytes.
|
||||
(*self as uint).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for TypeId {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.hash().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T: Hash<S>, U: Hash<S>> Hash<S> for Result<T, U> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
match *self {
|
||||
Ok(ref t) => { 1u.hash(state); t.hash(state); }
|
||||
Err(ref t) => { 2u.hash(state); t.hash(state); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::kinds::Sized;
|
||||
use std::mem;
|
||||
|
||||
use slice::SlicePrelude;
|
||||
use super::{Hash, Hasher, Writer};
|
||||
|
||||
struct MyWriterHasher;
|
||||
|
||||
impl Hasher<MyWriter> for MyWriterHasher {
|
||||
fn hash<Sized? T: Hash<MyWriter>>(&self, value: &T) -> u64 {
|
||||
let mut state = MyWriter { hash: 0 };
|
||||
value.hash(&mut state);
|
||||
state.hash
|
||||
}
|
||||
}
|
||||
|
||||
struct MyWriter {
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
impl Writer for MyWriter {
|
||||
// Most things we'll just add up the bytes.
|
||||
fn write(&mut self, buf: &[u8]) {
|
||||
for byte in buf.iter() {
|
||||
self.hash += *byte as u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_writer_hasher() {
|
||||
use alloc::boxed::Box;
|
||||
|
||||
let hasher = MyWriterHasher;
|
||||
|
||||
assert_eq!(hasher.hash(&()), 0);
|
||||
|
||||
assert_eq!(hasher.hash(&5u8), 5);
|
||||
assert_eq!(hasher.hash(&5u16), 5);
|
||||
assert_eq!(hasher.hash(&5u32), 5);
|
||||
assert_eq!(hasher.hash(&5u64), 5);
|
||||
assert_eq!(hasher.hash(&5u), 5);
|
||||
|
||||
assert_eq!(hasher.hash(&5i8), 5);
|
||||
assert_eq!(hasher.hash(&5i16), 5);
|
||||
assert_eq!(hasher.hash(&5i32), 5);
|
||||
assert_eq!(hasher.hash(&5i64), 5);
|
||||
assert_eq!(hasher.hash(&5i), 5);
|
||||
|
||||
assert_eq!(hasher.hash(&false), 0);
|
||||
assert_eq!(hasher.hash(&true), 1);
|
||||
|
||||
assert_eq!(hasher.hash(&'a'), 97);
|
||||
|
||||
let s: &str = "a";
|
||||
assert_eq!(hasher.hash(& s), 97 + 0xFF);
|
||||
// FIXME (#18283) Enable test
|
||||
//let s: Box<str> = box "a";
|
||||
//assert_eq!(hasher.hash(& s), 97 + 0xFF);
|
||||
let cs: &[u8] = &[1u8, 2u8, 3u8];
|
||||
assert_eq!(hasher.hash(& cs), 9);
|
||||
let cs: Box<[u8]> = box [1u8, 2u8, 3u8];
|
||||
assert_eq!(hasher.hash(& cs), 9);
|
||||
|
||||
// FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]>
|
||||
|
||||
unsafe {
|
||||
let ptr: *const int = mem::transmute(5i);
|
||||
assert_eq!(hasher.hash(&ptr), 5);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr: *mut int = mem::transmute(5i);
|
||||
assert_eq!(hasher.hash(&ptr), 5);
|
||||
}
|
||||
}
|
||||
|
||||
struct Custom {
|
||||
hash: u64
|
||||
}
|
||||
|
||||
impl Hash<u64> for Custom {
|
||||
fn hash(&self, state: &mut u64) {
|
||||
*state = self.hash;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_state() {
|
||||
let custom = Custom { hash: 5 };
|
||||
let mut state = 0;
|
||||
custom.hash(&mut state);
|
||||
assert_eq!(state, 5);
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
#![crate_name = "collections"]
|
||||
#![experimental]
|
||||
#![crate_type = "rlib"]
|
||||
#![license = "MIT/ASL2"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
@ -24,7 +23,8 @@
|
||||
|
||||
#![allow(unknown_features)]
|
||||
#![feature(macro_rules, default_type_params, phase, globs)]
|
||||
#![feature(unsafe_destructor, import_shadowing, slicing_syntax)]
|
||||
#![feature(unsafe_destructor, slicing_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![no_std]
|
||||
|
||||
#[phase(plugin, link)] extern crate core;
|
||||
@ -46,10 +46,6 @@ pub use dlist::DList;
|
||||
pub use enum_set::EnumSet;
|
||||
pub use ring_buf::RingBuf;
|
||||
pub use string::String;
|
||||
pub use tree_map::TreeMap;
|
||||
pub use tree_set::TreeSet;
|
||||
pub use trie_map::TrieMap;
|
||||
pub use trie_set::TrieSet;
|
||||
pub use vec::Vec;
|
||||
pub use vec_map::VecMap;
|
||||
|
||||
@ -61,13 +57,10 @@ mod btree;
|
||||
pub mod dlist;
|
||||
pub mod enum_set;
|
||||
pub mod ring_buf;
|
||||
mod tree;
|
||||
mod trie;
|
||||
pub mod slice;
|
||||
pub mod str;
|
||||
pub mod string;
|
||||
pub mod vec;
|
||||
pub mod hash;
|
||||
pub mod vec_map;
|
||||
|
||||
pub mod bitv {
|
||||
@ -78,22 +71,6 @@ pub mod bitv_set {
|
||||
pub use bit::{BitvSet, BitPositions, TwoBitPositions};
|
||||
}
|
||||
|
||||
pub mod tree_map {
|
||||
pub use tree::map::*;
|
||||
}
|
||||
|
||||
pub mod tree_set {
|
||||
pub use tree::set::*;
|
||||
}
|
||||
|
||||
pub mod trie_map {
|
||||
pub use trie::map::*;
|
||||
}
|
||||
|
||||
pub mod trie_set {
|
||||
pub use trie::set::*;
|
||||
}
|
||||
|
||||
pub mod btree_map {
|
||||
pub use btree::map::*;
|
||||
}
|
||||
@ -115,5 +92,44 @@ mod std {
|
||||
pub use core::option; // necessary for panic!()
|
||||
pub use core::clone; // deriving(Clone)
|
||||
pub use core::cmp; // deriving(Eq, Ord, etc.)
|
||||
pub use hash; // deriving(Hash)
|
||||
pub use core::kinds; // deriving(Copy)
|
||||
pub use core::hash; // deriving(Hash)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod prelude {
|
||||
// from core.
|
||||
pub use core::borrow::IntoCow;
|
||||
pub use core::char::Char;
|
||||
pub use core::clone::Clone;
|
||||
pub use core::cmp::{PartialEq, Eq, Equiv, PartialOrd, Ord};
|
||||
pub use core::cmp::Ordering::{Less, Equal, Greater};
|
||||
pub use core::iter::range;
|
||||
pub use core::iter::{FromIterator, Extend, IteratorExt};
|
||||
pub use core::iter::{Iterator, DoubleEndedIterator, RandomAccessIterator};
|
||||
pub use core::iter::{IteratorCloneExt, CloneIteratorExt, DoubleEndedIteratorExt};
|
||||
pub use core::iter::{IteratorOrdExt, MutableDoubleEndedIterator, ExactSizeIterator};
|
||||
pub use core::kinds::{Copy, Send, Sized, Sync};
|
||||
pub use core::mem::drop;
|
||||
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::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};
|
||||
|
||||
// from other crates.
|
||||
pub use alloc::boxed::Box;
|
||||
pub use unicode::char::UnicodeChar;
|
||||
|
||||
// from collections.
|
||||
pub use slice::{CloneSliceExt, VectorVector};
|
||||
pub use str::{IntoMaybeOwned, StrVector};
|
||||
pub use string::{String, ToString};
|
||||
pub use vec::Vec;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#![macro_escape]
|
||||
|
||||
/// Creates a `std::vec::Vec` containing the arguments.
|
||||
macro_rules! vec(
|
||||
macro_rules! vec {
|
||||
($($e:expr),*) => ({
|
||||
// leading _ to allow empty construction without a warning.
|
||||
let mut _temp = ::vec::Vec::new();
|
||||
@ -19,4 +19,5 @@ macro_rules! vec(
|
||||
_temp
|
||||
});
|
||||
($($e:expr),+,) => (vec!($($e),+))
|
||||
)
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Maps are collections of unique keys with corresponding values, and sets are
|
||||
//! just unique keys without a corresponding value. The `Map` and `Set` traits in
|
||||
//! `std::container` define the basic interface.
|
||||
//!
|
||||
//! This crate defines the `TreeMap` and `TreeSet` types. Their keys must implement `Ord`.
|
||||
//!
|
||||
//! `TreeMap`s are ordered.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```{rust}
|
||||
//! use std::collections::TreeSet;
|
||||
//!
|
||||
//! let mut tree_set = TreeSet::new();
|
||||
//!
|
||||
//! tree_set.insert(2i);
|
||||
//! tree_set.insert(1i);
|
||||
//! tree_set.insert(3i);
|
||||
//!
|
||||
//! for i in tree_set.iter() {
|
||||
//! println!("{}", i) // prints 1, then 2, then 3
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
pub mod map;
|
||||
pub mod set;
|
@ -1,985 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use core::borrow::BorrowFrom;
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::fmt::Show;
|
||||
use core::iter::Peekable;
|
||||
use core::iter;
|
||||
use std::hash::{Writer, Hash};
|
||||
|
||||
use tree_map::{TreeMap, Entries, RevEntries, MoveEntries};
|
||||
|
||||
// FIXME(conventions): implement bounded iterators
|
||||
// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub
|
||||
// FIXME(conventions): replace rev_iter(_mut) by making iter(_mut) DoubleEnded
|
||||
|
||||
/// An implementation of the `Set` trait on top of the `TreeMap` container. The
|
||||
/// only requirement is that the type of the elements contained ascribes to the
|
||||
/// `Ord` trait.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```{rust}
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut set = TreeSet::new();
|
||||
///
|
||||
/// set.insert(2i);
|
||||
/// set.insert(1i);
|
||||
/// set.insert(3i);
|
||||
///
|
||||
/// for i in set.iter() {
|
||||
/// println!("{}", i) // prints 1, then 2, then 3
|
||||
/// }
|
||||
///
|
||||
/// set.remove(&3);
|
||||
///
|
||||
/// if !set.contains(&3) {
|
||||
/// println!("set does not contain a 3 anymore");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The easiest way to use `TreeSet` with a custom type is to implement `Ord`.
|
||||
/// We must also implement `PartialEq`, `Eq` and `PartialOrd`.
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// // We need `Eq` and `PartialEq`, these can be derived.
|
||||
/// #[deriving(Eq, PartialEq)]
|
||||
/// struct Troll<'a> {
|
||||
/// name: &'a str,
|
||||
/// level: uint,
|
||||
/// }
|
||||
///
|
||||
/// // Implement `Ord` and sort trolls by level.
|
||||
/// impl<'a> Ord for Troll<'a> {
|
||||
/// fn cmp(&self, other: &Troll) -> Ordering {
|
||||
/// // If we swap `self` and `other`, we get descending ordering.
|
||||
/// self.level.cmp(&other.level)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // `PartialOrd` needs to be implemented as well.
|
||||
/// impl<'a> PartialOrd for Troll<'a> {
|
||||
/// fn partial_cmp(&self, other: &Troll) -> Option<Ordering> {
|
||||
/// Some(self.cmp(other))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut trolls = TreeSet::new();
|
||||
///
|
||||
/// trolls.insert(Troll { name: "Orgarr", level: 2 });
|
||||
/// trolls.insert(Troll { name: "Blargarr", level: 3 });
|
||||
/// trolls.insert(Troll { name: "Kron the Smelly One", level: 4 });
|
||||
/// trolls.insert(Troll { name: "Wartilda", level: 1 });
|
||||
///
|
||||
/// println!("You are facing {} trolls!", trolls.len());
|
||||
///
|
||||
/// // Print the trolls, ordered by level with smallest level first
|
||||
/// for x in trolls.iter() {
|
||||
/// println!("level {}: {}!", x.level, x.name);
|
||||
/// }
|
||||
///
|
||||
/// // Kill all trolls
|
||||
/// trolls.clear();
|
||||
/// assert_eq!(trolls.len(), 0);
|
||||
/// ```
|
||||
#[deriving(Clone)]
|
||||
pub struct TreeSet<T> {
|
||||
map: TreeMap<T, ()>
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Ord> PartialEq for TreeSet<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &TreeSet<T>) -> bool { self.map == other.map }
|
||||
}
|
||||
|
||||
impl<T: Eq + Ord> Eq for TreeSet<T> {}
|
||||
|
||||
impl<T: Ord> PartialOrd for TreeSet<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &TreeSet<T>) -> Option<Ordering> {
|
||||
self.map.partial_cmp(&other.map)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> Ord for TreeSet<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &TreeSet<T>) -> Ordering {
|
||||
iter::order::cmp(self.iter(), other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord + Show> Show for TreeSet<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{{"));
|
||||
|
||||
for (i, x) in self.iter().enumerate() {
|
||||
if i != 0 { try!(write!(f, ", ")); }
|
||||
try!(write!(f, "{}", *x));
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> Default for TreeSet<T> {
|
||||
#[inline]
|
||||
fn default() -> TreeSet<T> { TreeSet::new() }
|
||||
}
|
||||
|
||||
impl<T: Ord> TreeSet<T> {
|
||||
/// Creates an empty `TreeSet`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let mut set: TreeSet<int> = TreeSet::new();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> TreeSet<T> { TreeSet{map: TreeMap::new()} }
|
||||
|
||||
/// Gets a lazy iterator over the values in the set, in ascending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let set: TreeSet<int> = [1i, 4, 3, 5, 2].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Will print in ascending order.
|
||||
/// for x in set.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> SetItems<'a, T> {
|
||||
SetItems{iter: self.map.iter()}
|
||||
}
|
||||
|
||||
/// Gets a lazy iterator over the values in the set, in descending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let set: TreeSet<int> = [1i, 4, 3, 5, 2].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Will print in descending order.
|
||||
/// for x in set.rev_iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn rev_iter<'a>(&'a self) -> RevSetItems<'a, T> {
|
||||
RevSetItems{iter: self.map.rev_iter()}
|
||||
}
|
||||
|
||||
/// Creates a consuming iterator, that is, one that moves each value out of the
|
||||
/// set in ascending order. The set cannot be used after calling this.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let set: TreeSet<int> = [1i, 4, 3, 5, 2].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Not possible with a regular `.iter()`
|
||||
/// let v: Vec<int> = set.into_iter().collect();
|
||||
/// assert_eq!(v, vec![1, 2, 3, 4, 5]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn into_iter(self) -> MoveSetItems<T> {
|
||||
self.map.into_iter().map(|(value, _)| value)
|
||||
}
|
||||
|
||||
/// Gets a lazy iterator pointing to the first value not less than `v` (greater or equal).
|
||||
/// If all elements in the set are less than `v` empty iterator is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let set: TreeSet<int> = [2, 4, 6, 8].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// assert_eq!(set.lower_bound(&4).next(), Some(&4));
|
||||
/// assert_eq!(set.lower_bound(&5).next(), Some(&6));
|
||||
/// assert_eq!(set.lower_bound(&10).next(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lower_bound<'a>(&'a self, v: &T) -> SetItems<'a, T> {
|
||||
SetItems{iter: self.map.lower_bound(v)}
|
||||
}
|
||||
|
||||
/// Gets a lazy iterator pointing to the first value greater than `v`.
|
||||
/// If all elements in the set are less than or equal to `v` an
|
||||
/// empty iterator is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
/// let set: TreeSet<int> = [2, 4, 6, 8].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// assert_eq!(set.upper_bound(&4).next(), Some(&6));
|
||||
/// assert_eq!(set.upper_bound(&5).next(), Some(&6));
|
||||
/// assert_eq!(set.upper_bound(&10).next(), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn upper_bound<'a>(&'a self, v: &T) -> SetItems<'a, T> {
|
||||
SetItems{iter: self.map.upper_bound(v)}
|
||||
}
|
||||
|
||||
/// Visits the values representing the difference, in ascending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let a: TreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let b: TreeSet<int> = [3, 4, 5].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Can be seen as `a - b`.
|
||||
/// for x in a.difference(&b) {
|
||||
/// println!("{}", x); // Print 1 then 2
|
||||
/// }
|
||||
///
|
||||
/// let diff: TreeSet<int> = a.difference(&b).map(|&x| x).collect();
|
||||
/// assert_eq!(diff, [1, 2].iter().map(|&x| x).collect());
|
||||
///
|
||||
/// // Note that difference is not symmetric,
|
||||
/// // and `b - a` means something else:
|
||||
/// let diff: TreeSet<int> = b.difference(&a).map(|&x| x).collect();
|
||||
/// assert_eq!(diff, [4, 5].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn difference<'a>(&'a self, other: &'a TreeSet<T>) -> DifferenceItems<'a, T> {
|
||||
DifferenceItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the symmetric difference, in ascending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let a: TreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let b: TreeSet<int> = [3, 4, 5].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Print 1, 2, 4, 5 in ascending order.
|
||||
/// for x in a.symmetric_difference(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let diff1: TreeSet<int> = a.symmetric_difference(&b).map(|&x| x).collect();
|
||||
/// let diff2: TreeSet<int> = b.symmetric_difference(&a).map(|&x| x).collect();
|
||||
///
|
||||
/// assert_eq!(diff1, diff2);
|
||||
/// assert_eq!(diff1, [1, 2, 4, 5].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet<T>)
|
||||
-> SymDifferenceItems<'a, T> {
|
||||
SymDifferenceItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the intersection, in ascending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let a: TreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let b: TreeSet<int> = [2, 3, 4].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Print 2, 3 in ascending order.
|
||||
/// for x in a.intersection(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let diff: TreeSet<int> = a.intersection(&b).map(|&x| x).collect();
|
||||
/// assert_eq!(diff, [2, 3].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn intersection<'a>(&'a self, other: &'a TreeSet<T>)
|
||||
-> IntersectionItems<'a, T> {
|
||||
IntersectionItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Visits the values representing the union, in ascending order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let a: TreeSet<int> = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let b: TreeSet<int> = [3, 4, 5].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// // Print 1, 2, 3, 4, 5 in ascending order.
|
||||
/// for x in a.union(&b) {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// let diff: TreeSet<int> = a.union(&b).map(|&x| x).collect();
|
||||
/// assert_eq!(diff, [1, 2, 3, 4, 5].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn union<'a>(&'a self, other: &'a TreeSet<T>) -> UnionItems<'a, T> {
|
||||
UnionItems{a: self.iter().peekable(), b: other.iter().peekable()}
|
||||
}
|
||||
|
||||
/// Return the number of elements in the set
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut v = TreeSet::new();
|
||||
/// assert_eq!(v.len(), 0);
|
||||
/// v.insert(1i);
|
||||
/// assert_eq!(v.len(), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn len(&self) -> uint { self.map.len() }
|
||||
|
||||
/// Returns true if the set contains no elements
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut v = TreeSet::new();
|
||||
/// assert!(v.is_empty());
|
||||
/// v.insert(1i);
|
||||
/// assert!(!v.is_empty());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Clears the set, removing all values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut v = TreeSet::new();
|
||||
/// v.insert(1i);
|
||||
/// v.clear();
|
||||
/// assert!(v.is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn clear(&mut self) { self.map.clear() }
|
||||
|
||||
/// Returns `true` if the set contains a value.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type,
|
||||
/// but the ordering on the borrowed form *must* match the
|
||||
/// ordering on the value type.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let set: TreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
|
||||
/// assert_eq!(set.contains(&1), true);
|
||||
/// assert_eq!(set.contains(&4), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn contains<Sized? Q>(&self, value: &Q) -> bool
|
||||
where Q: Ord + BorrowFrom<T>
|
||||
{
|
||||
self.map.contains_key(value)
|
||||
}
|
||||
|
||||
/// Returns `true` if the set has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let a: TreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let mut b: TreeSet<int> = TreeSet::new();
|
||||
///
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(4);
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(1);
|
||||
/// assert_eq!(a.is_disjoint(&b), false);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_disjoint(&self, other: &TreeSet<T>) -> bool {
|
||||
self.intersection(other).next().is_none()
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a subset of another.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let sup: TreeSet<int> = [1i, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let mut set: TreeSet<int> = TreeSet::new();
|
||||
///
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(2);
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(4);
|
||||
/// assert_eq!(set.is_subset(&sup), false);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_subset(&self, other: &TreeSet<T>) -> bool {
|
||||
let mut x = self.iter();
|
||||
let mut y = other.iter();
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
while a.is_some() {
|
||||
if b.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let a1 = a.unwrap();
|
||||
let b1 = b.unwrap();
|
||||
|
||||
match b1.cmp(a1) {
|
||||
Less => (),
|
||||
Greater => return false,
|
||||
Equal => a = x.next(),
|
||||
}
|
||||
|
||||
b = y.next();
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a superset of another.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let sub: TreeSet<int> = [1i, 2].iter().map(|&x| x).collect();
|
||||
/// let mut set: TreeSet<int> = TreeSet::new();
|
||||
///
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(0);
|
||||
/// set.insert(1);
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(2);
|
||||
/// assert_eq!(set.is_superset(&sub), true);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_superset(&self, other: &TreeSet<T>) -> bool {
|
||||
other.is_subset(self)
|
||||
}
|
||||
|
||||
/// Adds a value to the set. Returns `true` if the value was not already
|
||||
/// present in the set.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut set = TreeSet::new();
|
||||
///
|
||||
/// assert_eq!(set.insert(2i), true);
|
||||
/// assert_eq!(set.insert(2i), false);
|
||||
/// assert_eq!(set.len(), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()).is_none() }
|
||||
|
||||
/// Removes a value from the set. Returns `true` if the value was
|
||||
/// present in the set.
|
||||
///
|
||||
/// The value may be any borrowed form of the set's value type,
|
||||
/// but the ordering on the borrowed form *must* match the
|
||||
/// ordering on the value type.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TreeSet;
|
||||
///
|
||||
/// let mut set = TreeSet::new();
|
||||
///
|
||||
/// set.insert(2i);
|
||||
/// assert_eq!(set.remove(&2), true);
|
||||
/// assert_eq!(set.remove(&2), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn remove<Sized? Q>(&mut self, value: &Q) -> bool
|
||||
where Q: Ord + BorrowFrom<T>
|
||||
{
|
||||
self.map.remove(value).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a set.
|
||||
pub struct SetItems<'a, T:'a> {
|
||||
iter: Entries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// A lazy backward iterator over a set.
|
||||
pub struct RevSetItems<'a, T:'a> {
|
||||
iter: RevEntries<'a, T, ()>
|
||||
}
|
||||
|
||||
/// A lazy forward iterator over a set that consumes the set while iterating.
|
||||
pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
|
||||
|
||||
/// A lazy iterator producing elements in the set difference (in-order).
|
||||
pub struct DifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set symmetric difference (in-order).
|
||||
pub struct SymDifferenceItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set intersection (in-order).
|
||||
pub struct IntersectionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// A lazy iterator producing elements in the set union (in-order).
|
||||
pub struct UnionItems<'a, T:'a> {
|
||||
a: Peekable<&'a T, SetItems<'a, T>>,
|
||||
b: Peekable<&'a T, SetItems<'a, T>>,
|
||||
}
|
||||
|
||||
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
|
||||
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>,
|
||||
short: Ordering, long: Ordering) -> Ordering {
|
||||
match (x, y) {
|
||||
(None , _ ) => short,
|
||||
(_ , None ) => long,
|
||||
(Some(x1), Some(y1)) => x1.cmp(y1),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for SetItems<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
self.iter.next().map(|(value, _)| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator<&'a T> for RevSetItems<'a, T> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
self.iter.next().map(|(value, _)| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for DifferenceItems<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) {
|
||||
Less => return self.a.next(),
|
||||
Equal => { self.a.next(); self.b.next(); }
|
||||
Greater => { self.b.next(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for SymDifferenceItems<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
|
||||
Less => return self.a.next(),
|
||||
Equal => { self.a.next(); self.b.next(); }
|
||||
Greater => return self.b.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for IntersectionItems<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
let o_cmp = match (self.a.peek(), self.b.peek()) {
|
||||
(None , _ ) => None,
|
||||
(_ , None ) => None,
|
||||
(Some(a1), Some(b1)) => Some(a1.cmp(b1)),
|
||||
};
|
||||
match o_cmp {
|
||||
None => return None,
|
||||
Some(Less) => { self.a.next(); }
|
||||
Some(Equal) => { self.b.next(); return self.a.next() }
|
||||
Some(Greater) => { self.b.next(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> Iterator<&'a T> for UnionItems<'a, T> {
|
||||
fn next(&mut self) -> Option<&'a T> {
|
||||
loop {
|
||||
match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
|
||||
Less => return self.a.next(),
|
||||
Equal => { self.b.next(); return self.a.next() }
|
||||
Greater => return self.b.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> FromIterator<T> for TreeSet<T> {
|
||||
fn from_iter<Iter: Iterator<T>>(iter: Iter) -> TreeSet<T> {
|
||||
let mut set = TreeSet::new();
|
||||
set.extend(iter);
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord> Extend<T> for TreeSet<T> {
|
||||
#[inline]
|
||||
fn extend<Iter: Iterator<T>>(&mut self, mut iter: Iter) {
|
||||
for elem in iter {
|
||||
self.insert(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T: Ord + Hash<S>> Hash<S> for TreeSet<T> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
for elt in self.iter() {
|
||||
elt.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::prelude::*;
|
||||
use std::hash;
|
||||
|
||||
use super::TreeSet;
|
||||
|
||||
#[test]
|
||||
fn test_clear() {
|
||||
let mut s = TreeSet::new();
|
||||
s.clear();
|
||||
assert!(s.insert(5i));
|
||||
assert!(s.insert(12));
|
||||
assert!(s.insert(19));
|
||||
s.clear();
|
||||
assert!(!s.contains(&5));
|
||||
assert!(!s.contains(&12));
|
||||
assert!(!s.contains(&19));
|
||||
assert!(s.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_disjoint() {
|
||||
let mut xs = TreeSet::new();
|
||||
let mut ys = TreeSet::new();
|
||||
assert!(xs.is_disjoint(&ys));
|
||||
assert!(ys.is_disjoint(&xs));
|
||||
assert!(xs.insert(5i));
|
||||
assert!(ys.insert(11i));
|
||||
assert!(xs.is_disjoint(&ys));
|
||||
assert!(ys.is_disjoint(&xs));
|
||||
assert!(xs.insert(7));
|
||||
assert!(xs.insert(19));
|
||||
assert!(xs.insert(4));
|
||||
assert!(ys.insert(2));
|
||||
assert!(ys.insert(-11));
|
||||
assert!(xs.is_disjoint(&ys));
|
||||
assert!(ys.is_disjoint(&xs));
|
||||
assert!(ys.insert(7));
|
||||
assert!(!xs.is_disjoint(&ys));
|
||||
assert!(!ys.is_disjoint(&xs));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subset_and_superset() {
|
||||
let mut a = TreeSet::new();
|
||||
assert!(a.insert(0i));
|
||||
assert!(a.insert(5));
|
||||
assert!(a.insert(11));
|
||||
assert!(a.insert(7));
|
||||
|
||||
let mut b = TreeSet::new();
|
||||
assert!(b.insert(0i));
|
||||
assert!(b.insert(7));
|
||||
assert!(b.insert(19));
|
||||
assert!(b.insert(250));
|
||||
assert!(b.insert(11));
|
||||
assert!(b.insert(200));
|
||||
|
||||
assert!(!a.is_subset(&b));
|
||||
assert!(!a.is_superset(&b));
|
||||
assert!(!b.is_subset(&a));
|
||||
assert!(!b.is_superset(&a));
|
||||
|
||||
assert!(b.insert(5));
|
||||
|
||||
assert!(a.is_subset(&b));
|
||||
assert!(!a.is_superset(&b));
|
||||
assert!(!b.is_subset(&a));
|
||||
assert!(b.is_superset(&a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator() {
|
||||
let mut m = TreeSet::new();
|
||||
|
||||
assert!(m.insert(3i));
|
||||
assert!(m.insert(0));
|
||||
assert!(m.insert(4));
|
||||
assert!(m.insert(2));
|
||||
assert!(m.insert(1));
|
||||
|
||||
let mut n = 0;
|
||||
for x in m.iter() {
|
||||
assert_eq!(*x, n);
|
||||
n += 1
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rev_iter() {
|
||||
let mut m = TreeSet::new();
|
||||
|
||||
assert!(m.insert(3i));
|
||||
assert!(m.insert(0));
|
||||
assert!(m.insert(4));
|
||||
assert!(m.insert(2));
|
||||
assert!(m.insert(1));
|
||||
|
||||
let mut n = 4;
|
||||
for x in m.rev_iter() {
|
||||
assert_eq!(*x, n);
|
||||
n -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter() {
|
||||
let s: TreeSet<int> = range(0i, 5).collect();
|
||||
|
||||
let mut n = 0;
|
||||
for x in s.into_iter() {
|
||||
assert_eq!(x, n);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_iter_size_hint() {
|
||||
let s: TreeSet<int> = vec!(0i, 1).into_iter().collect();
|
||||
|
||||
let mut it = s.into_iter();
|
||||
|
||||
assert_eq!(it.size_hint(), (2, Some(2)));
|
||||
assert!(it.next() != None);
|
||||
|
||||
assert_eq!(it.size_hint(), (1, Some(1)));
|
||||
assert!(it.next() != None);
|
||||
|
||||
assert_eq!(it.size_hint(), (0, Some(0)));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_eq() {
|
||||
let mut m = TreeSet::new();
|
||||
|
||||
m.insert(1i);
|
||||
m.insert(2);
|
||||
|
||||
assert!(m.clone() == m);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
let mut x = TreeSet::new();
|
||||
let mut y = TreeSet::new();
|
||||
|
||||
x.insert(1i);
|
||||
x.insert(2);
|
||||
x.insert(3);
|
||||
|
||||
y.insert(3i);
|
||||
y.insert(2);
|
||||
y.insert(1);
|
||||
|
||||
assert!(hash::hash(&x) == hash::hash(&y));
|
||||
}
|
||||
|
||||
fn check(a: &[int],
|
||||
b: &[int],
|
||||
expected: &[int],
|
||||
f: |&TreeSet<int>, &TreeSet<int>, f: |&int| -> bool| -> bool) {
|
||||
let mut set_a = TreeSet::new();
|
||||
let mut set_b = TreeSet::new();
|
||||
|
||||
for x in a.iter() { assert!(set_a.insert(*x)) }
|
||||
for y in b.iter() { assert!(set_b.insert(*y)) }
|
||||
|
||||
let mut i = 0;
|
||||
f(&set_a, &set_b, |x| {
|
||||
assert_eq!(*x, expected[i]);
|
||||
i += 1;
|
||||
true
|
||||
});
|
||||
assert_eq!(i, expected.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intersection() {
|
||||
fn check_intersection(a: &[int], b: &[int], expected: &[int]) {
|
||||
check(a, b, expected, |x, y, f| x.intersection(y).all(f))
|
||||
}
|
||||
|
||||
check_intersection(&[], &[], &[]);
|
||||
check_intersection(&[1, 2, 3], &[], &[]);
|
||||
check_intersection(&[], &[1, 2, 3], &[]);
|
||||
check_intersection(&[2], &[1, 2, 3], &[2]);
|
||||
check_intersection(&[1, 2, 3], &[2], &[2]);
|
||||
check_intersection(&[11, 1, 3, 77, 103, 5, -5],
|
||||
&[2, 11, 77, -9, -42, 5, 3],
|
||||
&[3, 5, 11, 77]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_difference() {
|
||||
fn check_difference(a: &[int], b: &[int], expected: &[int]) {
|
||||
check(a, b, expected, |x, y, f| x.difference(y).all(f))
|
||||
}
|
||||
|
||||
check_difference(&[], &[], &[]);
|
||||
check_difference(&[1, 12], &[], &[1, 12]);
|
||||
check_difference(&[], &[1, 2, 3, 9], &[]);
|
||||
check_difference(&[1, 3, 5, 9, 11],
|
||||
&[3, 9],
|
||||
&[1, 5, 11]);
|
||||
check_difference(&[-5, 11, 22, 33, 40, 42],
|
||||
&[-12, -5, 14, 23, 34, 38, 39, 50],
|
||||
&[11, 22, 33, 40, 42]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symmetric_difference() {
|
||||
fn check_symmetric_difference(a: &[int], b: &[int],
|
||||
expected: &[int]) {
|
||||
check(a, b, expected, |x, y, f| x.symmetric_difference(y).all(f))
|
||||
}
|
||||
|
||||
check_symmetric_difference(&[], &[], &[]);
|
||||
check_symmetric_difference(&[1, 2, 3], &[2], &[1, 3]);
|
||||
check_symmetric_difference(&[2], &[1, 2, 3], &[1, 3]);
|
||||
check_symmetric_difference(&[1, 3, 5, 9, 11],
|
||||
&[-2, 3, 9, 14, 22],
|
||||
&[-2, 1, 5, 11, 14, 22]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_union() {
|
||||
fn check_union(a: &[int], b: &[int],
|
||||
expected: &[int]) {
|
||||
check(a, b, expected, |x, y, f| x.union(y).all(f))
|
||||
}
|
||||
|
||||
check_union(&[], &[], &[]);
|
||||
check_union(&[1, 2, 3], &[2], &[1, 2, 3]);
|
||||
check_union(&[2], &[1, 2, 3], &[1, 2, 3]);
|
||||
check_union(&[1, 3, 5, 9, 11, 16, 19, 24],
|
||||
&[-2, 1, 5, 9, 13, 19],
|
||||
&[-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zip() {
|
||||
let mut x = TreeSet::new();
|
||||
x.insert(5u);
|
||||
x.insert(12u);
|
||||
x.insert(11u);
|
||||
|
||||
let mut y = TreeSet::new();
|
||||
y.insert("foo");
|
||||
y.insert("bar");
|
||||
|
||||
let x = x;
|
||||
let y = y;
|
||||
let mut z = x.iter().zip(y.iter());
|
||||
|
||||
// FIXME: #5801: this needs a type hint to compile...
|
||||
let result: Option<(&uint, & &'static str)> = z.next();
|
||||
assert_eq!(result.unwrap(), (&5u, &("bar")));
|
||||
|
||||
let result: Option<(&uint, & &'static str)> = z.next();
|
||||
assert_eq!(result.unwrap(), (&11u, &("foo")));
|
||||
|
||||
let result: Option<(&uint, & &'static str)> = z.next();
|
||||
assert!(result.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = [1i, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
|
||||
let set: TreeSet<int> = xs.iter().map(|&x| x).collect();
|
||||
|
||||
for x in xs.iter() {
|
||||
assert!(set.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let mut set: TreeSet<int> = TreeSet::new();
|
||||
let empty: TreeSet<int> = TreeSet::new();
|
||||
|
||||
set.insert(1);
|
||||
set.insert(2);
|
||||
|
||||
let set_str = format!("{}", set);
|
||||
|
||||
assert!(set_str == "{1, 2}".to_string());
|
||||
assert_eq!(format!("{}", empty), "{}".to_string());
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,20 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Maps are collections of unique keys with corresponding values, and sets are
|
||||
//! just unique keys without a corresponding value. The `Map` and `Set` traits in
|
||||
//! `std::container` define the basic interface.
|
||||
//!
|
||||
//! This crate defines `TrieMap` and `TrieSet`, which require `uint` keys.
|
||||
//!
|
||||
//! `TrieMap` is ordered.
|
||||
|
||||
pub mod map;
|
||||
pub mod set;
|
@ -1,474 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME(conventions): implement bounded iterators
|
||||
// FIXME(conventions): implement union family of fns
|
||||
// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub
|
||||
// FIXME(conventions): replace each_reverse by making iter DoubleEnded
|
||||
// FIXME(conventions): implement iter_mut and into_iter
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::fmt::Show;
|
||||
use std::hash::Hash;
|
||||
|
||||
use trie_map::{TrieMap, Entries};
|
||||
|
||||
/// A set implemented as a radix trie.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut set = TrieSet::new();
|
||||
/// set.insert(6);
|
||||
/// set.insert(28);
|
||||
/// set.insert(6);
|
||||
///
|
||||
/// assert_eq!(set.len(), 2);
|
||||
///
|
||||
/// if !set.contains(&3) {
|
||||
/// println!("3 is not in the set");
|
||||
/// }
|
||||
///
|
||||
/// // Print contents in order
|
||||
/// for x in set.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
///
|
||||
/// set.remove(&6);
|
||||
/// assert_eq!(set.len(), 1);
|
||||
///
|
||||
/// set.clear();
|
||||
/// assert!(set.is_empty());
|
||||
/// ```
|
||||
#[deriving(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct TrieSet {
|
||||
map: TrieMap<()>
|
||||
}
|
||||
|
||||
impl Show for TrieSet {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{{"));
|
||||
|
||||
for (i, x) in self.iter().enumerate() {
|
||||
if i != 0 { try!(write!(f, ", ")); }
|
||||
try!(write!(f, "{}", x));
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TrieSet {
|
||||
#[inline]
|
||||
fn default() -> TrieSet { TrieSet::new() }
|
||||
}
|
||||
|
||||
impl TrieSet {
|
||||
/// Creates an empty TrieSet.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
/// let mut set = TrieSet::new();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> TrieSet {
|
||||
TrieSet{map: TrieMap::new()}
|
||||
}
|
||||
|
||||
/// Visits all values in reverse order. Aborts traversal when `f` returns `false`.
|
||||
/// Returns `true` if `f` returns `true` for all elements.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let set: TrieSet = [1, 2, 3, 4, 5].iter().map(|&x| x).collect();
|
||||
///
|
||||
/// let mut vec = Vec::new();
|
||||
/// assert_eq!(true, set.each_reverse(|&x| { vec.push(x); true }));
|
||||
/// assert_eq!(vec, vec![5, 4, 3, 2, 1]);
|
||||
///
|
||||
/// // Stop when we reach 3
|
||||
/// let mut vec = Vec::new();
|
||||
/// assert_eq!(false, set.each_reverse(|&x| { vec.push(x); x != 3 }));
|
||||
/// assert_eq!(vec, vec![5, 4, 3]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn each_reverse(&self, f: |&uint| -> bool) -> bool {
|
||||
self.map.each_reverse(|k, _| f(k))
|
||||
}
|
||||
|
||||
/// Gets an iterator over the values in the set, in sorted order.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut set = TrieSet::new();
|
||||
/// set.insert(3);
|
||||
/// set.insert(2);
|
||||
/// set.insert(1);
|
||||
/// set.insert(2);
|
||||
///
|
||||
/// // Print 1, 2, 3
|
||||
/// for x in set.iter() {
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'a>(&'a self) -> SetItems<'a> {
|
||||
SetItems{iter: self.map.iter()}
|
||||
}
|
||||
|
||||
/// Gets an iterator pointing to the first value that is not less than `val`.
|
||||
/// If all values in the set are less than `val` an empty iterator is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let set: TrieSet = [2, 4, 6, 8].iter().map(|&x| x).collect();
|
||||
/// assert_eq!(set.lower_bound(4).next(), Some(4));
|
||||
/// assert_eq!(set.lower_bound(5).next(), Some(6));
|
||||
/// assert_eq!(set.lower_bound(10).next(), None);
|
||||
/// ```
|
||||
pub fn lower_bound<'a>(&'a self, val: uint) -> SetItems<'a> {
|
||||
SetItems{iter: self.map.lower_bound(val)}
|
||||
}
|
||||
|
||||
/// Gets an iterator pointing to the first value that key is greater than `val`.
|
||||
/// If all values in the set are less than or equal to `val` an empty iterator is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let set: TrieSet = [2, 4, 6, 8].iter().map(|&x| x).collect();
|
||||
/// assert_eq!(set.upper_bound(4).next(), Some(6));
|
||||
/// assert_eq!(set.upper_bound(5).next(), Some(6));
|
||||
/// assert_eq!(set.upper_bound(10).next(), None);
|
||||
/// ```
|
||||
pub fn upper_bound<'a>(&'a self, val: uint) -> SetItems<'a> {
|
||||
SetItems{iter: self.map.upper_bound(val)}
|
||||
}
|
||||
|
||||
/// Return the number of elements in the set
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut v = TrieSet::new();
|
||||
/// assert_eq!(v.len(), 0);
|
||||
/// v.insert(1);
|
||||
/// assert_eq!(v.len(), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn len(&self) -> uint { self.map.len() }
|
||||
|
||||
/// Returns true if the set contains no elements
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut v = TrieSet::new();
|
||||
/// assert!(v.is_empty());
|
||||
/// v.insert(1);
|
||||
/// assert!(!v.is_empty());
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Clears the set, removing all values.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut v = TrieSet::new();
|
||||
/// v.insert(1);
|
||||
/// v.clear();
|
||||
/// assert!(v.is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn clear(&mut self) { self.map.clear() }
|
||||
|
||||
/// Returns `true` if the set contains a value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let set: TrieSet = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// assert_eq!(set.contains(&1), true);
|
||||
/// assert_eq!(set.contains(&4), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn contains(&self, value: &uint) -> bool {
|
||||
self.map.contains_key(value)
|
||||
}
|
||||
|
||||
/// Returns `true` if the set has no elements in common with `other`.
|
||||
/// This is equivalent to checking for an empty intersection.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let a: TrieSet = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let mut b: TrieSet = TrieSet::new();
|
||||
///
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(4);
|
||||
/// assert_eq!(a.is_disjoint(&b), true);
|
||||
/// b.insert(1);
|
||||
/// assert_eq!(a.is_disjoint(&b), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_disjoint(&self, other: &TrieSet) -> bool {
|
||||
self.iter().all(|v| !other.contains(&v))
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a subset of another.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let sup: TrieSet = [1, 2, 3].iter().map(|&x| x).collect();
|
||||
/// let mut set: TrieSet = TrieSet::new();
|
||||
///
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(2);
|
||||
/// assert_eq!(set.is_subset(&sup), true);
|
||||
/// set.insert(4);
|
||||
/// assert_eq!(set.is_subset(&sup), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_subset(&self, other: &TrieSet) -> bool {
|
||||
self.iter().all(|v| other.contains(&v))
|
||||
}
|
||||
|
||||
/// Returns `true` if the set is a superset of another.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let sub: TrieSet = [1, 2].iter().map(|&x| x).collect();
|
||||
/// let mut set: TrieSet = TrieSet::new();
|
||||
///
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(0);
|
||||
/// set.insert(1);
|
||||
/// assert_eq!(set.is_superset(&sub), false);
|
||||
///
|
||||
/// set.insert(2);
|
||||
/// assert_eq!(set.is_superset(&sub), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_superset(&self, other: &TrieSet) -> bool {
|
||||
other.is_subset(self)
|
||||
}
|
||||
|
||||
/// Adds a value to the set. Returns `true` if the value was not already
|
||||
/// present in the set.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut set = TrieSet::new();
|
||||
///
|
||||
/// assert_eq!(set.insert(2), true);
|
||||
/// assert_eq!(set.insert(2), false);
|
||||
/// assert_eq!(set.len(), 1);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn insert(&mut self, value: uint) -> bool {
|
||||
self.map.insert(value, ()).is_none()
|
||||
}
|
||||
|
||||
/// Removes a value from the set. Returns `true` if the value was
|
||||
/// present in the set.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::TrieSet;
|
||||
///
|
||||
/// let mut set = TrieSet::new();
|
||||
///
|
||||
/// set.insert(2);
|
||||
/// assert_eq!(set.remove(&2), true);
|
||||
/// assert_eq!(set.remove(&2), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn remove(&mut self, value: &uint) -> bool {
|
||||
self.map.remove(value).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<uint> for TrieSet {
|
||||
fn from_iter<Iter: Iterator<uint>>(iter: Iter) -> TrieSet {
|
||||
let mut set = TrieSet::new();
|
||||
set.extend(iter);
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<uint> for TrieSet {
|
||||
fn extend<Iter: Iterator<uint>>(&mut self, mut iter: Iter) {
|
||||
for elem in iter {
|
||||
self.insert(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A forward iterator over a set.
|
||||
pub struct SetItems<'a> {
|
||||
iter: Entries<'a, ()>
|
||||
}
|
||||
|
||||
impl<'a> Iterator<uint> for SetItems<'a> {
|
||||
fn next(&mut self) -> Option<uint> {
|
||||
self.iter.next().map(|(key, _)| key)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (uint, Option<uint>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::prelude::*;
|
||||
use std::uint;
|
||||
|
||||
use super::TrieSet;
|
||||
|
||||
#[test]
|
||||
fn test_sane_chunk() {
|
||||
let x = 1;
|
||||
let y = 1 << (uint::BITS - 1);
|
||||
|
||||
let mut trie = TrieSet::new();
|
||||
|
||||
assert!(trie.insert(x));
|
||||
assert!(trie.insert(y));
|
||||
|
||||
assert_eq!(trie.len(), 2);
|
||||
|
||||
let expected = [x, y];
|
||||
|
||||
for (i, x) in trie.iter().enumerate() {
|
||||
assert_eq!(expected[i], x);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter() {
|
||||
let xs = vec![9u, 8, 7, 6, 5, 4, 3, 2, 1];
|
||||
|
||||
let set: TrieSet = xs.iter().map(|&x| x).collect();
|
||||
|
||||
for x in xs.iter() {
|
||||
assert!(set.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_show() {
|
||||
let mut set = TrieSet::new();
|
||||
let empty = TrieSet::new();
|
||||
|
||||
set.insert(1);
|
||||
set.insert(2);
|
||||
|
||||
let set_str = format!("{}", set);
|
||||
|
||||
assert!(set_str == "{1, 2}".to_string());
|
||||
assert_eq!(format!("{}", empty), "{}".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone() {
|
||||
let mut a = TrieSet::new();
|
||||
|
||||
a.insert(1);
|
||||
a.insert(2);
|
||||
a.insert(3);
|
||||
|
||||
assert!(a.clone() == a);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lt() {
|
||||
let mut a = TrieSet::new();
|
||||
let mut b = TrieSet::new();
|
||||
|
||||
assert!(!(a < b) && !(b < a));
|
||||
assert!(b.insert(2u));
|
||||
assert!(a < b);
|
||||
assert!(a.insert(3u));
|
||||
assert!(!(a < b) && b < a);
|
||||
assert!(b.insert(1));
|
||||
assert!(b < a);
|
||||
assert!(a.insert(0));
|
||||
assert!(a < b);
|
||||
assert!(a.insert(6));
|
||||
assert!(a < b && !(b < a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ord() {
|
||||
let mut a = TrieSet::new();
|
||||
let mut b = TrieSet::new();
|
||||
|
||||
assert!(a <= b && a >= b);
|
||||
assert!(a.insert(1u));
|
||||
assert!(a > b && a >= b);
|
||||
assert!(b < a && b <= a);
|
||||
assert!(b.insert(2u));
|
||||
assert!(b > a && b >= a);
|
||||
assert!(a < b && a <= b);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -17,20 +17,19 @@ use core::prelude::*;
|
||||
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{Hash, Writer};
|
||||
use core::iter;
|
||||
use core::iter::{Enumerate, FilterMap};
|
||||
use core::iter::{Enumerate, FilterMap, Map};
|
||||
use core::mem::replace;
|
||||
|
||||
use {vec, slice};
|
||||
use vec::Vec;
|
||||
use hash;
|
||||
use hash::Hash;
|
||||
|
||||
// FIXME(conventions): capacity management???
|
||||
|
||||
/// A map optimized for small integer keys.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -61,12 +60,13 @@ use hash::Hash;
|
||||
/// months.clear();
|
||||
/// assert!(months.is_empty());
|
||||
/// ```
|
||||
#[deriving(PartialEq, Eq)]
|
||||
pub struct VecMap<T> {
|
||||
v: Vec<Option<T>>,
|
||||
pub struct VecMap<V> {
|
||||
v: Vec<Option<V>>,
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<V> Default for VecMap<V> {
|
||||
#[stable]
|
||||
#[inline]
|
||||
fn default() -> VecMap<V> { VecMap::new() }
|
||||
}
|
||||
@ -83,28 +83,35 @@ impl<V:Clone> Clone for VecMap<V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <S: hash::Writer, T: Hash<S>> Hash<S> for VecMap<T> {
|
||||
impl<S: Writer, V: Hash<S>> Hash<S> for VecMap<V> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.v.hash(state)
|
||||
// In order to not traverse the `VecMap` twice, count the elements
|
||||
// during iteration.
|
||||
let mut count: uint = 0;
|
||||
for elt in self.iter() {
|
||||
elt.hash(state);
|
||||
count += 1;
|
||||
}
|
||||
count.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> VecMap<V> {
|
||||
/// Creates an empty `VecMap`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
/// let mut map: VecMap<&str> = VecMap::new();
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> VecMap<V> { VecMap{v: vec!()} }
|
||||
pub fn new() -> VecMap<V> { VecMap { v: vec![] } }
|
||||
|
||||
/// Creates an empty `VecMap` with space for at least `capacity`
|
||||
/// elements before resizing.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -115,24 +122,46 @@ impl<V> VecMap<V> {
|
||||
VecMap { v: Vec::with_capacity(capacity) }
|
||||
}
|
||||
|
||||
/// Returns the number of elements the `VecMap` can hold without
|
||||
/// reallocating.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
/// let map: VecMap<String> = VecMap::with_capacity(10);
|
||||
/// assert!(map.capacity() >= 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn capacity(&self) -> uint {
|
||||
self.v.capacity()
|
||||
}
|
||||
|
||||
/// Returns an iterator visiting all keys in ascending order by the keys.
|
||||
/// The iterator's element type is `uint`.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn keys<'r>(&'r self) -> Keys<'r, V> {
|
||||
self.iter().map(|(k, _v)| k)
|
||||
fn first<A, B>((a, _): (A, B)) -> A { a }
|
||||
let first: fn((uint, &'r V)) -> uint = first; // coerce to fn pointer
|
||||
|
||||
Keys { iter: self.iter().map(first) }
|
||||
}
|
||||
|
||||
/// Returns an iterator visiting all values in ascending order by the keys.
|
||||
/// The iterator's element type is `&'r V`.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn values<'r>(&'r self) -> Values<'r, V> {
|
||||
self.iter().map(|(_k, v)| v)
|
||||
fn second<A, B>((_, b): (A, B)) -> B { b }
|
||||
let second: fn((uint, &'r V)) -> &'r V = second; // coerce to fn pointer
|
||||
|
||||
Values { iter: self.iter().map(second) }
|
||||
}
|
||||
|
||||
/// Returns an iterator visiting all key-value pairs in ascending order by the keys.
|
||||
/// The iterator's element type is `(uint, &'r V)`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -148,8 +177,8 @@ impl<V> VecMap<V> {
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter<'r>(&'r self) -> Entries<'r, V> {
|
||||
Entries {
|
||||
pub fn iter<'r>(&'r self) -> Iter<'r, V> {
|
||||
Iter {
|
||||
front: 0,
|
||||
back: self.v.len(),
|
||||
iter: self.v.iter()
|
||||
@ -160,7 +189,7 @@ impl<V> VecMap<V> {
|
||||
/// with mutable references to the values.
|
||||
/// The iterator's element type is `(uint, &'r mut V)`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -179,8 +208,8 @@ impl<V> VecMap<V> {
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn iter_mut<'r>(&'r mut self) -> MutEntries<'r, V> {
|
||||
MutEntries {
|
||||
pub fn iter_mut<'r>(&'r mut self) -> IterMut<'r, V> {
|
||||
IterMut {
|
||||
front: 0,
|
||||
back: self.v.len(),
|
||||
iter: self.v.iter_mut()
|
||||
@ -191,7 +220,7 @@ impl<V> VecMap<V> {
|
||||
/// the keys, emptying (but not consuming) the original `VecMap`.
|
||||
/// The iterator's element type is `(uint, &'r V)`.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -207,19 +236,19 @@ impl<V> VecMap<V> {
|
||||
/// assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn into_iter(&mut self)
|
||||
-> FilterMap<(uint, Option<V>), (uint, V),
|
||||
Enumerate<vec::MoveItems<Option<V>>>>
|
||||
{
|
||||
let values = replace(&mut self.v, vec!());
|
||||
values.into_iter().enumerate().filter_map(|(i, v)| {
|
||||
pub fn into_iter(&mut self) -> IntoIter<V> {
|
||||
fn filter<A>((i, v): (uint, Option<A>)) -> Option<(uint, A)> {
|
||||
v.map(|v| (i, v))
|
||||
})
|
||||
}
|
||||
let filter: fn((uint, Option<V>)) -> Option<(uint, V)> = filter; // coerce to fn ptr
|
||||
|
||||
let values = replace(&mut self.v, vec!());
|
||||
IntoIter { iter: values.into_iter().enumerate().filter_map(filter) }
|
||||
}
|
||||
|
||||
/// Return the number of elements in the map.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -236,7 +265,7 @@ impl<V> VecMap<V> {
|
||||
|
||||
/// Return true if the map contains no elements.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -253,7 +282,7 @@ impl<V> VecMap<V> {
|
||||
|
||||
/// Clears the map, removing all key-value pairs.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -274,7 +303,7 @@ impl<V> VecMap<V> {
|
||||
|
||||
/// Returns a reference to the value corresponding to the key.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -298,7 +327,7 @@ impl<V> VecMap<V> {
|
||||
|
||||
/// Returns true if the map contains a value for the specified key.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -322,7 +351,7 @@ impl<V> VecMap<V> {
|
||||
|
||||
/// Returns a mutable reference to the value corresponding to the key.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -356,7 +385,7 @@ impl<V> VecMap<V> {
|
||||
/// Inserts a key-value pair from the map. If the key already had a value
|
||||
/// present in the map, that value is returned. Otherwise, `None` is returned.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -387,7 +416,7 @@ impl<V> VecMap<V> {
|
||||
/// Removes a key from the map, returning the value at the key if the key
|
||||
/// was previously in the map.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -412,7 +441,7 @@ impl<V:Clone> VecMap<V> {
|
||||
/// Otherwise, sets the value to `newval`.
|
||||
/// Returns `true` if the key did not already exist in the map.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -427,8 +456,8 @@ impl<V:Clone> VecMap<V> {
|
||||
/// assert!(!map.update(1, vec![3i, 4], |mut old, new| { old.extend(new.into_iter()); old }));
|
||||
/// assert_eq!(map[1], vec![1i, 2, 3, 4]);
|
||||
/// ```
|
||||
pub fn update(&mut self, key: uint, newval: V, ff: |V, V| -> V) -> bool {
|
||||
self.update_with_key(key, newval, |_k, v, v1| ff(v,v1))
|
||||
pub fn update<F>(&mut self, key: uint, newval: V, ff: F) -> bool where F: FnOnce(V, V) -> V {
|
||||
self.update_with_key(key, newval, move |_k, v, v1| ff(v,v1))
|
||||
}
|
||||
|
||||
/// Updates a value in the map. If the key already exists in the map,
|
||||
@ -436,7 +465,7 @@ impl<V:Clone> VecMap<V> {
|
||||
/// Otherwise, sets the value to `newval`.
|
||||
/// Returns `true` if the key did not already exist in the map.
|
||||
///
|
||||
/// # Example
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecMap;
|
||||
@ -451,11 +480,9 @@ impl<V:Clone> VecMap<V> {
|
||||
/// assert!(!map.update_with_key(7, 20, |key, old, new| (old + new) % key));
|
||||
/// assert_eq!(map[7], 2);
|
||||
/// ```
|
||||
pub fn update_with_key(&mut self,
|
||||
key: uint,
|
||||
val: V,
|
||||
ff: |uint, V, V| -> V)
|
||||
-> bool {
|
||||
pub fn update_with_key<F>(&mut self, key: uint, val: V, ff: F) -> bool where
|
||||
F: FnOnce(uint, V, V) -> V
|
||||
{
|
||||
let new_val = match self.get(&key) {
|
||||
None => val,
|
||||
Some(orig) => ff(key, (*orig).clone(), val)
|
||||
@ -464,6 +491,14 @@ impl<V:Clone> VecMap<V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: PartialEq> PartialEq for VecMap<V> {
|
||||
fn eq(&self, other: &VecMap<V>) -> bool {
|
||||
iter::order::eq(self.iter(), other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Eq> Eq for VecMap<V> {}
|
||||
|
||||
impl<V: PartialOrd> PartialOrd for VecMap<V> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &VecMap<V>) -> Option<Ordering> {
|
||||
@ -523,16 +558,19 @@ impl<V> IndexMut<uint, V> for VecMap<V> {
|
||||
|
||||
macro_rules! iterator {
|
||||
(impl $name:ident -> $elem:ty, $($getter:ident),+) => {
|
||||
impl<'a, T> Iterator<$elem> for $name<'a, T> {
|
||||
impl<'a, V> Iterator<$elem> for $name<'a, V> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<$elem> {
|
||||
while self.front < self.back {
|
||||
match self.iter.next() {
|
||||
Some(elem) => {
|
||||
if elem.is_some() {
|
||||
let index = self.front;
|
||||
self.front += 1;
|
||||
return Some((index, elem $(. $getter ())+));
|
||||
match elem$(. $getter ())+ {
|
||||
Some(x) => {
|
||||
let index = self.front;
|
||||
self.front += 1;
|
||||
return Some((index, x));
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
@ -552,15 +590,18 @@ macro_rules! iterator {
|
||||
|
||||
macro_rules! double_ended_iterator {
|
||||
(impl $name:ident -> $elem:ty, $($getter:ident),+) => {
|
||||
impl<'a, T> DoubleEndedIterator<$elem> for $name<'a, T> {
|
||||
impl<'a, V> DoubleEndedIterator<$elem> for $name<'a, V> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<$elem> {
|
||||
while self.front < self.back {
|
||||
match self.iter.next_back() {
|
||||
Some(elem) => {
|
||||
if elem.is_some() {
|
||||
self.back -= 1;
|
||||
return Some((self.back, elem$(. $getter ())+));
|
||||
match elem$(. $getter ())+ {
|
||||
Some(x) => {
|
||||
self.back -= 1;
|
||||
return Some((self.back, x));
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
@ -573,40 +614,76 @@ macro_rules! double_ended_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Forward iterator over a map.
|
||||
pub struct Entries<'a, T:'a> {
|
||||
/// An iterator over the key-value pairs of a map.
|
||||
pub struct Iter<'a, V:'a> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::Items<'a, Option<T>>
|
||||
iter: slice::Iter<'a, Option<V>>
|
||||
}
|
||||
|
||||
iterator!(impl Entries -> (uint, &'a T), as_ref, unwrap)
|
||||
double_ended_iterator!(impl Entries -> (uint, &'a T), as_ref, unwrap)
|
||||
iterator! { impl Iter -> (uint, &'a V), as_ref }
|
||||
double_ended_iterator! { impl Iter -> (uint, &'a V), as_ref }
|
||||
|
||||
/// Forward iterator over the key-value pairs of a map, with the
|
||||
/// An iterator over the key-value pairs of a map, with the
|
||||
/// values being mutable.
|
||||
pub struct MutEntries<'a, T:'a> {
|
||||
pub struct IterMut<'a, V:'a> {
|
||||
front: uint,
|
||||
back: uint,
|
||||
iter: slice::MutItems<'a, Option<T>>
|
||||
iter: slice::IterMut<'a, Option<V>>
|
||||
}
|
||||
|
||||
iterator!(impl MutEntries -> (uint, &'a mut T), as_mut, unwrap)
|
||||
double_ended_iterator!(impl MutEntries -> (uint, &'a mut T), as_mut, unwrap)
|
||||
iterator! { impl IterMut -> (uint, &'a mut V), as_mut }
|
||||
double_ended_iterator! { impl IterMut -> (uint, &'a mut V), as_mut }
|
||||
|
||||
/// Forward iterator over the keys of a map
|
||||
pub type Keys<'a, T> =
|
||||
iter::Map<'static, (uint, &'a T), uint, Entries<'a, T>>;
|
||||
/// An iterator over the keys of a map.
|
||||
pub struct Keys<'a, V: 'a> {
|
||||
iter: Map<(uint, &'a V), uint, Iter<'a, V>, fn((uint, &'a V)) -> uint>
|
||||
}
|
||||
|
||||
/// Forward iterator over the values of a map
|
||||
pub type Values<'a, T> =
|
||||
iter::Map<'static, (uint, &'a T), &'a T, Entries<'a, T>>;
|
||||
/// An iterator over the values of a map.
|
||||
pub struct Values<'a, V: 'a> {
|
||||
iter: Map<(uint, &'a V), &'a V, Iter<'a, V>, fn((uint, &'a V)) -> &'a V>
|
||||
}
|
||||
|
||||
/// A consuming iterator over the key-value pairs of a map.
|
||||
pub struct IntoIter<V> {
|
||||
iter: FilterMap<
|
||||
(uint, Option<V>),
|
||||
(uint, V),
|
||||
Enumerate<vec::IntoIter<Option<V>>>,
|
||||
fn((uint, Option<V>)) -> Option<(uint, V)>>
|
||||
}
|
||||
|
||||
impl<'a, V> Iterator<uint> for Keys<'a, V> {
|
||||
fn next(&mut self) -> Option<uint> { self.iter.next() }
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
impl<'a, V> DoubleEndedIterator<uint> for Keys<'a, V> {
|
||||
fn next_back(&mut self) -> Option<uint> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
|
||||
impl<'a, V> Iterator<&'a V> for Values<'a, V> {
|
||||
fn next(&mut self) -> Option<(&'a V)> { self.iter.next() }
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
impl<'a, V> DoubleEndedIterator<&'a V> for Values<'a, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a V)> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
|
||||
impl<V> Iterator<(uint, V)> for IntoIter<V> {
|
||||
fn next(&mut self) -> Option<(uint, V)> { self.iter.next() }
|
||||
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
|
||||
}
|
||||
impl<V> DoubleEndedIterator<(uint, V)> for IntoIter<V> {
|
||||
fn next_back(&mut self) -> Option<(uint, V)> { self.iter.next_back() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_map {
|
||||
use std::prelude::*;
|
||||
use vec::Vec;
|
||||
use hash;
|
||||
use prelude::*;
|
||||
use core::hash::hash;
|
||||
|
||||
use super::VecMap;
|
||||
|
||||
@ -854,9 +931,8 @@ mod test_map {
|
||||
map.insert(3, 4i);
|
||||
|
||||
let map_str = map.to_string();
|
||||
let map_str = map_str.as_slice();
|
||||
assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
|
||||
assert_eq!(format!("{}", empty), "{}".to_string());
|
||||
assert_eq!(format!("{}", empty), "{}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -886,6 +962,10 @@ mod test_map {
|
||||
assert!(a != b);
|
||||
assert!(b.insert(5, 19).is_none());
|
||||
assert!(a == b);
|
||||
|
||||
a = VecMap::new();
|
||||
b = VecMap::with_capacity(1);
|
||||
assert!(a == b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -925,7 +1005,7 @@ mod test_map {
|
||||
let mut x = VecMap::new();
|
||||
let mut y = VecMap::new();
|
||||
|
||||
assert!(hash::hash(&x) == hash::hash(&y));
|
||||
assert!(hash(&x) == hash(&y));
|
||||
x.insert(1, 'a');
|
||||
x.insert(2, 'b');
|
||||
x.insert(3, 'c');
|
||||
@ -934,7 +1014,12 @@ mod test_map {
|
||||
y.insert(2, 'b');
|
||||
y.insert(1, 'a');
|
||||
|
||||
assert!(hash::hash(&x) == hash::hash(&y));
|
||||
assert!(hash(&x) == hash(&y));
|
||||
|
||||
x.insert(1000, 'd');
|
||||
x.remove(&1000);
|
||||
|
||||
assert!(hash(&x) == hash(&y));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -974,8 +1059,7 @@ mod test_map {
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
use test::Bencher;
|
||||
use super::VecMap;
|
||||
use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n};
|
||||
|
||||
|
@ -71,8 +71,9 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
use mem::{transmute, transmute_copy};
|
||||
use option::{Option, Some, None};
|
||||
use mem::{transmute};
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
use raw::TraitObject;
|
||||
use intrinsics::TypeId;
|
||||
|
||||
@ -88,7 +89,7 @@ use intrinsics::TypeId;
|
||||
#[stable]
|
||||
pub trait Any: 'static {
|
||||
/// Get the `TypeId` of `self`
|
||||
#[stable]
|
||||
#[experimental = "this method will likely be replaced by an associated static"]
|
||||
fn get_type_id(&self) -> TypeId;
|
||||
}
|
||||
|
||||
@ -134,7 +135,7 @@ impl<'a> AnyRefExt<'a> for &'a Any {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject = transmute_copy(&self);
|
||||
let to: TraitObject = transmute(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Some(transmute(to.data))
|
||||
@ -162,7 +163,7 @@ impl<'a> AnyMutRefExt<'a> for &'a mut Any {
|
||||
if self.is::<T>() {
|
||||
unsafe {
|
||||
// Get the raw representation of the trait object
|
||||
let to: TraitObject = transmute_copy(&self);
|
||||
let to: TraitObject = transmute(self);
|
||||
|
||||
// Extract the data pointer
|
||||
Some(transmute(to.data))
|
||||
|
@ -18,13 +18,14 @@ use clone::Clone;
|
||||
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
||||
use fmt;
|
||||
use kinds::Copy;
|
||||
use ops::Deref;
|
||||
use option::Option;
|
||||
|
||||
// macro for implementing n-ary tuple functions and operations
|
||||
macro_rules! array_impls {
|
||||
($($N:expr)+) => {
|
||||
$(
|
||||
#[unstable = "waiting for Clone to stabilize"]
|
||||
#[stable]
|
||||
impl<T:Copy> Clone for [T, ..$N] {
|
||||
fn clone(&self) -> [T, ..$N] {
|
||||
*self
|
||||
@ -39,17 +40,37 @@ macro_rules! array_impls {
|
||||
}
|
||||
|
||||
#[unstable = "waiting for PartialEq to stabilize"]
|
||||
impl<T:PartialEq> PartialEq for [T, ..$N] {
|
||||
impl<A, B> PartialEq<[B, ..$N]> for [A, ..$N] where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &[T, ..$N]) -> bool {
|
||||
fn eq(&self, other: &[B, ..$N]) -> bool {
|
||||
self[] == other[]
|
||||
}
|
||||
#[inline]
|
||||
fn ne(&self, other: &[T, ..$N]) -> bool {
|
||||
fn ne(&self, other: &[B, ..$N]) -> bool {
|
||||
self[] != other[]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A, B, Rhs> PartialEq<Rhs> for [A, ..$N] where
|
||||
A: PartialEq<B>,
|
||||
Rhs: Deref<[B]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Rhs) -> bool { PartialEq::eq(self[], &**other) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &Rhs) -> bool { PartialEq::ne(self[], &**other) }
|
||||
}
|
||||
|
||||
impl<'a, A, B, Lhs> PartialEq<[B, ..$N]> for Lhs where
|
||||
A: PartialEq<B>,
|
||||
Lhs: Deref<[A]>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &[B, ..$N]) -> bool { PartialEq::eq(&**self, other[]) }
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &[B, ..$N]) -> bool { PartialEq::ne(&**self, other[]) }
|
||||
}
|
||||
|
||||
#[unstable = "waiting for Eq to stabilize"]
|
||||
impl<T:Eq> Eq for [T, ..$N] { }
|
||||
|
||||
@ -94,4 +115,3 @@ array_impls! {
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
30 31 32
|
||||
}
|
||||
|
||||
|
@ -15,35 +15,30 @@
|
||||
pub use self::Ordering::*;
|
||||
|
||||
use intrinsics;
|
||||
use std::kinds::marker;
|
||||
use cell::UnsafeCell;
|
||||
|
||||
/// A boolean type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicBool {
|
||||
v: UnsafeCell<uint>,
|
||||
nocopy: marker::NoCopy
|
||||
}
|
||||
|
||||
/// A signed integer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicInt {
|
||||
v: UnsafeCell<int>,
|
||||
nocopy: marker::NoCopy
|
||||
}
|
||||
|
||||
/// An unsigned integer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicUint {
|
||||
v: UnsafeCell<uint>,
|
||||
nocopy: marker::NoCopy
|
||||
}
|
||||
|
||||
/// A raw pointer type which can be safely shared between threads.
|
||||
#[stable]
|
||||
pub struct AtomicPtr<T> {
|
||||
p: UnsafeCell<uint>,
|
||||
nocopy: marker::NoCopy
|
||||
}
|
||||
|
||||
/// Atomic memory orderings
|
||||
@ -57,6 +52,7 @@ pub struct AtomicPtr<T> {
|
||||
/// Rust's memory orderings are [the same as
|
||||
/// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync).
|
||||
#[stable]
|
||||
#[deriving(Copy)]
|
||||
pub enum Ordering {
|
||||
/// No ordering constraints, only atomic operations.
|
||||
#[stable]
|
||||
@ -84,15 +80,15 @@ pub enum Ordering {
|
||||
/// An `AtomicBool` initialized to `false`.
|
||||
#[unstable = "may be renamed, pending conventions for static initalizers"]
|
||||
pub const INIT_ATOMIC_BOOL: AtomicBool =
|
||||
AtomicBool { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy };
|
||||
AtomicBool { v: UnsafeCell { value: 0 } };
|
||||
/// An `AtomicInt` initialized to `0`.
|
||||
#[unstable = "may be renamed, pending conventions for static initalizers"]
|
||||
pub const INIT_ATOMIC_INT: AtomicInt =
|
||||
AtomicInt { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy };
|
||||
AtomicInt { v: UnsafeCell { value: 0 } };
|
||||
/// An `AtomicUint` initialized to `0`.
|
||||
#[unstable = "may be renamed, pending conventions for static initalizers"]
|
||||
pub const INIT_ATOMIC_UINT: AtomicUint =
|
||||
AtomicUint { v: UnsafeCell { value: 0, }, nocopy: marker::NoCopy };
|
||||
AtomicUint { v: UnsafeCell { value: 0, } };
|
||||
|
||||
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
|
||||
const UINT_TRUE: uint = -1;
|
||||
@ -112,7 +108,7 @@ impl AtomicBool {
|
||||
#[stable]
|
||||
pub fn new(v: bool) -> AtomicBool {
|
||||
let val = if v { UINT_TRUE } else { 0 };
|
||||
AtomicBool { v: UnsafeCell::new(val), nocopy: marker::NoCopy }
|
||||
AtomicBool { v: UnsafeCell::new(val) }
|
||||
}
|
||||
|
||||
/// Loads a value from the bool.
|
||||
@ -352,7 +348,7 @@ impl AtomicInt {
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new(v: int) -> AtomicInt {
|
||||
AtomicInt {v: UnsafeCell::new(v), nocopy: marker::NoCopy}
|
||||
AtomicInt {v: UnsafeCell::new(v)}
|
||||
}
|
||||
|
||||
/// Loads a value from the int.
|
||||
@ -538,7 +534,7 @@ impl AtomicUint {
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new(v: uint) -> AtomicUint {
|
||||
AtomicUint { v: UnsafeCell::new(v), nocopy: marker::NoCopy }
|
||||
AtomicUint { v: UnsafeCell::new(v) }
|
||||
}
|
||||
|
||||
/// Loads a value from the uint.
|
||||
@ -725,7 +721,7 @@ impl<T> AtomicPtr<T> {
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new(p: *mut T) -> AtomicPtr<T> {
|
||||
AtomicPtr { p: UnsafeCell::new(p as uint), nocopy: marker::NoCopy }
|
||||
AtomicPtr { p: UnsafeCell::new(p as uint) }
|
||||
}
|
||||
|
||||
/// Loads a value from the pointer.
|
||||
|
@ -37,16 +37,19 @@
|
||||
//! data lazily when mutation or ownership is required. The type is designed to
|
||||
//! work with general borrowed data via the `BorrowFrom` trait.
|
||||
//!
|
||||
//! `Cow` implements both `Deref` and `DerefMut`, which means that you can call
|
||||
//! methods directly on the data it encloses. The first time a mutable reference
|
||||
//! is required, the data will be cloned (via `to_owned`) if it is not
|
||||
//! already owned.
|
||||
//! `Cow` implements both `Deref`, which means that you can call
|
||||
//! non-mutating methods directly on the data it encloses. If mutation
|
||||
//! is desired, `to_mut` will obtain a mutable references to an owned
|
||||
//! value, cloning if necessary.
|
||||
|
||||
#![unstable = "recently added as part of collections reform"]
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||
use fmt;
|
||||
use kinds::Sized;
|
||||
use ops::Deref;
|
||||
use option::Option;
|
||||
use self::Cow::*;
|
||||
|
||||
/// A trait for borrowing data.
|
||||
@ -69,8 +72,34 @@ impl<Sized? T> BorrowFromMut<T> for T {
|
||||
fn borrow_from_mut(owned: &mut T) -> &mut T { owned }
|
||||
}
|
||||
|
||||
impl BorrowFrom<&'static str> for str {
|
||||
fn borrow_from<'a>(owned: &'a &'static str) -> &'a str { &**owned }
|
||||
impl<'a, Sized? T> BorrowFrom<&'a T> for T {
|
||||
fn borrow_from<'b>(owned: &'b &'a T) -> &'b T { &**owned }
|
||||
}
|
||||
|
||||
impl<'a, Sized? T> BorrowFrom<&'a mut T> for T {
|
||||
fn borrow_from<'b>(owned: &'b &'a mut T) -> &'b T { &**owned }
|
||||
}
|
||||
|
||||
impl<'a, Sized? T> BorrowFromMut<&'a mut T> for T {
|
||||
fn borrow_from_mut<'b>(owned: &'b mut &'a mut T) -> &'b mut T { &mut **owned }
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> BorrowFrom<Cow<'a, T, B>> for B where B: ToOwned<T> {
|
||||
fn borrow_from<'b>(owned: &'b Cow<'a, T, B>) -> &'b B {
|
||||
&**owned
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for moving into a `Cow`
|
||||
pub trait IntoCow<'a, T, Sized? B> {
|
||||
/// Moves `self` into `Cow`
|
||||
fn into_cow(self) -> Cow<'a, T, B>;
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> IntoCow<'a, T, B> for Cow<'a, T, B> where B: ToOwned<T> {
|
||||
fn into_cow(self) -> Cow<'a, T, B> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A generalization of Clone to borrowed data.
|
||||
@ -84,7 +113,23 @@ impl<T> ToOwned<T> for T where T: Clone {
|
||||
}
|
||||
|
||||
/// A clone-on-write smart pointer.
|
||||
pub enum Cow<'a, T, B: 'a> where B: ToOwned<T> {
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::borrow::Cow;
|
||||
///
|
||||
/// fn abs_all(input: &mut Cow<Vec<int>, [int]>) {
|
||||
/// for i in range(0, input.len()) {
|
||||
/// let v = input[i];
|
||||
/// if v < 0 {
|
||||
/// // clones into a vector the first time (if not already owned)
|
||||
/// input.to_mut()[i] = -v;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub enum Cow<'a, T, Sized? B: 'a> where B: ToOwned<T> {
|
||||
/// Borrowed data.
|
||||
Borrowed(&'a B),
|
||||
|
||||
@ -92,7 +137,20 @@ pub enum Cow<'a, T, B: 'a> where B: ToOwned<T> {
|
||||
Owned(T)
|
||||
}
|
||||
|
||||
impl<'a, T, B> Cow<'a, T, B> where B: ToOwned<T> {
|
||||
#[stable]
|
||||
impl<'a, T, Sized? B> Clone for Cow<'a, T, B> where B: ToOwned<T> {
|
||||
fn clone(&self) -> Cow<'a, T, B> {
|
||||
match *self {
|
||||
Borrowed(b) => Borrowed(b),
|
||||
Owned(ref o) => {
|
||||
let b: &B = BorrowFrom::borrow_from(o);
|
||||
Owned(b.to_owned())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> Cow<'a, T, B> where B: ToOwned<T> {
|
||||
/// Acquire a mutable reference to the owned form of the data.
|
||||
///
|
||||
/// Copies the data if it is not already owned.
|
||||
@ -115,9 +173,25 @@ impl<'a, T, B> Cow<'a, T, B> where B: ToOwned<T> {
|
||||
Owned(owned) => owned
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this `Cow` wraps a borrowed value
|
||||
pub fn is_borrowed(&self) -> bool {
|
||||
match *self {
|
||||
Borrowed(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this `Cow` wraps an owned value
|
||||
pub fn is_owned(&self) -> bool {
|
||||
match *self {
|
||||
Owned(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, B> Deref<B> for Cow<'a, T, B> where B: ToOwned<T> {
|
||||
impl<'a, T, Sized? B> Deref<B> for Cow<'a, T, B> where B: ToOwned<T> {
|
||||
fn deref(&self) -> &B {
|
||||
match *self {
|
||||
Borrowed(borrowed) => borrowed,
|
||||
@ -125,3 +199,38 @@ impl<'a, T, B> Deref<B> for Cow<'a, T, B> where B: ToOwned<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> Eq for Cow<'a, T, B> where B: Eq + ToOwned<T> {}
|
||||
|
||||
impl<'a, T, Sized? B> Ord for Cow<'a, T, B> where B: Ord + ToOwned<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Cow<'a, T, B>) -> Ordering {
|
||||
Ord::cmp(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, T, U, Sized? B, Sized? C> PartialEq<Cow<'b, U, C>> for Cow<'a, T, B> where
|
||||
B: PartialEq<C> + ToOwned<T>,
|
||||
C: ToOwned<U>,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Cow<'b, U, C>) -> bool {
|
||||
PartialEq::eq(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> PartialOrd for Cow<'a, T, B> where B: PartialOrd + ToOwned<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Cow<'a, T, B>) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, Sized? B> fmt::Show for Cow<'a, T, B> where B: fmt::Show + ToOwned<T>, T: fmt::Show {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Borrowed(ref b) => fmt::Show::fmt(b, f),
|
||||
Owned(ref o) => fmt::Show::fmt(o, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,10 +160,11 @@ use cmp::PartialEq;
|
||||
use default::Default;
|
||||
use kinds::{marker, Copy};
|
||||
use ops::{Deref, DerefMut, Drop};
|
||||
use option::{None, Option, Some};
|
||||
use option::Option;
|
||||
use option::Option::{None, Some};
|
||||
|
||||
/// A mutable memory location that admits only `Copy` data.
|
||||
#[unstable = "likely to be renamed; otherwise stable"]
|
||||
#[stable]
|
||||
pub struct Cell<T> {
|
||||
value: UnsafeCell<T>,
|
||||
noshare: marker::NoSync,
|
||||
@ -207,15 +208,16 @@ impl<T:Copy> Cell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "waiting for `Clone` trait to become stable"]
|
||||
#[stable]
|
||||
impl<T:Copy> Clone for Cell<T> {
|
||||
fn clone(&self) -> Cell<T> {
|
||||
Cell::new(self.get())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable]
|
||||
#[stable]
|
||||
impl<T:Default + Copy> Default for Cell<T> {
|
||||
#[stable]
|
||||
fn default() -> Cell<T> {
|
||||
Cell::new(Default::default())
|
||||
}
|
||||
@ -229,11 +231,10 @@ impl<T:PartialEq + Copy> PartialEq for Cell<T> {
|
||||
}
|
||||
|
||||
/// A mutable memory location with dynamically checked borrow rules
|
||||
#[unstable = "likely to be renamed; otherwise stable"]
|
||||
#[stable]
|
||||
pub struct RefCell<T> {
|
||||
value: UnsafeCell<T>,
|
||||
borrow: Cell<BorrowFlag>,
|
||||
nocopy: marker::NoCopy,
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
|
||||
@ -250,32 +251,35 @@ impl<T> RefCell<T> {
|
||||
RefCell {
|
||||
value: UnsafeCell::new(value),
|
||||
borrow: Cell::new(UNUSED),
|
||||
nocopy: marker::NoCopy,
|
||||
noshare: marker::NoSync,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the `RefCell`, returning the wrapped value.
|
||||
#[unstable = "may be renamed, depending on global conventions"]
|
||||
pub fn unwrap(self) -> T {
|
||||
#[stable]
|
||||
pub fn into_inner(self) -> T {
|
||||
// Since this function takes `self` (the `RefCell`) by value, the
|
||||
// compiler statically verifies that it is not currently borrowed.
|
||||
// Therefore the following assertion is just a `debug_assert!`.
|
||||
debug_assert!(self.borrow.get() == UNUSED);
|
||||
unsafe{self.value.unwrap()}
|
||||
unsafe { self.value.into_inner() }
|
||||
}
|
||||
|
||||
/// Deprecated, use into_inner() instead
|
||||
#[deprecated = "renamed to into_inner()"]
|
||||
pub fn unwrap(self) -> T { self.into_inner() }
|
||||
|
||||
/// Attempts to immutably borrow the wrapped value.
|
||||
///
|
||||
/// The borrow lasts until the returned `Ref` exits scope. Multiple
|
||||
/// immutable borrows can be taken out at the same time.
|
||||
///
|
||||
/// Returns `None` if the value is currently mutably borrowed.
|
||||
#[unstable = "may be renamed, depending on global conventions"]
|
||||
#[unstable = "may be renamed or removed"]
|
||||
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
|
||||
match self.borrow.get() {
|
||||
WRITING => None,
|
||||
borrow => {
|
||||
self.borrow.set(borrow + 1);
|
||||
Some(Ref { _parent: self })
|
||||
}
|
||||
match BorrowRef::new(&self.borrow) {
|
||||
Some(b) => Some(Ref { _value: unsafe { &*self.value.get() }, _borrow: b }),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,7 +291,7 @@ impl<T> RefCell<T> {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently mutably borrowed.
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
|
||||
match self.try_borrow() {
|
||||
Some(ptr) => ptr,
|
||||
@ -301,14 +305,11 @@ impl<T> RefCell<T> {
|
||||
/// cannot be borrowed while this borrow is active.
|
||||
///
|
||||
/// Returns `None` if the value is currently borrowed.
|
||||
#[unstable = "may be renamed, depending on global conventions"]
|
||||
#[unstable = "may be renamed or removed"]
|
||||
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
|
||||
match self.borrow.get() {
|
||||
UNUSED => {
|
||||
self.borrow.set(WRITING);
|
||||
Some(RefMut { _parent: self })
|
||||
},
|
||||
_ => None
|
||||
match BorrowRefMut::new(&self.borrow) {
|
||||
Some(b) => Some(RefMut { _value: unsafe { &mut *self.value.get() }, _borrow: b }),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,7 +321,7 @@ impl<T> RefCell<T> {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
|
||||
match self.try_borrow_mut() {
|
||||
Some(ptr) => ptr,
|
||||
@ -340,15 +341,16 @@ impl<T> RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "waiting for `Clone` to become stable"]
|
||||
#[stable]
|
||||
impl<T: Clone> Clone for RefCell<T> {
|
||||
fn clone(&self) -> RefCell<T> {
|
||||
RefCell::new(self.borrow().clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable]
|
||||
#[stable]
|
||||
impl<T:Default> Default for RefCell<T> {
|
||||
#[stable]
|
||||
fn default() -> RefCell<T> {
|
||||
RefCell::new(Default::default())
|
||||
}
|
||||
@ -361,29 +363,56 @@ impl<T: PartialEq> PartialEq for RefCell<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a borrowed reference to a value in a `RefCell` box.
|
||||
#[unstable]
|
||||
pub struct Ref<'b, T:'b> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_parent: &'b RefCell<T>
|
||||
struct BorrowRef<'b> {
|
||||
_borrow: &'b Cell<BorrowFlag>,
|
||||
}
|
||||
|
||||
impl<'b> BorrowRef<'b> {
|
||||
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
|
||||
match borrow.get() {
|
||||
WRITING => None,
|
||||
b => {
|
||||
borrow.set(b + 1);
|
||||
Some(BorrowRef { _borrow: borrow })
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[unstable]
|
||||
impl<'b, T> Drop for Ref<'b, T> {
|
||||
impl<'b> Drop for BorrowRef<'b> {
|
||||
fn drop(&mut self) {
|
||||
let borrow = self._parent.borrow.get();
|
||||
let borrow = self._borrow.get();
|
||||
debug_assert!(borrow != WRITING && borrow != UNUSED);
|
||||
self._parent.borrow.set(borrow - 1);
|
||||
self._borrow.set(borrow - 1);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Clone for BorrowRef<'b> {
|
||||
fn clone(&self) -> BorrowRef<'b> {
|
||||
// Since this Ref exists, we know the borrow flag
|
||||
// is not set to WRITING.
|
||||
let borrow = self._borrow.get();
|
||||
debug_assert!(borrow != WRITING && borrow != UNUSED);
|
||||
self._borrow.set(borrow + 1);
|
||||
BorrowRef { _borrow: self._borrow }
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a borrowed reference to a value in a `RefCell` box.
|
||||
#[stable]
|
||||
pub struct Ref<'b, T:'b> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_value: &'b T,
|
||||
_borrow: BorrowRef<'b>,
|
||||
}
|
||||
|
||||
#[unstable = "waiting for `Deref` to become stable"]
|
||||
impl<'b, T> Deref<T> for Ref<'b, T> {
|
||||
#[inline]
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
unsafe { &*self._parent.value.get() }
|
||||
self._value
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,41 +423,52 @@ impl<'b, T> Deref<T> for Ref<'b, T> {
|
||||
/// A `Clone` implementation would interfere with the widespread
|
||||
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
|
||||
#[experimental = "likely to be moved to a method, pending language changes"]
|
||||
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
// Since this Ref exists, we know the borrow flag
|
||||
// is not set to WRITING.
|
||||
let borrow = orig._parent.borrow.get();
|
||||
debug_assert!(borrow != WRITING && borrow != UNUSED);
|
||||
orig._parent.borrow.set(borrow + 1);
|
||||
|
||||
pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
Ref {
|
||||
_parent: orig._parent,
|
||||
_value: orig._value,
|
||||
_borrow: orig._borrow.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
struct BorrowRefMut<'b> {
|
||||
_borrow: &'b Cell<BorrowFlag>,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'b> Drop for BorrowRefMut<'b> {
|
||||
fn drop(&mut self) {
|
||||
let borrow = self._borrow.get();
|
||||
debug_assert!(borrow == WRITING);
|
||||
self._borrow.set(UNUSED);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> BorrowRefMut<'b> {
|
||||
fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
|
||||
match borrow.get() {
|
||||
UNUSED => {
|
||||
borrow.set(WRITING);
|
||||
Some(BorrowRefMut { _borrow: borrow })
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
|
||||
#[unstable]
|
||||
#[stable]
|
||||
pub struct RefMut<'b, T:'b> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_parent: &'b RefCell<T>
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[unstable]
|
||||
impl<'b, T> Drop for RefMut<'b, T> {
|
||||
fn drop(&mut self) {
|
||||
let borrow = self._parent.borrow.get();
|
||||
debug_assert!(borrow == WRITING);
|
||||
self._parent.borrow.set(UNUSED);
|
||||
}
|
||||
_value: &'b mut T,
|
||||
_borrow: BorrowRefMut<'b>,
|
||||
}
|
||||
|
||||
#[unstable = "waiting for `Deref` to become stable"]
|
||||
impl<'b, T> Deref<T> for RefMut<'b, T> {
|
||||
#[inline]
|
||||
fn deref<'a>(&'a self) -> &'a T {
|
||||
unsafe { &*self._parent.value.get() }
|
||||
self._value
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +476,7 @@ impl<'b, T> Deref<T> for RefMut<'b, T> {
|
||||
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
|
||||
#[inline]
|
||||
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
unsafe { &mut *self._parent.value.get() }
|
||||
self._value
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,7 +517,7 @@ impl<'b, T> DerefMut<T> for RefMut<'b, T> {
|
||||
/// is not recommended to access its fields directly, `get` should be used
|
||||
/// instead.
|
||||
#[lang="unsafe"]
|
||||
#[unstable = "this type may be renamed in the future"]
|
||||
#[stable]
|
||||
pub struct UnsafeCell<T> {
|
||||
/// Wrapped value
|
||||
///
|
||||
@ -499,21 +539,19 @@ impl<T> UnsafeCell<T> {
|
||||
}
|
||||
|
||||
/// Gets a mutable pointer to the wrapped value.
|
||||
///
|
||||
/// This function is unsafe as the pointer returned is an unsafe pointer and
|
||||
/// no guarantees are made about the aliasing of the pointers being handed
|
||||
/// out in this or other tasks.
|
||||
#[inline]
|
||||
#[unstable = "conventions around acquiring an inner reference are still \
|
||||
under development"]
|
||||
pub unsafe fn get(&self) -> *mut T { &self.value as *const T as *mut T }
|
||||
#[stable]
|
||||
pub fn get(&self) -> *mut T { &self.value as *const T as *mut T }
|
||||
|
||||
/// Unwraps the value
|
||||
///
|
||||
/// This function is unsafe because there is no guarantee that this or other
|
||||
/// tasks are currently inspecting the inner value.
|
||||
#[inline]
|
||||
#[unstable = "conventions around the name `unwrap` are still under \
|
||||
development"]
|
||||
pub unsafe fn unwrap(self) -> T { self.value }
|
||||
#[stable]
|
||||
pub unsafe fn into_inner(self) -> T { self.value }
|
||||
|
||||
/// Deprecated, use into_inner() instead
|
||||
#[deprecated = "renamed to into_inner()"]
|
||||
pub unsafe fn unwrap(self) -> T { self.into_inner() }
|
||||
}
|
||||
|
@ -15,10 +15,12 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![doc(primitive = "char")]
|
||||
|
||||
use iter::Iterator;
|
||||
use mem::transmute;
|
||||
use option::{None, Option, Some};
|
||||
use iter::{range_step, Iterator, RangeStep};
|
||||
use slice::SlicePrelude;
|
||||
use ops::FnMut;
|
||||
use option::Option::{None, Some};
|
||||
use option::Option;
|
||||
use slice::SliceExt;
|
||||
|
||||
// UTF-8 ranges and tags for encoding characters
|
||||
static TAG_CONT: u8 = 0b1000_0000u8;
|
||||
@ -64,7 +66,7 @@ static MAX_THREE_B: u32 = 0x10000u32;
|
||||
|
||||
/// The highest valid code point
|
||||
#[stable]
|
||||
pub const MAX: char = '\U0010ffff';
|
||||
pub const MAX: char = '\u{10ffff}';
|
||||
|
||||
/// Converts from `u32` to a `char`
|
||||
#[inline]
|
||||
@ -81,7 +83,7 @@ pub fn from_u32(i: u32) -> Option<char> {
|
||||
///
|
||||
/// Checks if a `char` parses as a numeric digit in the given radix
|
||||
///
|
||||
/// Compared to `is_digit()`, this function only recognizes the
|
||||
/// Compared to `is_numeric()`, this function only recognizes the
|
||||
/// characters `0-9`, `a-z` and `A-Z`.
|
||||
///
|
||||
/// # Return value
|
||||
@ -139,7 +141,7 @@ pub fn to_digit(c: char, radix: uint) -> Option<uint> {
|
||||
#[unstable = "pending decisions about costructors for primitives"]
|
||||
pub fn from_digit(num: uint, radix: uint) -> Option<char> {
|
||||
if radix > 36 {
|
||||
panic!("from_digit: radix is to high (maximum 36)");
|
||||
panic!("from_digit: radix is too high (maximum 36)");
|
||||
}
|
||||
if num < radix {
|
||||
unsafe {
|
||||
@ -154,36 +156,17 @@ pub fn from_digit(num: uint, radix: uint) -> Option<char> {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the hexadecimal Unicode escape of a `char`
|
||||
///
|
||||
/// The rules are as follows:
|
||||
///
|
||||
/// - chars in [0,0xff] get 2-digit escapes: `\\xNN`
|
||||
/// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
|
||||
/// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
|
||||
///
|
||||
/// Deprecated, call the escape_unicode method instead.
|
||||
#[deprecated = "use the Char::escape_unicode method"]
|
||||
pub fn escape_unicode(c: char, f: |char|) {
|
||||
pub fn escape_unicode<F>(c: char, mut f: F) where F: FnMut(char) {
|
||||
for char in c.escape_unicode() {
|
||||
f(char);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns a 'default' ASCII and C++11-like literal escape of a `char`
|
||||
///
|
||||
/// The default is chosen with a bias toward producing literals that are
|
||||
/// legal in a variety of languages, including C++11 and similar C-family
|
||||
/// languages. The exact rules are:
|
||||
///
|
||||
/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
|
||||
/// - Single-quote, double-quote and backslash chars are backslash-escaped.
|
||||
/// - Any other chars in the range [0x20,0x7e] are not escaped.
|
||||
/// - Any other chars are given hex Unicode escapes; see `escape_unicode`.
|
||||
///
|
||||
/// Deprecated, call the escape_default method instead.
|
||||
#[deprecated = "use the Char::escape_default method"]
|
||||
pub fn escape_default(c: char, f: |char|) {
|
||||
pub fn escape_default<F>(c: char, mut f: F) where F: FnMut(char) {
|
||||
for c in c.escape_default() {
|
||||
f(c);
|
||||
}
|
||||
@ -201,7 +184,7 @@ pub fn len_utf8_bytes(c: char) -> uint {
|
||||
pub trait Char {
|
||||
/// Checks if a `char` parses as a numeric digit in the given radix.
|
||||
///
|
||||
/// Compared to `is_digit()`, this function only recognizes the characters
|
||||
/// Compared to `is_numeric()`, this function only recognizes the characters
|
||||
/// `0-9`, `a-z` and `A-Z`.
|
||||
///
|
||||
/// # Return value
|
||||
@ -217,7 +200,7 @@ pub trait Char {
|
||||
|
||||
/// Checks if a `char` parses as a numeric digit in the given radix.
|
||||
///
|
||||
/// Compared to `is_digit()`, this function only recognizes the characters
|
||||
/// Compared to `is_numeric()`, this function only recognizes the characters
|
||||
/// `0-9`, `a-z` and `A-Z`.
|
||||
///
|
||||
/// # Return value
|
||||
@ -265,13 +248,11 @@ pub trait Char {
|
||||
/// Returns an iterator that yields the hexadecimal Unicode escape
|
||||
/// of a character, as `char`s.
|
||||
///
|
||||
/// The rules are as follows:
|
||||
///
|
||||
/// * Characters in [0,0xff] get 2-digit escapes: `\\xNN`
|
||||
/// * Characters in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`.
|
||||
/// * Characters above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`.
|
||||
/// All characters are escaped with Rust syntax of the form `\\u{NNNN}`
|
||||
/// where `NNNN` is the shortest hexadecimal representation of the code
|
||||
/// point.
|
||||
#[unstable = "pending error conventions, trait organization"]
|
||||
fn escape_unicode(self) -> UnicodeEscapedChars;
|
||||
fn escape_unicode(self) -> EscapeUnicode;
|
||||
|
||||
/// Returns an iterator that yields the 'default' ASCII and
|
||||
/// C++11-like literal escape of a character, as `char`s.
|
||||
@ -286,7 +267,7 @@ pub trait Char {
|
||||
/// * Any other chars in the range [0x20,0x7e] are not escaped.
|
||||
/// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
|
||||
#[unstable = "pending error conventions, trait organization"]
|
||||
fn escape_default(self) -> DefaultEscapedChars;
|
||||
fn escape_default(self) -> EscapeDefault;
|
||||
|
||||
/// Returns the amount of bytes this character would need if encoded in
|
||||
/// UTF-8.
|
||||
@ -356,23 +337,23 @@ impl Char for char {
|
||||
fn from_u32(i: u32) -> Option<char> { from_u32(i) }
|
||||
|
||||
#[unstable = "pending error conventions, trait organization"]
|
||||
fn escape_unicode(self) -> UnicodeEscapedChars {
|
||||
UnicodeEscapedChars { c: self, state: UnicodeEscapedCharsState::Backslash }
|
||||
fn escape_unicode(self) -> EscapeUnicode {
|
||||
EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash }
|
||||
}
|
||||
|
||||
#[unstable = "pending error conventions, trait organization"]
|
||||
fn escape_default(self) -> DefaultEscapedChars {
|
||||
fn escape_default(self) -> EscapeDefault {
|
||||
let init_state = match self {
|
||||
'\t' => DefaultEscapedCharsState::Backslash('t'),
|
||||
'\r' => DefaultEscapedCharsState::Backslash('r'),
|
||||
'\n' => DefaultEscapedCharsState::Backslash('n'),
|
||||
'\\' => DefaultEscapedCharsState::Backslash('\\'),
|
||||
'\'' => DefaultEscapedCharsState::Backslash('\''),
|
||||
'"' => DefaultEscapedCharsState::Backslash('"'),
|
||||
'\x20' ... '\x7e' => DefaultEscapedCharsState::Char(self),
|
||||
_ => DefaultEscapedCharsState::Unicode(self.escape_unicode())
|
||||
'\t' => EscapeDefaultState::Backslash('t'),
|
||||
'\r' => EscapeDefaultState::Backslash('r'),
|
||||
'\n' => EscapeDefaultState::Backslash('n'),
|
||||
'\\' => EscapeDefaultState::Backslash('\\'),
|
||||
'\'' => EscapeDefaultState::Backslash('\''),
|
||||
'"' => EscapeDefaultState::Backslash('"'),
|
||||
'\x20' ... '\x7e' => EscapeDefaultState::Char(self),
|
||||
_ => EscapeDefaultState::Unicode(self.escape_unicode())
|
||||
};
|
||||
DefaultEscapedChars { state: init_state }
|
||||
EscapeDefault { state: init_state }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -449,72 +430,87 @@ impl Char for char {
|
||||
|
||||
/// An iterator over the characters that represent a `char`, as escaped by
|
||||
/// Rust's unicode escaping rules.
|
||||
pub struct UnicodeEscapedChars {
|
||||
pub struct EscapeUnicode {
|
||||
c: char,
|
||||
state: UnicodeEscapedCharsState
|
||||
state: EscapeUnicodeState
|
||||
}
|
||||
|
||||
enum UnicodeEscapedCharsState {
|
||||
enum EscapeUnicodeState {
|
||||
Backslash,
|
||||
Type,
|
||||
Value(RangeStep<i32>),
|
||||
LeftBrace,
|
||||
Value(uint),
|
||||
RightBrace,
|
||||
Done,
|
||||
}
|
||||
|
||||
impl Iterator<char> for UnicodeEscapedChars {
|
||||
impl Iterator<char> for EscapeUnicode {
|
||||
fn next(&mut self) -> Option<char> {
|
||||
match self.state {
|
||||
UnicodeEscapedCharsState::Backslash => {
|
||||
self.state = UnicodeEscapedCharsState::Type;
|
||||
EscapeUnicodeState::Backslash => {
|
||||
self.state = EscapeUnicodeState::Type;
|
||||
Some('\\')
|
||||
}
|
||||
UnicodeEscapedCharsState::Type => {
|
||||
let (typechar, pad) = if self.c <= '\x7f' { ('x', 2) }
|
||||
else if self.c <= '\uffff' { ('u', 4) }
|
||||
else { ('U', 8) };
|
||||
self.state = UnicodeEscapedCharsState::Value(range_step(4 * (pad - 1), -1, -4i32));
|
||||
Some(typechar)
|
||||
EscapeUnicodeState::Type => {
|
||||
self.state = EscapeUnicodeState::LeftBrace;
|
||||
Some('u')
|
||||
}
|
||||
UnicodeEscapedCharsState::Value(ref mut range_step) => match range_step.next() {
|
||||
Some(offset) => {
|
||||
let offset = offset as uint;
|
||||
let v = match ((self.c as i32) >> offset) & 0xf {
|
||||
i @ 0 ... 9 => '0' as i32 + i,
|
||||
i => 'a' as i32 + (i - 10)
|
||||
};
|
||||
Some(unsafe { transmute(v) })
|
||||
EscapeUnicodeState::LeftBrace => {
|
||||
let mut n = 0u;
|
||||
while (self.c as u32) >> (4 * (n + 1)) != 0 {
|
||||
n += 1;
|
||||
}
|
||||
None => None
|
||||
self.state = EscapeUnicodeState::Value(n);
|
||||
Some('{')
|
||||
}
|
||||
EscapeUnicodeState::Value(offset) => {
|
||||
let v = match ((self.c as i32) >> (offset * 4)) & 0xf {
|
||||
i @ 0 ... 9 => '0' as i32 + i,
|
||||
i => 'a' as i32 + (i - 10)
|
||||
};
|
||||
if offset == 0 {
|
||||
self.state = EscapeUnicodeState::RightBrace;
|
||||
} else {
|
||||
self.state = EscapeUnicodeState::Value(offset - 1);
|
||||
}
|
||||
Some(unsafe { transmute(v) })
|
||||
}
|
||||
EscapeUnicodeState::RightBrace => {
|
||||
self.state = EscapeUnicodeState::Done;
|
||||
Some('}')
|
||||
}
|
||||
EscapeUnicodeState::Done => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the characters that represent a `char`, escaped
|
||||
/// for maximum portability.
|
||||
pub struct DefaultEscapedChars {
|
||||
state: DefaultEscapedCharsState
|
||||
pub struct EscapeDefault {
|
||||
state: EscapeDefaultState
|
||||
}
|
||||
|
||||
enum DefaultEscapedCharsState {
|
||||
enum EscapeDefaultState {
|
||||
Backslash(char),
|
||||
Char(char),
|
||||
Done,
|
||||
Unicode(UnicodeEscapedChars),
|
||||
Unicode(EscapeUnicode),
|
||||
}
|
||||
|
||||
impl Iterator<char> for DefaultEscapedChars {
|
||||
impl Iterator<char> for EscapeDefault {
|
||||
fn next(&mut self) -> Option<char> {
|
||||
match self.state {
|
||||
DefaultEscapedCharsState::Backslash(c) => {
|
||||
self.state = DefaultEscapedCharsState::Char(c);
|
||||
EscapeDefaultState::Backslash(c) => {
|
||||
self.state = EscapeDefaultState::Char(c);
|
||||
Some('\\')
|
||||
}
|
||||
DefaultEscapedCharsState::Char(c) => {
|
||||
self.state = DefaultEscapedCharsState::Done;
|
||||
EscapeDefaultState::Char(c) => {
|
||||
self.state = EscapeDefaultState::Done;
|
||||
Some(c)
|
||||
}
|
||||
DefaultEscapedCharsState::Done => None,
|
||||
DefaultEscapedCharsState::Unicode(ref mut iter) => iter.next()
|
||||
EscapeDefaultState::Done => None,
|
||||
EscapeDefaultState::Unicode(ref mut iter) => iter.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,26 +8,26 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*! The `Clone` trait for types that cannot be 'implicitly copied'
|
||||
//! The `Clone` trait for types that cannot be 'implicitly copied'
|
||||
//!
|
||||
//! In Rust, some simple types are "implicitly copyable" and when you
|
||||
//! assign them or pass them as arguments, the receiver will get a copy,
|
||||
//! leaving the original value in place. These types do not require
|
||||
//! allocation to copy and do not have finalizers (i.e. they do not
|
||||
//! contain owned boxes or implement `Drop`), so the compiler considers
|
||||
//! them cheap and safe to copy. For other types copies must be made
|
||||
//! explicitly, by convention implementing the `Clone` trait and calling
|
||||
//! the `clone` method.
|
||||
|
||||
In Rust, some simple types are "implicitly copyable" and when you
|
||||
assign them or pass them as arguments, the receiver will get a copy,
|
||||
leaving the original value in place. These types do not require
|
||||
allocation to copy and do not have finalizers (i.e. they do not
|
||||
contain owned boxes or implement `Drop`), so the compiler considers
|
||||
them cheap and safe to copy. For other types copies must be made
|
||||
explicitly, by convention implementing the `Clone` trait and calling
|
||||
the `clone` method.
|
||||
|
||||
*/
|
||||
|
||||
#![unstable]
|
||||
#![stable]
|
||||
|
||||
use kinds::Sized;
|
||||
|
||||
/// A common trait for cloning an object.
|
||||
#[stable]
|
||||
pub trait Clone {
|
||||
/// Returns a copy of the value.
|
||||
#[stable]
|
||||
fn clone(&self) -> Self;
|
||||
|
||||
/// Perform copy-assignment from `source`.
|
||||
@ -36,48 +36,50 @@ pub trait Clone {
|
||||
/// but can be overridden to reuse the resources of `a` to avoid unnecessary
|
||||
/// allocations.
|
||||
#[inline(always)]
|
||||
#[experimental = "this function is mostly unused"]
|
||||
#[unstable = "this function rarely unused"]
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
*self = source.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<'a, Sized? T> Clone for &'a T {
|
||||
/// Return a shallow copy of the reference.
|
||||
#[inline]
|
||||
fn clone(&self) -> &'a T { *self }
|
||||
}
|
||||
|
||||
macro_rules! clone_impl(
|
||||
macro_rules! clone_impl {
|
||||
($t:ty) => {
|
||||
#[stable]
|
||||
impl Clone for $t {
|
||||
/// Return a deep copy of the value.
|
||||
#[inline]
|
||||
fn clone(&self) -> $t { *self }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
clone_impl!(int)
|
||||
clone_impl!(i8)
|
||||
clone_impl!(i16)
|
||||
clone_impl!(i32)
|
||||
clone_impl!(i64)
|
||||
clone_impl! { int }
|
||||
clone_impl! { i8 }
|
||||
clone_impl! { i16 }
|
||||
clone_impl! { i32 }
|
||||
clone_impl! { i64 }
|
||||
|
||||
clone_impl!(uint)
|
||||
clone_impl!(u8)
|
||||
clone_impl!(u16)
|
||||
clone_impl!(u32)
|
||||
clone_impl!(u64)
|
||||
clone_impl! { uint }
|
||||
clone_impl! { u8 }
|
||||
clone_impl! { u16 }
|
||||
clone_impl! { u32 }
|
||||
clone_impl! { u64 }
|
||||
|
||||
clone_impl!(f32)
|
||||
clone_impl!(f64)
|
||||
clone_impl! { f32 }
|
||||
clone_impl! { f64 }
|
||||
|
||||
clone_impl!(())
|
||||
clone_impl!(bool)
|
||||
clone_impl!(char)
|
||||
clone_impl! { () }
|
||||
clone_impl! { bool }
|
||||
clone_impl! { char }
|
||||
|
||||
macro_rules! extern_fn_clone(
|
||||
macro_rules! extern_fn_clone {
|
||||
($($A:ident),*) => (
|
||||
#[experimental = "this may not be sufficient for fns with region parameters"]
|
||||
impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType {
|
||||
@ -86,15 +88,14 @@ macro_rules! extern_fn_clone(
|
||||
fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self }
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
extern_fn_clone!()
|
||||
extern_fn_clone!(A)
|
||||
extern_fn_clone!(A, B)
|
||||
extern_fn_clone!(A, B, C)
|
||||
extern_fn_clone!(A, B, C, D)
|
||||
extern_fn_clone!(A, B, C, D, E)
|
||||
extern_fn_clone!(A, B, C, D, E, F)
|
||||
extern_fn_clone!(A, B, C, D, E, F, G)
|
||||
extern_fn_clone!(A, B, C, D, E, F, G, H)
|
||||
}
|
||||
|
||||
extern_fn_clone! {}
|
||||
extern_fn_clone! { A }
|
||||
extern_fn_clone! { A, B }
|
||||
extern_fn_clone! { A, B, C }
|
||||
extern_fn_clone! { A, B, C, D }
|
||||
extern_fn_clone! { A, B, C, D, E }
|
||||
extern_fn_clone! { A, B, C, D, E, F }
|
||||
extern_fn_clone! { A, B, C, D, E, F, G }
|
||||
extern_fn_clone! { A, B, C, D, E, F, G, H }
|
||||
|
@ -41,10 +41,10 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
pub use self::Ordering::*;
|
||||
use self::Ordering::*;
|
||||
|
||||
use kinds::Sized;
|
||||
use option::{Option, Some, None};
|
||||
use option::Option::{mod, Some, None};
|
||||
|
||||
/// Trait for values that can be compared for equality and inequality.
|
||||
///
|
||||
@ -61,13 +61,13 @@ use option::{Option, Some, None};
|
||||
/// `Eq`.
|
||||
#[lang="eq"]
|
||||
#[unstable = "Definition may change slightly after trait reform"]
|
||||
pub trait PartialEq for Sized? {
|
||||
pub trait PartialEq<Sized? Rhs = Self> for Sized? {
|
||||
/// This method tests for `self` and `other` values to be equal, and is used by `==`.
|
||||
fn eq(&self, other: &Self) -> bool;
|
||||
fn eq(&self, other: &Rhs) -> bool;
|
||||
|
||||
/// This method tests for `!=`.
|
||||
#[inline]
|
||||
fn ne(&self, other: &Self) -> bool { !self.eq(other) }
|
||||
fn ne(&self, other: &Rhs) -> bool { !self.eq(other) }
|
||||
}
|
||||
|
||||
/// Trait for equality comparisons which are [equivalence relations](
|
||||
@ -80,7 +80,7 @@ pub trait PartialEq for Sized? {
|
||||
/// - symmetric: `a == b` implies `b == a`; and
|
||||
/// - transitive: `a == b` and `b == c` implies `a == c`.
|
||||
#[unstable = "Definition may change slightly after trait reform"]
|
||||
pub trait Eq for Sized?: PartialEq {
|
||||
pub trait Eq<Sized? Rhs = Self> for Sized?: PartialEq<Rhs> {
|
||||
// FIXME #13101: this method is used solely by #[deriving] to
|
||||
// assert that every component of a type implements #[deriving]
|
||||
// itself, the current deriving infrastructure means doing this
|
||||
@ -94,7 +94,7 @@ pub trait Eq for Sized?: PartialEq {
|
||||
}
|
||||
|
||||
/// An ordering is, e.g, a result of a comparison between two values.
|
||||
#[deriving(Clone, PartialEq, Show)]
|
||||
#[deriving(Clone, Copy, PartialEq, Show)]
|
||||
#[stable]
|
||||
pub enum Ordering {
|
||||
/// An ordering where a compared value is less [than another].
|
||||
@ -150,7 +150,7 @@ impl Ordering {
|
||||
/// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for
|
||||
/// both `==` and `>`.
|
||||
#[unstable = "Definition may change slightly after trait reform"]
|
||||
pub trait Ord for Sized?: Eq + PartialOrd {
|
||||
pub trait Ord<Sized? Rhs = Self> for Sized?: Eq<Rhs> + PartialOrd<Rhs> {
|
||||
/// This method returns an ordering between `self` and `other` values.
|
||||
///
|
||||
/// By convention, `self.cmp(&other)` returns the ordering matching
|
||||
@ -161,7 +161,7 @@ pub trait Ord for Sized?: Eq + PartialOrd {
|
||||
/// assert_eq!(10u.cmp(&5), Greater); // because 10 > 5
|
||||
/// assert_eq!( 5u.cmp(&5), Equal); // because 5 == 5
|
||||
/// ```
|
||||
fn cmp(&self, other: &Self) -> Ordering;
|
||||
fn cmp(&self, other: &Rhs) -> Ordering;
|
||||
}
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
@ -194,14 +194,14 @@ impl PartialOrd for Ordering {
|
||||
/// 5.11).
|
||||
#[lang="ord"]
|
||||
#[unstable = "Definition may change slightly after trait reform"]
|
||||
pub trait PartialOrd for Sized?: PartialEq {
|
||||
pub trait PartialOrd<Sized? Rhs = Self> for Sized?: PartialEq<Rhs> {
|
||||
/// This method returns an ordering between `self` and `other` values
|
||||
/// if one exists.
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering>;
|
||||
fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;
|
||||
|
||||
/// This method tests less than (for `self` and `other`) and is used by the `<` operator.
|
||||
#[inline]
|
||||
fn lt(&self, other: &Self) -> bool {
|
||||
fn lt(&self, other: &Rhs) -> bool {
|
||||
match self.partial_cmp(other) {
|
||||
Some(Less) => true,
|
||||
_ => false,
|
||||
@ -210,7 +210,7 @@ pub trait PartialOrd for Sized?: PartialEq {
|
||||
|
||||
/// This method tests less than or equal to (`<=`).
|
||||
#[inline]
|
||||
fn le(&self, other: &Self) -> bool {
|
||||
fn le(&self, other: &Rhs) -> bool {
|
||||
match self.partial_cmp(other) {
|
||||
Some(Less) | Some(Equal) => true,
|
||||
_ => false,
|
||||
@ -219,7 +219,7 @@ pub trait PartialOrd for Sized?: PartialEq {
|
||||
|
||||
/// This method tests greater than (`>`).
|
||||
#[inline]
|
||||
fn gt(&self, other: &Self) -> bool {
|
||||
fn gt(&self, other: &Rhs) -> bool {
|
||||
match self.partial_cmp(other) {
|
||||
Some(Greater) => true,
|
||||
_ => false,
|
||||
@ -228,7 +228,7 @@ pub trait PartialOrd for Sized?: PartialEq {
|
||||
|
||||
/// This method tests greater than or equal to (`>=`).
|
||||
#[inline]
|
||||
fn ge(&self, other: &Self) -> bool {
|
||||
fn ge(&self, other: &Rhs) -> bool {
|
||||
match self.partial_cmp(other) {
|
||||
Some(Greater) | Some(Equal) => true,
|
||||
_ => false,
|
||||
@ -240,7 +240,7 @@ pub trait PartialOrd for Sized?: PartialEq {
|
||||
/// of different types. The most common use case for this relation is
|
||||
/// container types; e.g. it is often desirable to be able to use `&str`
|
||||
/// values to look up entries in a container with `String` keys.
|
||||
#[experimental = "Better solutions may be discovered."]
|
||||
#[deprecated = "Use overloaded core::cmp::PartialEq"]
|
||||
pub trait Equiv<Sized? T> for Sized? {
|
||||
/// Implement this function to decide equivalent values.
|
||||
fn equiv(&self, other: &T) -> bool;
|
||||
@ -288,12 +288,13 @@ pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
|
||||
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
|
||||
mod impls {
|
||||
use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering,
|
||||
Less, Greater, Equal};
|
||||
use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
|
||||
use cmp::Ordering::{Less, Greater, Equal};
|
||||
use kinds::Sized;
|
||||
use option::{Option, Some, None};
|
||||
use option::Option;
|
||||
use option::Option::{Some, None};
|
||||
|
||||
macro_rules! partial_eq_impl(
|
||||
macro_rules! partial_eq_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl PartialEq for $t {
|
||||
@ -303,7 +304,7 @@ mod impls {
|
||||
fn ne(&self, other: &$t) -> bool { (*self) != (*other) }
|
||||
}
|
||||
)*)
|
||||
)
|
||||
}
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl PartialEq for () {
|
||||
@ -313,18 +314,20 @@ mod impls {
|
||||
fn ne(&self, _other: &()) -> bool { false }
|
||||
}
|
||||
|
||||
partial_eq_impl!(bool char uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64)
|
||||
partial_eq_impl! {
|
||||
bool char uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64
|
||||
}
|
||||
|
||||
macro_rules! eq_impl(
|
||||
macro_rules! eq_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl Eq for $t {}
|
||||
)*)
|
||||
)
|
||||
}
|
||||
|
||||
eq_impl!(() bool char uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
||||
eq_impl! { () bool char uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
|
||||
macro_rules! partial_ord_impl(
|
||||
macro_rules! partial_ord_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl PartialOrd for $t {
|
||||
@ -347,7 +350,7 @@ mod impls {
|
||||
fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
|
||||
}
|
||||
)*)
|
||||
)
|
||||
}
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl PartialOrd for () {
|
||||
@ -365,9 +368,9 @@ mod impls {
|
||||
}
|
||||
}
|
||||
|
||||
partial_ord_impl!(char uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64)
|
||||
partial_ord_impl! { char uint u8 u16 u32 u64 int i8 i16 i32 i64 f32 f64 }
|
||||
|
||||
macro_rules! ord_impl(
|
||||
macro_rules! ord_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl Ord for $t {
|
||||
@ -379,7 +382,7 @@ mod impls {
|
||||
}
|
||||
}
|
||||
)*)
|
||||
)
|
||||
}
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl Ord for () {
|
||||
@ -395,16 +398,16 @@ mod impls {
|
||||
}
|
||||
}
|
||||
|
||||
ord_impl!(char uint u8 u16 u32 u64 int i8 i16 i32 i64)
|
||||
ord_impl! { char uint u8 u16 u32 u64 int i8 i16 i32 i64 }
|
||||
|
||||
// & pointers
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl<'a, Sized? T: PartialEq> PartialEq for &'a T {
|
||||
impl<'a, 'b, Sized? A, Sized? B> PartialEq<&'b B> for &'a A where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: & &'a T) -> bool { PartialEq::eq(*self, *other) }
|
||||
fn eq(&self, other: & &'b B) -> bool { PartialEq::eq(*self, *other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: & &'a T) -> bool { PartialEq::ne(*self, *other) }
|
||||
fn ne(&self, other: & &'b B) -> bool { PartialEq::ne(*self, *other) }
|
||||
}
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl<'a, Sized? T: PartialOrd> PartialOrd for &'a T {
|
||||
@ -432,11 +435,11 @@ mod impls {
|
||||
// &mut pointers
|
||||
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl<'a, Sized? T: PartialEq> PartialEq for &'a mut T {
|
||||
impl<'a, 'b, Sized? A, Sized? B> PartialEq<&'b mut B> for &'a mut A where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&'a mut T) -> bool { PartialEq::eq(*self, *other) }
|
||||
fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &&'a mut T) -> bool { PartialEq::ne(*self, *other) }
|
||||
fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) }
|
||||
}
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl<'a, Sized? T: PartialOrd> PartialOrd for &'a mut T {
|
||||
@ -460,4 +463,18 @@ mod impls {
|
||||
}
|
||||
#[unstable = "Trait is unstable."]
|
||||
impl<'a, Sized? T: Eq> Eq for &'a mut T {}
|
||||
|
||||
impl<'a, 'b, Sized? A, Sized? B> PartialEq<&'b mut B> for &'a A where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) }
|
||||
}
|
||||
|
||||
impl<'a, 'b, Sized? A, Sized? B> PartialEq<&'b B> for &'a mut A where A: PartialEq<B> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&'b B) -> bool { PartialEq::eq(*self, *other) }
|
||||
#[inline]
|
||||
fn ne(&self, other: &&'b B) -> bool { PartialEq::ne(*self, *other) }
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@
|
||||
/// bar: f32,
|
||||
/// }
|
||||
/// ```
|
||||
#[stable]
|
||||
pub trait Default {
|
||||
/// Returns the "default value" for a type.
|
||||
///
|
||||
@ -130,33 +131,37 @@ pub trait Default {
|
||||
/// fn default() -> Kind { Kind::A }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable]
|
||||
fn default() -> Self;
|
||||
}
|
||||
|
||||
macro_rules! default_impl(
|
||||
macro_rules! default_impl {
|
||||
($t:ty, $v:expr) => {
|
||||
#[stable]
|
||||
impl Default for $t {
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn default() -> $t { $v }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
default_impl!((), ())
|
||||
default_impl!(bool, false)
|
||||
default_impl!(char, '\x00')
|
||||
default_impl! { (), () }
|
||||
default_impl! { bool, false }
|
||||
default_impl! { char, '\x00' }
|
||||
|
||||
default_impl!(uint, 0u)
|
||||
default_impl!(u8, 0u8)
|
||||
default_impl!(u16, 0u16)
|
||||
default_impl!(u32, 0u32)
|
||||
default_impl!(u64, 0u64)
|
||||
default_impl! { uint, 0u }
|
||||
default_impl! { u8, 0u8 }
|
||||
default_impl! { u16, 0u16 }
|
||||
default_impl! { u32, 0u32 }
|
||||
default_impl! { u64, 0u64 }
|
||||
|
||||
default_impl!(int, 0i)
|
||||
default_impl!(i8, 0i8)
|
||||
default_impl!(i16, 0i16)
|
||||
default_impl!(i32, 0i32)
|
||||
default_impl!(i64, 0i64)
|
||||
default_impl! { int, 0i }
|
||||
default_impl! { i8, 0i8 }
|
||||
default_impl! { i16, 0i16 }
|
||||
default_impl! { i32, 0i32 }
|
||||
default_impl! { i64, 0i64 }
|
||||
|
||||
default_impl! { f32, 0.0f32 }
|
||||
default_impl! { f64, 0.0f64 }
|
||||
|
||||
default_impl!(f32, 0.0f32)
|
||||
default_impl!(f64, 0.0f64)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user