Merge branch 'master' into cfg_tmp_dir

Conflicts:
	src/etc/rustup.sh
This commit is contained in:
Johannes Hoff 2014-12-24 13:22:11 +01:00
commit 0128159c95
1456 changed files with 71160 additions and 61577 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -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>

View File

@ -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
View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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.

View File

@ -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
View 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))))))

View File

@ -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 -----------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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)))))

View File

@ -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

View File

@ -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)))))

View File

@ -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)

View File

@ -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))

View File

@ -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:

View File

@ -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 $$@

View File

@ -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)):

View File

@ -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.

View File

@ -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 {

View File

@ -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 '{}'",

View File

@ -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, }))
})
}

View File

@ -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;
}

View File

@ -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)
}

View File

@ -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.

View File

@ -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!

View File

@ -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

View File

@ -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;

View File

@ -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
```

View File

@ -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
Weve seen a few examples of borrowing data. To this point, weve 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`.
Lets 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 dont 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.

View File

@ -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
View 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.

View File

@ -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

View File

@ -181,7 +181,7 @@ for l in s.graphemes(true) {
This prints:
```{notrust,ignore}
```{text}
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

View File

@ -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());
```

View File

@ -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.
```

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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();
}
}
```

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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() }

View File

@ -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 ()

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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")

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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,

View File

@ -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

View File

@ -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());

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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), "{}");
}
}

View File

@ -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)]

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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};

View File

@ -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))

View File

@ -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
}

View File

@ -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.

View File

@ -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),
}
}
}

View File

@ -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() }
}

View File

@ -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()
}
}
}

View File

@ -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 }

View File

@ -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) }
}
}

View File

@ -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