Merge remote-tracking branch 'mozilla/incoming' into issue-5910-dyna-freeze

Conflicts:
	src/libcore/core.rc
	src/libcore/hashmap.rs
	src/libcore/num/f32.rs
	src/libcore/num/f64.rs
	src/libcore/num/float.rs
	src/libcore/num/int-template.rs
	src/libcore/num/num.rs
	src/libcore/num/strconv.rs
	src/libcore/num/uint-template.rs
	src/libcore/ops.rs
	src/libcore/os.rs
	src/libcore/prelude.rs
	src/libcore/rt/mod.rs
	src/libcore/unstable/lang.rs
	src/librustc/driver/session.rs
	src/librustc/middle/astencode.rs
	src/librustc/middle/borrowck/check_loans.rs
	src/librustc/middle/borrowck/gather_loans.rs
	src/librustc/middle/borrowck/loan.rs
	src/librustc/middle/borrowck/preserve.rs
	src/librustc/middle/liveness.rs
	src/librustc/middle/mem_categorization.rs
	src/librustc/middle/region.rs
	src/librustc/middle/trans/base.rs
	src/librustc/middle/trans/inline.rs
	src/librustc/middle/trans/reachable.rs
	src/librustc/middle/typeck/check/_match.rs
	src/librustc/middle/typeck/check/regionck.rs
	src/librustc/util/ppaux.rs
	src/libstd/arena.rs
	src/libstd/ebml.rs
	src/libstd/json.rs
	src/libstd/serialize.rs
	src/libstd/std.rc
	src/libsyntax/ast_map.rs
	src/libsyntax/parse/parser.rs
	src/test/compile-fail/borrowck-uniq-via-box.rs
	src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs
	src/test/run-pass/borrowck-nested-calls.rs
This commit is contained in:
Niko Matsakis 2013-05-05 15:11:04 -04:00
commit 4300d4d2fa
661 changed files with 7136 additions and 5629 deletions

9
.gitattributes vendored Normal file
View File

@ -0,0 +1,9 @@
[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
* text=auto
*.cpp rust
*.h rust
*.rs rust
src/rt/msvc/* -whitespace
src/rt/vg/* -whitespace
src/rt/linenoise/* -whitespace

View File

@ -367,4 +367,3 @@ their own copyright notices and license terms:
has chosen for the collective work, enumerated at the top
of this file. The only difference is the retention of
copyright itself, held by the contributor.

View File

@ -241,7 +241,7 @@ $(foreach target,$(CFG_TARGET_TRIPLES),\
CORELIB_CRATE := $(S)src/libcore/core.rc
CORELIB_INPUTS := $(wildcard $(addprefix $(S)src/libcore/, \
core.rc *.rs */*.rs */*/*rs))
core.rc *.rs */*.rs */*/*rs */*/*/*rs))
######################################################################
# Standard library variables

View File

@ -250,7 +250,7 @@ Version 0.3 (July 2012)
* Slices and fixed-size, interior-allocated vectors
* #!-comments for lang versioning, shell execution
* Destructors and iface implementation for classes;
type-parameterized classes and class methods
type-parameterized classes and class methods
* 'const' type kind for types that can be used to implement
shared-memory concurrency patterns
@ -261,7 +261,7 @@ Version 0.3 (July 2012)
'crust', 'native' (now 'extern'), 'cont' (now 'again')
* Constructs: do-while loops ('do' repurposed), fn binding,
resources (replaced by destructors)
resources (replaced by destructors)
* Compiler reorganization
* Syntax-layer of compiler split into separate crate
@ -276,7 +276,7 @@ Version 0.3 (July 2012)
* Extensive work on libuv interface
* Much vector code moved to libraries
* Syntax extensions: #line, #col, #file, #mod, #stringify,
#include, #include_str, #include_bin
#include, #include_str, #include_bin
* Tool improvements
* Cargo automatically resolves dependencies

View File

@ -1,6 +1,6 @@
The markdown docs are only generated by make when node is installed (use
`make doc`). If you don't have node installed you can generate them yourself.
Unfortunately there's no real standard for markdown and all the tools work
`make doc`). If you don't have node installed you can generate them yourself.
Unfortunately there's no real standard for markdown and all the tools work
differently. pandoc is one that seems to work well.
To generate an html version of a doc do something like:
@ -10,4 +10,4 @@ The syntax for pandoc flavored markdown can be found at:
http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown
A nice quick reference (for non-pandoc markdown) is at:
http://kramdown.rubyforge.org/quickref.html
http://kramdown.rubyforge.org/quickref.html

View File

@ -1467,8 +1467,8 @@ A complete list of the built-in language items follows:
: Elements can be subtracted.
`mul`
: Elements can be multiplied.
`quot`
: Elements have a quotient operation.
`div`
: Elements have a division operation.
`rem`
: Elements have a remainder operation.
`neg`
@ -1857,7 +1857,7 @@ The default meaning of the operators on standard types is given here.
Calls the `mul` method on the `core::ops::Mul` trait.
`/`
: Quotient.
Calls the `quot` method on the `core::ops::Quot` trait.
Calls the `div` method on the `core::ops::Div` trait.
`%`
: Remainder.
Calls the `rem` method on the `core::ops::Rem` trait.
@ -2393,7 +2393,7 @@ variables in the arm's block, and control enters the block.
An example of an `match` expression:
~~~~ {.xfail-test}
~~~~
# fn process_pair(a: int, b: int) { }
# fn process_ten() { }
@ -3351,4 +3351,3 @@ Additional specific influences can be seen from the following languages:
* The typeclass system of Haskell.
* The lexical identifier rule of Python.
* The block syntax of Ruby.

View File

@ -150,11 +150,7 @@ wrapping `malloc` and `free`:
~~~~
use core::libc::{c_void, size_t, malloc, free};
#[abi = "rust-intrinsic"]
extern "rust-intrinsic" mod rusti {
fn init<T>() -> T;
}
use core::unstable::intrinsics;
// a wrapper around the handle returned by the foreign code
pub struct Unique<T> {
@ -166,7 +162,8 @@ pub impl<'self, T: Owned> Unique<T> {
unsafe {
let ptr = malloc(core::sys::size_of::<T>() as size_t) as *mut T;
assert!(!ptr::is_null(ptr));
*ptr = value;
// `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
intrinsics::move_val_init(&mut *ptr, value);
Unique{ptr: ptr}
}
}
@ -186,7 +183,7 @@ pub impl<'self, T: Owned> Unique<T> {
impl<T: Owned> Drop for Unique<T> {
fn finalize(&self) {
unsafe {
let mut x = rusti::init(); // dummy value to swap in
let mut x = intrinsics::init(); // dummy value to swap in
x <-> *self.ptr; // moving the object out is needed to call the destructor
free(self.ptr as *c_void)
}

View File

@ -402,4 +402,3 @@ tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
states, invoking `trace_macros!(true)` will automatically print those
intermediate states out, and passing the flag `--pretty expanded` as a
command-line argument to the compiler will show the result of expansion.

View File

@ -511,4 +511,3 @@ The parent task first calls `DuplexStream` to create a pair of bidirectional
endpoints. It then uses `task::spawn` to create the child task, which captures
one end of the communication channel. As a result, both parent and child can
send and receive data to and from the other.

View File

@ -1006,9 +1006,9 @@ let mut d = @mut 5; // mutable variable, mutable box
d = @mut 15;
~~~~
A mutable variable and an immutable variable can refer to the same box, given
that their types are compatible. Mutability of a box is a property of its type,
however, so for example a mutable handle to an immutable box cannot be
A mutable variable and an immutable variable can refer to the same box, given
that their types are compatible. Mutability of a box is a property of its type,
however, so for example a mutable handle to an immutable box cannot be
assigned a reference to a mutable box.
~~~~
@ -1041,7 +1041,7 @@ let y = x.clone(); // y is a newly allocated box
let z = x; // no new memory allocated, x can no longer be used
~~~~
Since in owned boxes mutability is a property of the owner, not the
Since in owned boxes mutability is a property of the owner, not the
box, mutable boxes may become immutable when they are moved, and vice-versa.
~~~~

View File

@ -7,4 +7,3 @@
</center>
</div>

View File

@ -48,7 +48,7 @@ clean-misc:
$(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF)
$(Q)rm -Rf $(DOCS)
$(Q)rm -Rf $(GENERATED)
$(Q)rm -f tmp/*.log tmp/*.rc tmp/*.rs tmp/*.ok
$(Q)rm -f tmp/*
$(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist
$(Q)rm -Rf $(foreach ext, \
html aux cp fn ky log pdf pg toc tp vr cps, \

View File

@ -16,15 +16,8 @@ DOCS :=
######################################################################
# Pandoc (reference-manual related)
# Docs, from pandoc, rustdoc (which runs pandoc), and node
######################################################################
ifeq ($(CFG_PANDOC),)
$(info cfg: no pandoc found, omitting doc/rust.pdf)
else
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting doc/tutorial.html)
else
doc/rust.css: rust.css
@$(call E, cp: $@)
@ -34,6 +27,18 @@ doc/manual.css: manual.css
@$(call E, cp: $@)
$(Q)cp -a $< $@ 2> /dev/null
ifeq ($(CFG_PANDOC),)
$(info cfg: no pandoc found, omitting docs)
NO_DOCS = 1
endif
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting docs)
NO_DOCS = 1
endif
ifneq ($(NO_DOCS),1)
DOCS += doc/rust.html
doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
@$(call E, pandoc: $@)
@ -47,19 +52,8 @@ doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css
--css=manual.css \
--include-before-body=doc/version_info.html \
--output=$@
endif
ifeq ($(CFG_PDFLATEX),)
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
else
ifeq ($(CFG_XETEX),)
$(info cfg: no xetex found, disabling doc/rust.pdf)
else
ifeq ($(CFG_LUATEX),)
$(info cfg: lacking luatex, disabling pdflatex)
else
DOCS += doc/rust.pdf
DOCS += doc/rust.tex
doc/rust.tex: rust.md doc/version.md
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js $< | \
@ -70,17 +64,6 @@ doc/rust.tex: rust.md doc/version.md
--from=markdown --to=latex \
--output=$@
doc/rust.pdf: doc/rust.tex
@$(call E, pdflatex: $@)
$(Q)$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$<
endif
endif
endif
DOCS += doc/rustpkg.html
doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css
@$(call E, pandoc: $@)
@ -95,13 +78,6 @@ doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css
--include-before-body=doc/version_info.html \
--output=$@
######################################################################
# Node (tutorial related)
######################################################################
ifeq ($(CFG_NODE),)
$(info cfg: no node found, omitting doc/tutorial.html)
else
DOCS += doc/tutorial.html
doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css
@$(call E, pandoc: $@)
@ -153,9 +129,29 @@ doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css
--include-before-body=doc/version_info.html \
--output=$@
endif
endif
ifeq ($(CFG_PDFLATEX),)
$(info cfg: no pdflatex found, omitting doc/rust.pdf)
else
ifeq ($(CFG_XETEX),)
$(info cfg: no xetex found, disabling doc/rust.pdf)
else
ifeq ($(CFG_LUATEX),)
$(info cfg: lacking luatex, disabling pdflatex)
else
DOCS += doc/rust.pdf
doc/rust.pdf: doc/rust.tex
@$(call E, pdflatex: $@)
$(Q)$(CFG_PDFLATEX) \
-interaction=batchmode \
-output-directory=doc \
$<
endif
endif
endif
endif # No pandoc / node
######################################################################
# LLnextgen (grammar analysis from refman)

View File

@ -29,7 +29,9 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
| $$(HBIN$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
@ -39,7 +41,9 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \
@ -51,7 +55,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \
$$(HCORELIB_DEFAULT$(2)_H_$(4)) \
$$(HSTDLIB_DEFAULT$(2)_H_$(4))
$$(HSTDLIB_DEFAULT$(2)_H_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \
@ -59,13 +64,15 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \
$$(HLIB$(2)_H_$(4))
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4))
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
# Subtle: We do not let the shell expand $(CORELIB_DSYM_GLOB) directly rather
@ -82,7 +89,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \
$$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \
@ -91,14 +99,16 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \
$$(HLIB$(2)_H_$(4))/libcore.rlib: \
$$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/libstd.rlib: \
$$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \
$$(HLIB$(2)_H_$(4))/libcore.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
@ -106,15 +116,23 @@ $$(HLIB$(2)_H_$(4))/librustc.rlib: \
$$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \
$$(HLIB$(2)_H_$(4))/libcore.rlib \
$$(HLIB$(2)_H_$(4))/libstd.rlib \
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4))
$$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4))
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \
| $$(HLIB$(2)_H_$(4))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(HBIN$(2)_H_$(4))/:
mkdir -p $$@
$$(HLIB$(2)_H_$(4))/:
mkdir -p $$@
endef
$(foreach t,$(CFG_HOST_TRIPLES), \

View File

@ -11,7 +11,7 @@
# Create variables HOST_<triple> containing the host part
# of each target triple. For example, the triple i686-darwin-macos
# would create a variable HOST_i686-darwin-macos with the value
# would create a variable HOST_i686-darwin-macos with the value
# i386.
define DEF_HOST_VAR
HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1))))
@ -276,8 +276,8 @@ CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -march=i686
CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 :=
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 :=
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 :=
CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def
CFG_INSTALL_NAME_i686-pc-mingw32 =
CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi

View File

@ -1,27 +1,27 @@
# This is a procedure to define the targets for building
# the runtime.
# the runtime.
#
# Argument 1 is the target triple.
#
# This is not really the right place to explain this, but
# for those of you who are not Makefile gurus, let me briefly
# cover the $ expansion system in use here, because it
# cover the $ expansion system in use here, because it
# confused me for a while! The variable DEF_RUNTIME_TARGETS
# will be defined once and then expanded with different
# values substituted for $(1) each time it is called.
# That resulting text is then eval'd.
# That resulting text is then eval'd.
#
# For most variables, you could use a single $ sign. The result
# is that the substitution would occur when the CALL occurs,
# I believe. The problem is that the automatic variables $< and $@
# need to be expanded-per-rule. Therefore, for those variables at
# least, you need $$< and $$@ in the variable text. This way, after
# least, you need $$< and $$@ in the variable text. This way, after
# the CALL substitution occurs, you will have $< and $@. This text
# will then be evaluated, and all will work as you like.
#
# Reader beware, this explanantion could be wrong, but it seems to
# fit the experimental data (i.e., I was able to get the system
# working under these assumptions).
# fit the experimental data (i.e., I was able to get the system
# working under these assumptions).
# Hack for passing flags into LIBUV, see below.
LIBUV_FLAGS_i386 = -m32 -fPIC
@ -163,14 +163,16 @@ endif
ifdef CFG_WINDOWSY_$(1)
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(CFG_GCCISH_CFLAGS)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS)" \
builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \
OS=mingw \
V=$$(VERBOSE)
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
@ -181,8 +183,8 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
else
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
$$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \

View File

@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \
$(S)src/etc/get-snapshot.py $(MKFILE_DEPS)
@$(call E, fetch: $@)
# Note: the variable "SNAPSHOT_FILE" is generally not set, and so
# we generally only pass one argument to this script.
# we generally only pass one argument to this script.
ifdef CFG_ENABLE_LOCAL_RUST
$(Q)$(S)src/etc/local_stage0.sh $(CFG_BUILD_TRIPLE) $(CFG_LOCAL_RUST_ROOT)
else
else
$(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD_TRIPLE) $(SNAPSHOT_FILE)
ifdef CFG_ENABLE_PAX_FLAGS
@$(call E, apply PaX flags: $@)
@"$(CFG_PAXCTL)" -cm "$@"
endif
endif
endif
$(Q)touch $@
# Host libs will be extracted by the above rule

View File

@ -18,25 +18,29 @@
define TARGET_STAGE_N
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a
rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \
rt/$(2)/$(CFG_RUNTIME_$(2))
rt/$(2)/$(CFG_RUNTIME_$(2)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)): \
$$(CORELIB_CRATE) $$(CORELIB_INPUTS) \
$$(TSREQ$(1)_T_$(2)_H_$(3))
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \
$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \
$$(TSREQ$(1)_T_$(2)_H_$(3))
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
@ -44,7 +48,8 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
$$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3))
$$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@
@ -52,20 +57,23 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \
ifneq ($$(findstring $(2),$$(CFG_HOST_TRIPLES)),)
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \
rustllvm/$(2)/$(CFG_RUSTLLVM_$(3))
rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \
$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \
| $$(TLIB$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@
$$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \
$$(DRIVER_CRATE) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3))
$$(DRIVER_CRATE) \
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \
| $$(TBIN$(1)_T_$(2)_H_$(3))/
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$<
ifdef CFG_ENABLE_PAX_FLAGS
@ -75,6 +83,12 @@ endif
endif
$$(TBIN$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
$$(TLIB$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
endef
# In principle, each host can build each target:

View File

@ -179,9 +179,9 @@ tidy:
$(Q)find $(S)src/etc -name '*.py' \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)echo $(ALL_CS) \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
$(Q)echo $(ALL_HS) \
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
| xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py
endif
@ -709,4 +709,3 @@ endef
$(foreach host,$(CFG_HOST_TRIPLES), \
$(eval $(call DEF_CHECK_FAST_FOR_H,$(host))))

View File

@ -223,10 +223,3 @@ pub fn make_test_closure(config: config, testfile: &Path) -> test::TestFn {
let testfile = testfile.to_str();
test::DynTestFn(|| runtest::run(config, testfile))
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -9,7 +9,7 @@ my $anchors = {};
my $i = 0;
foreach $line (@lines) {
$i++;
if ($line =~ m/id="([^"]+)"/) {
if ($line =~ m/id="([^"]+)"/) {
$anchors->{$1} = $i;
}
}
@ -17,10 +17,9 @@ foreach $line (@lines) {
$i = 0;
foreach $line (@lines) {
$i++;
while ($line =~ m/href="#([^"]+)"/g) {
while ($line =~ m/href="#([^"]+)"/g) {
if (! exists($anchors->{$1})) {
print "$file:$i: $1 referenced\n";
}
}
}

View File

@ -8,4 +8,3 @@ Instructions for Ubuntu Linux 12.04+
2) Copy the included "share" folder into "~/.local/"
3) Open a shell in "~/.local/share/" and run "update-mime-database mime"

View File

@ -123,11 +123,11 @@
<keyword>mode_t</keyword>
<keyword>ssize_t</keyword>
</context>
<context id="self" style-ref="identifier">
<keyword>self</keyword>
</context>
<context id="constants" style-ref="constant">
<keyword>true</keyword>
<keyword>false</keyword>
@ -261,4 +261,3 @@
</definitions>
</language>

View File

@ -2,6 +2,6 @@
<mime-type type="text/x-rust">
<comment>Rust Source</comment>
<glob pattern="*.rs"/>
<glob pattern="*.rc"/>
<glob pattern="*.rc"/>
</mime-type>
</mime-info>

View File

@ -14,4 +14,3 @@ while (<>) {
$indent -= 1;
}
}

View File

@ -52,5 +52,3 @@ def download_new_file (date, rev, platform, hsh):
for ff in newestSet["files"]:
download_new_file (newestSet["date"], newestSet["rev"],
ff["platform"], ff["hash"])

View File

@ -243,4 +243,3 @@ int main() {
extra_consts();
printf("}\n");
}

View File

@ -96,4 +96,3 @@ def check_license(name, contents):
return True
return False

View File

@ -1,13 +1,13 @@
#!/bin/sh
TARG_DIR=$1
TARG_DIR=$1
PREFIX=$2
BINDIR=bin
LIBDIR=lib
OS=`uname -s`
case $OS in
case $OS in
("Linux"|"FreeBSD")
BIN_SUF=
LIB_SUF=.so

View File

@ -33,6 +33,3 @@ for line in f.readlines():
print("got download with ok hash")
else:
raise Exception("bad hash on download")

View File

@ -77,4 +77,3 @@ while (my ($key, $substs) = each %funcs) {
}
print "\n";
}

View File

@ -80,4 +80,3 @@ def sugarise_file(path):
for (dirpath, dirnames, filenames) in os.walk('.'):
for name in fnmatch.filter(filenames, '*.r[sc]'):
sugarise_file(os.path.join(dirpath, name))

View File

@ -81,4 +81,3 @@ except UnicodeDecodeError, e:
sys.exit(err)

View File

@ -235,6 +235,10 @@ for i in [r]:
rf = open(r, "w")
(canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt")
# Explain that the source code was generated by this script.
rf.write('// The following code was generated by "src/etc/unicode.py"\n\n')
emit_property_module(rf, "general_category", gencats)
#emit_decomp_module(rf, canon_decomp, compat_decomp)

View File

@ -366,7 +366,7 @@
...
}
{
{
llvm-user-new-leak
Memcheck:Leak
fun:_Znwj
@ -401,7 +401,7 @@
Helgrind:Race
fun:_ZN15lock_and_signal27lock_held_by_current_threadEv
...
}
}
{
lock_and_signal-probably-threadsafe-access-outside-of-lock2

121
src/etc/ziggurat_tables.py Executable file
View File

@ -0,0 +1,121 @@
#!/usr/bin/env python
# xfail-license
# This creates the tables used for distributions implemented using the
# ziggurat algorithm in `core::rand::distributions;`. They are
# (basically) the tables as used in the ZIGNOR variant (Doornik 2005).
# They are changed rarely, so the generated file should be checked in
# to git.
#
# It creates 3 tables: X as in the paper, F which is f(x_i), and
# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached
# values which is not done in that paper (but is done in other
# variants). Note that the adZigR table is unnecessary because of
# algebra.
#
# It is designed to be compatible with Python 2 and 3.
from math import exp, sqrt, log, floor
import random
# The order should match the return value of `tables`
TABLE_NAMES = ['X', 'F', 'F_DIFF']
# The actual length of the table is 1 more, to stop
# index-out-of-bounds errors. This should match the bitwise operation
# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and
# *_V constants below depend on this value.
TABLE_LEN = 256
# equivalent to `zigNorInit` in Doornik2005, but generalised to any
# distribution. r = dR, v = dV, f = probability density function,
# f_inv = inverse of f
def tables(r, v, f, f_inv):
# compute the x_i
xvec = [0]*(TABLE_LEN+1)
xvec[0] = v / f(r)
xvec[1] = r
for i in range(2, TABLE_LEN):
last = xvec[i-1]
xvec[i] = f_inv(v / last + f(last))
# cache the f's
fvec = [0]*(TABLE_LEN+1)
fdiff = [0]*(TABLE_LEN+1)
for i in range(TABLE_LEN+1):
fvec[i] = f(xvec[i])
if i > 0:
fdiff[i] = fvec[i] - fvec[i-1]
return xvec, fvec, fdiff
# Distributions
# N(0, 1)
def norm_f(x):
return exp(-x*x/2.0)
def norm_f_inv(y):
return sqrt(-2.0*log(y))
NORM_R = 3.6541528853610088
NORM_V = 0.00492867323399
NORM = tables(NORM_R, NORM_V,
norm_f, norm_f_inv)
# Exp(1)
def exp_f(x):
return exp(-x)
def exp_f_inv(y):
return -log(y)
EXP_R = 7.69711747013104972
EXP_V = 0.0039496598225815571993
EXP = tables(EXP_R, EXP_V,
exp_f, exp_f_inv)
# Output the tables/constants/types
def render_static(name, type, value):
# no space or
return 'pub static %s: %s =%s;\n' % (name, type, value)
# static `name`: [`type`, .. `len(values)`] =
# [values[0], ..., values[3],
# values[4], ..., values[7],
# ... ];
def render_table(name, values):
rows = []
# 4 values on each row
for i in range(0, len(values), 4):
row = values[i:i+4]
rows.append(', '.join('%.18f' % f for f in row))
rendered = '\n [%s]' % ',\n '.join(rows)
return render_static(name, '[f64, .. %d]' % len(values), rendered)
with open('ziggurat_tables.rs', 'w') as f:
f.write('''// Copyright 2013 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.
// Tables for distributions which are sampled using the ziggurat
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &\'static [f64, .. %d];
''' % (TABLE_LEN + 1))
for name, tables, r in [('NORM', NORM, NORM_R),
('EXP', EXP, EXP_R)]:
f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r))
for (tabname, table) in zip(TABLE_NAMES, tables):
f.write(render_table('ZIG_%s_%s' % (name, tabname), table))

View File

@ -108,8 +108,6 @@ mod tests {
#[test]
fn test_bool_from_str() {
use from_str::FromStr;
do all_values |v| {
assert!(Some(v) == FromStr::from_str(to_str(v)))
}

View File

@ -19,35 +19,11 @@ pub mod rusti {
pub extern "rust-intrinsic" {
fn forget<T>(+x: T);
#[cfg(stage0)]
fn reinterpret_cast<T, U>(&&e: T) -> U;
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn transmute<T,U>(e: T) -> U;
}
}
/// Casts the value at `src` to U. The two types must have the same length.
#[inline(always)]
#[cfg(stage0)]
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
rusti::reinterpret_cast(*src)
}
/// Unsafely copies and casts the value at `src` to U, even if the value is
/// noncopyable. The two types must have the same length.
#[inline(always)]
#[cfg(stage0)]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
rusti::reinterpret_cast(*src)
}
#[inline(always)]
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
let mut dest: U = unstable::intrinsics::init();
{
@ -88,17 +64,6 @@ pub unsafe fn bump_box_refcount<T>(t: @T) { forget(t); }
* assert!(transmute("L") == ~[76u8, 0u8]);
*/
#[inline(always)]
#[cfg(stage0)]
pub unsafe fn transmute<L, G>(thing: L) -> G {
let newthing: G = reinterpret_cast(&thing);
forget(thing);
newthing
}
#[inline(always)]
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
pub unsafe fn transmute<L, G>(thing: L) -> G {
rusti::transmute(thing)
}
@ -159,15 +124,6 @@ mod tests {
use cast::{bump_box_refcount, transmute};
#[test]
#[cfg(stage0)]
fn test_reinterpret_cast() {
assert!(1u == unsafe { ::cast::reinterpret_cast(&1) });
}
#[test]
#[cfg(stage1)]
#[cfg(stage2)]
#[cfg(stage3)]
fn test_transmute_copy() {
assert!(1u == unsafe { ::cast::transmute_copy(&1) });
}

View File

@ -10,6 +10,7 @@
//! Utilities for manipulating the char type
#[cfg(notest)]
use cmp::Ord;
use option::{None, Option, Some};
use str;

View File

@ -258,4 +258,3 @@ pub mod rustrt {
pub unsafe fn rust_get_task() -> *c_void;
}
}

View File

@ -192,4 +192,27 @@ mod test {
assert!(trapped);
}
// Issue #6009
mod m {
condition! {
sadness: int -> int;
}
mod n {
use super::sadness;
#[test]
fn test_conditions_are_public() {
let mut trapped = false;
do sadness::cond.trap(|_| {
trapped = true;
0
}).in {
sadness::cond.raise(0);
}
assert!(trapped);
}
}
}
}

View File

@ -63,7 +63,6 @@ they contained the following prologue:
#[warn(vecs_implicitly_copyable)];
#[deny(non_camel_case_types)];
#[allow(deprecated_mutable_fields)];
#[allow(deprecated_drop)];
// Make core testable by not duplicating lang items. See #2912
#[cfg(test)] extern mod realcore(name = "core", vers = "0.7-pre");
@ -75,7 +74,7 @@ they contained the following prologue:
pub use kinds::{Const, Copy, Owned, Durable};
pub use ops::{Drop};
pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Shl, Shr, Index};
@ -109,6 +108,7 @@ pub use num::{Bitwise, BitCount, Bounded};
pub use num::{Primitive, Int, Float};
pub use ptr::Ptr;
pub use from_str::FromStr;
pub use to_str::ToStr;
pub use clone::Clone;
@ -122,6 +122,9 @@ pub mod linkhack {
}
}
// Internal macros
mod macros;
/* The Prelude. */
pub mod prelude;
@ -261,12 +264,3 @@ mod core {
pub use sys;
pub use pipes;
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -263,13 +263,3 @@ fn test_partition_empty() {
assert_eq!(vec::len(lefts), 0u);
assert_eq!(vec::len(rights), 0u);
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -678,7 +678,7 @@ pub impl <T:Hash + Eq> HashSet<T> {
}
}
#[test]
#[cfg(test)]
mod test_map {
use container::{Container, Map, Set};
use option::{None, Some};
@ -854,7 +854,7 @@ mod test_map {
}
}
#[test]
#[cfg(test)]
mod test_set {
use super::*;
use container::{Container, Map, Set};

View File

@ -1954,13 +1954,3 @@ mod tests {
}
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -41,6 +41,9 @@ much easier to implement.
*/
use cmp::Ord;
use option::{Option, Some, None};
pub trait Times {
fn times(&self, it: &fn() -> bool);
}
@ -104,6 +107,78 @@ pub fn all<T>(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool {
true
}
/**
* Return the first element where `predicate` returns `true`. Return `None` if no element is found.
*
* # Example:
*
* ~~~~
* let xs = ~[1u, 2, 3, 4, 5, 6];
* assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4);
* ~~~~
*/
#[inline(always)]
pub fn find<T>(predicate: &fn(&T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> Option<T> {
for iter |x| {
if predicate(&x) {
return Some(x);
}
}
None
}
/**
* Return the largest item yielded by an iterator. Return `None` if the iterator is empty.
*
* # Example:
*
* ~~~~
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
* assert_eq!(max(|f| xs.each(f)).unwrap(), &15);
* ~~~~
*/
#[inline]
pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool)) -> Option<T> {
let mut result = None;
for iter |x| {
match result {
Some(ref mut y) => {
if x > *y {
*y = x;
}
}
None => result = Some(x)
}
}
result
}
/**
* Return the smallest item yielded by an iterator. Return `None` if the iterator is empty.
*
* # Example:
*
* ~~~~
* let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
* assert_eq!(max(|f| xs.each(f)).unwrap(), &-5);
* ~~~~
*/
#[inline]
pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool)) -> Option<T> {
let mut result = None;
for iter |x| {
match result {
Some(ref mut y) => {
if x < *y {
*y = x;
}
}
None => result = Some(x)
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
@ -128,4 +203,22 @@ mod tests {
assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f)));
assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f)));
}
#[test]
fn test_find() {
let xs = ~[1u, 2, 3, 4, 5, 6];
assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4);
}
#[test]
fn test_max() {
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
assert_eq!(max(|f| xs.each(f)).unwrap(), &15);
}
#[test]
fn test_min() {
let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
assert_eq!(min(|f| xs.each(f)).unwrap(), &-5);
}
}

View File

@ -29,7 +29,7 @@ pub trait Iterator<A> {
///
/// In the future these will be default methods instead of a utility trait.
pub trait IteratorUtil<A> {
fn chain(self, other: Self) -> ChainIterator<Self>;
fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<Self, U>;
fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<Self, U>;
// FIXME: #5898: should be called map
fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>;
@ -50,7 +50,7 @@ pub trait IteratorUtil<A> {
/// In the future these will be default methods instead of a utility trait.
impl<A, T: Iterator<A>> IteratorUtil<A> for T {
#[inline(always)]
fn chain(self, other: T) -> ChainIterator<T> {
fn chain<U: Iterator<A>>(self, other: U) -> ChainIterator<T, U> {
ChainIterator{a: self, b: other, flag: false}
}
@ -115,13 +115,13 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T {
}
}
pub struct ChainIterator<T> {
pub struct ChainIterator<T, U> {
priv a: T,
priv b: T,
priv b: U,
priv flag: bool
}
impl<A, T: Iterator<A>> Iterator<A> for ChainIterator<T> {
impl<A, T: Iterator<A>, U: Iterator<A>> Iterator<A> for ChainIterator<T, U> {
#[inline]
fn next(&mut self) -> Option<A> {
if self.flag {
@ -385,7 +385,7 @@ mod tests {
#[test]
fn test_iterator_chain() {
let xs = [0u, 1, 2, 3, 4, 5];
let ys = [30, 40, 50, 60];
let ys = [30u, 40, 50, 60];
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
let mut it = xs.iter().chain(ys.iter());
let mut i = 0;
@ -394,6 +394,15 @@ mod tests {
i += 1;
}
assert_eq!(i, expected.len());
let ys = Counter::new(30u, 10).take(4);
let mut it = xs.iter().transform(|&x| x).chain(ys);
let mut i = 0;
for it.advance |x: uint| {
assert_eq!(x, expected[i]);
i += 1;
}
assert_eq!(i, expected.len());
}
#[test]

View File

@ -104,6 +104,7 @@ pub use libc::funcs::posix88::unistd::*;
pub use libc::funcs::posix01::stat_::*;
pub use libc::funcs::posix01::unistd::*;
pub use libc::funcs::posix01::glob::*;
pub use libc::funcs::posix08::unistd::*;
pub use libc::funcs::bsd44::*;
@ -210,7 +211,21 @@ pub mod types {
#[cfg(target_os = "android")]
pub mod os {
pub mod common {
pub mod posix01 {}
pub mod posix01 {
use libc::types::common::c95::{c_void};
use libc::types::os::arch::c95::{c_char, size_t};
pub struct glob_t {
gl_pathc: size_t,
gl_pathv: **c_char,
gl_offs: size_t,
__unused1: *c_void,
__unused2: *c_void,
__unused3: *c_void,
__unused4: *c_void,
__unused5: *c_void,
}
}
}
#[cfg(target_arch = "x86")]
@ -368,7 +383,25 @@ pub mod types {
#[cfg(target_os = "freebsd")]
pub mod os {
pub mod common {
pub mod posix01 {}
pub mod posix01 {
use libc::types::common::c95::{c_void};
use libc::types::os::arch::c95::{c_char, c_int, size_t};
pub struct glob_t {
gl_pathc: size_t,
__unused1: size_t,
gl_offs: size_t,
__unused2: c_int,
gl_pathv: **c_char,
__unused3: *c_void,
__unused4: *c_void,
__unused5: *c_void,
__unused6: *c_void,
__unused7: *c_void,
__unused8: *c_void,
}
}
}
#[cfg(target_arch = "x86_64")]
@ -548,12 +581,16 @@ pub mod types {
pub type LPWSTR = *mut WCHAR;
pub type LPSTR = *mut CHAR;
pub type LPTSTR = *mut CHAR;
// Not really, but opaque to us.
pub type LPSECURITY_ATTRIBUTES = LPVOID;
pub type LPVOID = *mut c_void;
pub type LPBYTE = *mut BYTE;
pub type LPWORD = *mut WORD;
pub type LPDWORD = *mut DWORD;
pub type LPHANDLE = *mut HANDLE;
pub type LRESULT = LONG_PTR;
pub type PBOOL = *mut BOOL;
@ -562,6 +599,36 @@ pub mod types {
pub type time64_t = i64;
pub type int64 = i64;
pub struct STARTUPINFO {
cb: DWORD,
lpReserved: LPTSTR,
lpDesktop: LPTSTR,
lpTitle: LPTSTR,
dwX: DWORD,
dwY: DWORD,
dwXSize: DWORD,
dwYSize: DWORD,
dwXCountChars: DWORD,
dwYCountCharts: DWORD,
dwFillAttribute: DWORD,
dwFlags: DWORD,
wShowWindow: WORD,
cbReserved2: WORD,
lpReserved2: LPBYTE,
hStdInput: HANDLE,
hStdOutput: HANDLE,
hStdError: HANDLE
}
pub type LPSTARTUPINFO = *mut STARTUPINFO;
pub struct PROCESS_INFORMATION {
hProcess: HANDLE,
hThread: HANDLE,
dwProcessId: DWORD,
dwThreadId: DWORD
}
pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
}
}
}
@ -570,6 +637,23 @@ pub mod types {
pub mod os {
pub mod common {
pub mod posix01 {
use libc::types::common::c95::{c_void};
use libc::types::os::arch::c95::{c_char, c_int, size_t};
pub struct glob_t {
gl_pathc: size_t,
__unused1: c_int,
gl_offs: size_t,
__unused2: c_int,
gl_pathv: **c_char,
__unused3: *c_void,
__unused4: *c_void,
__unused5: *c_void,
__unused6: *c_void,
__unused7: *c_void,
__unused8: *c_void,
}
}
}
@ -797,6 +881,11 @@ pub mod consts {
pub mod bsd44 {
}
pub mod extra {
use libc::types::os::arch::extra::{DWORD, BOOL};
pub static TRUE : BOOL = 1;
pub static FALSE : BOOL = 0;
pub static O_TEXT : int = 16384;
pub static O_BINARY : int = 32768;
pub static O_NOINHERIT: int = 128;
@ -804,6 +893,50 @@ pub mod consts {
pub static ERROR_SUCCESS : int = 0;
pub static ERROR_INSUFFICIENT_BUFFER : int = 122;
pub static INVALID_HANDLE_VALUE: int = -1;
pub static DELETE : DWORD = 0x00010000;
pub static READ_CONTROL : DWORD = 0x00020000;
pub static SYNCHRONIZE : DWORD = 0x00100000;
pub static WRITE_DAC : DWORD = 0x00040000;
pub static WRITE_OWNER : DWORD = 0x00080000;
pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080;
pub static PROCESS_CREATE_THREAD : DWORD = 0x0002;
pub static PROCESS_DUP_HANDLE : DWORD = 0x0040;
pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400;
pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000;
pub static PROCESS_SET_INFORMATION : DWORD = 0x0200;
pub static PROCESS_SET_QUOTA : DWORD = 0x0100;
pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800;
pub static PROCESS_TERMINATE : DWORD = 0x0001;
pub static PROCESS_VM_OPERATION : DWORD = 0x0008;
pub static PROCESS_VM_READ : DWORD = 0x0010;
pub static PROCESS_VM_WRITE : DWORD = 0x0020;
pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040;
pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080;
pub static STARTF_PREVENTPINNING : DWORD = 0x00002000;
pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020;
pub static STARTF_TITLEISAPPID : DWORD = 0x00001000;
pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800;
pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008;
pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010;
pub static STARTF_USEHOTKEY : DWORD = 0x00000200;
pub static STARTF_USEPOSITION : DWORD = 0x00000004;
pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001;
pub static STARTF_USESIZE : DWORD = 0x00000002;
pub static STARTF_USESTDHANDLES : DWORD = 0x00000100;
pub static WAIT_ABANDONED : DWORD = 0x00000080;
pub static WAIT_OBJECT_0 : DWORD = 0x00000000;
pub static WAIT_TIMEOUT : DWORD = 0x00000102;
pub static WAIT_FAILED : DWORD = -1;
pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
pub static INFINITE : DWORD = -1;
pub static STILL_ACTIVE : DWORD = 259;
}
}
@ -876,6 +1009,18 @@ pub mod consts {
}
pub mod posix01 {
pub static SIGTRAP : int = 5;
pub static GLOB_ERR : int = 1 << 0;
pub static GLOB_MARK : int = 1 << 1;
pub static GLOB_NOSORT : int = 1 << 2;
pub static GLOB_DOOFFS : int = 1 << 3;
pub static GLOB_NOCHECK : int = 1 << 4;
pub static GLOB_APPEND : int = 1 << 5;
pub static GLOB_NOESCAPE : int = 1 << 6;
pub static GLOB_NOSPACE : int = 1;
pub static GLOB_ABORTED : int = 2;
pub static GLOB_NOMATCH : int = 3;
}
pub mod posix08 {
}
@ -955,6 +1100,18 @@ pub mod consts {
}
pub mod posix01 {
pub static SIGTRAP : int = 5;
pub static GLOB_APPEND : int = 0x0001;
pub static GLOB_DOOFFS : int = 0x0002;
pub static GLOB_ERR : int = 0x0004;
pub static GLOB_MARK : int = 0x0008;
pub static GLOB_NOCHECK : int = 0x0010;
pub static GLOB_NOSORT : int = 0x0020;
pub static GLOB_NOESCAPE : int = 0x2000;
pub static GLOB_NOSPACE : int = -1;
pub static GLOB_ABORTED : int = -2;
pub static GLOB_NOMATCH : int = -3;
}
pub mod posix08 {
}
@ -1035,6 +1192,18 @@ pub mod consts {
}
pub mod posix01 {
pub static SIGTRAP : int = 5;
pub static GLOB_APPEND : int = 0x0001;
pub static GLOB_DOOFFS : int = 0x0002;
pub static GLOB_ERR : int = 0x0004;
pub static GLOB_MARK : int = 0x0008;
pub static GLOB_NOCHECK : int = 0x0010;
pub static GLOB_NOSORT : int = 0x0020;
pub static GLOB_NOESCAPE : int = 0x2000;
pub static GLOB_NOSPACE : int = -1;
pub static GLOB_ABORTED : int = -2;
pub static GLOB_NOMATCH : int = -3;
}
pub mod posix08 {
}
@ -1605,6 +1774,21 @@ pub mod funcs {
-> pid_t;
}
}
#[nolink]
#[abi = "cdecl"]
pub mod glob {
use libc::types::common::c95::{c_void};
use libc::types::os::arch::c95::{c_char, c_int};
use libc::types::os::common::posix01::{glob_t};
pub extern {
unsafe fn glob(pattern: *c_char, flags: c_int,
errfunc: *c_void, // XXX callback
pglob: *mut glob_t);
unsafe fn globfree(pglob: *mut glob_t);
}
}
}
#[cfg(target_os = "win32")]
@ -1614,6 +1798,9 @@ pub mod funcs {
pub mod unistd {
}
pub mod glob {
}
}
@ -1646,12 +1833,24 @@ pub mod funcs {
unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int,
sizep: *mut size_t) -> c_int;
unsafe fn getdtablesize() -> c_int;
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
pub mod bsd44 {
use libc::types::os::arch::c95::{c_int};
#[abi = "cdecl"]
pub extern {
unsafe fn getdtablesize() -> c_int;
}
}
#[cfg(target_os = "win32")]
pub mod bsd44 {
}
@ -1685,9 +1884,11 @@ pub mod funcs {
pub mod kernel32 {
use libc::types::os::arch::c95::{c_uint};
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
use libc::types::os::arch::extra::{HANDLE};
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR,
LPTSTR, LPTCH, LPDWORD, LPVOID};
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO,
LPPROCESS_INFORMATION};
use libc::types::os::arch::extra::{HANDLE, LPHANDLE};
#[abi = "stdcall"]
pub extern "stdcall" {
@ -1724,29 +1925,46 @@ pub mod funcs {
findFileData: HANDLE)
-> BOOL;
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE,
hSourceHandle: HANDLE,
hTargetProcessHandle: HANDLE,
lpTargetHandle: LPHANDLE,
dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
dwOptions: DWORD) -> BOOL;
unsafe fn CloseHandle(hObject: HANDLE) -> BOOL;
unsafe fn OpenProcess(dwDesiredAccess: DWORD,
bInheritHandle: BOOL,
dwProcessId: DWORD) -> HANDLE;
unsafe fn GetCurrentProcess() -> HANDLE;
unsafe fn CreateProcessA(lpApplicationName: LPCTSTR,
lpCommandLine: LPTSTR,
lpProcessAttributes: LPSECURITY_ATTRIBUTES,
lpThreadAttributes: LPSECURITY_ATTRIBUTES,
bInheritHandles: BOOL,
dwCreationFlags: DWORD,
lpEnvironment: LPVOID,
lpCurrentDirectory: LPCTSTR,
lpStartupInfo: LPSTARTUPINFO,
lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL;
unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
}
}
pub mod msvcrt {
use libc::types::os::arch::c95::c_int;
use libc::types::os::arch::c95::{c_int, c_long};
#[abi = "cdecl"]
#[nolink]
pub extern {
#[link_name = "_commit"]
unsafe fn commit(fd: c_int) -> c_int;
#[link_name = "_get_osfhandle"]
unsafe fn get_osfhandle(fd: c_int) -> c_long;
}
}
}
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -59,4 +59,3 @@ pub fn log_type<T>(level: u32, object: &T) {
rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len);
}
}

39
src/libcore/macros.rs Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2012 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.
#[macro_escape];
// Some basic logging
macro_rules! rtdebug_ (
($( $arg:expr),+) => ( {
dumb_println(fmt!( $($arg),+ ));
fn dumb_println(s: &str) {
use io::WriterUtil;
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
dbg.write_str(s);
dbg.write_str("\n");
}
} )
)
// An alternate version with no output, for turning off logging
macro_rules! rtdebug (
($( $arg:expr),+) => ( $(let _ = $arg)*; )
)
macro_rules! abort(
($( $msg:expr),+) => ( {
rtdebug!($($msg),+);
unsafe { ::libc::abort(); }
} )
)

View File

@ -267,14 +267,3 @@ pub mod c_double_targ_consts {
}
*/
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -10,7 +10,6 @@
//! Operations and constants for `f32`
use from_str;
use num::{Zero, One, strconv};
use prelude::*;
@ -123,7 +122,7 @@ pub fn sub(x: f32, y: f32) -> f32 { return x - y; }
pub fn mul(x: f32, y: f32) -> f32 { return x * y; }
#[inline(always)]
pub fn quot(x: f32, y: f32) -> f32 { return x / y; }
pub fn div(x: f32, y: f32) -> f32 { return x / y; }
#[inline(always)]
pub fn rem(x: f32, y: f32) -> f32 { return x % y; }
@ -278,11 +277,13 @@ impl Mul<f32,f32> for f32 {
#[inline(always)]
fn mul(&self, other: &f32) -> f32 { *self * *other }
}
#[cfg(notest)]
impl Quot<f32,f32> for f32 {
impl Div<f32,f32> for f32 {
#[inline(always)]
fn quot(&self, other: &f32) -> f32 { *self / *other }
fn div(&self, other: &f32) -> f32 { *self / *other }
}
#[cfg(notest)]
impl Rem<f32,f32> for f32 {
#[inline(always)]
@ -791,7 +792,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
strconv::ExpNone, false, false)
}
impl from_str::FromStr for f32 {
impl FromStr for f32 {
#[inline(always)]
fn from_str(val: &str) -> Option<f32> { from_str(val) }
}
@ -979,13 +980,3 @@ mod tests {
assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -10,7 +10,6 @@
//! Operations and constants for `f64`
use from_str;
use libc::c_int;
use num::{Zero, One, strconv};
use prelude::*;
@ -149,7 +148,7 @@ pub fn sub(x: f64, y: f64) -> f64 { return x - y; }
pub fn mul(x: f64, y: f64) -> f64 { return x * y; }
#[inline(always)]
pub fn quot(x: f64, y: f64) -> f64 { return x / y; }
pub fn div(x: f64, y: f64) -> f64 { return x / y; }
#[inline(always)]
pub fn rem(x: f64, y: f64) -> f64 { return x % y; }
@ -297,9 +296,8 @@ impl Mul<f64,f64> for f64 {
fn mul(&self, other: &f64) -> f64 { *self * *other }
}
#[cfg(notest)]
impl Quot<f64,f64> for f64 {
#[inline(always)]
fn quot(&self, other: &f64) -> f64 { *self / *other }
impl Div<f64,f64> for f64 {
fn div(&self, other: &f64) -> f64 { *self / *other }
}
#[cfg(notest)]
impl Rem<f64,f64> for f64 {
@ -837,7 +835,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
strconv::ExpNone, false, false)
}
impl from_str::FromStr for f64 {
impl FromStr for f64 {
#[inline(always)]
fn from_str(val: &str) -> Option<f64> { from_str(val) }
}
@ -1030,13 +1028,3 @@ mod tests {
assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -20,12 +20,11 @@
// PORT this must match in width according to architecture
use from_str;
use libc::c_int;
use num::{Zero, One, strconv};
use prelude::*;
pub use f64::{add, sub, mul, quot, rem, lt, le, eq, ne, ge, gt};
pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
pub use f64::logarithm;
pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor};
pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub};
@ -289,7 +288,7 @@ pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
strconv::ExpNone, false, false)
}
impl from_str::FromStr for float {
impl FromStr for float {
#[inline(always)]
fn from_str(val: &str) -> Option<float> { from_str(val) }
}
@ -691,11 +690,13 @@ impl Mul<float,float> for float {
#[inline(always)]
fn mul(&self, other: &float) -> float { *self * *other }
}
#[cfg(notest)]
impl Quot<float,float> for float {
impl Div<float,float> for float {
#[inline(always)]
fn quot(&self, other: &float) -> float { *self / *other }
fn div(&self, other: &float) -> float { *self / *other }
}
#[cfg(notest)]
impl Rem<float,float> for float {
#[inline(always)]
@ -1132,13 +1133,3 @@ mod tests {
assert_eq!(to_str_digits(-infinity, 10u), ~"-inf");
}
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View File

@ -10,7 +10,6 @@
use T = self::inst::T;
use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix};
use num::{Zero, One, strconv};
use prelude::*;
@ -30,7 +29,7 @@ pub fn sub(x: T, y: T) -> T { x - y }
#[inline(always)]
pub fn mul(x: T, y: T) -> T { x * y }
#[inline(always)]
pub fn quot(x: T, y: T) -> T { x / y }
pub fn div(x: T, y: T) -> T { x / y }
///
/// Returns the remainder of y / x.
@ -202,10 +201,10 @@ impl Mul<T,T> for T {
}
#[cfg(notest)]
impl Quot<T,T> for T {
impl Div<T,T> for T {
///
/// Returns the integer quotient, truncated towards 0. As this behaviour reflects
/// the underlying machine implementation it is more efficient than `Natural::div`.
/// Integer division, truncated towards 0. As this behaviour reflects the underlying
/// machine implementation it is more efficient than `Integer::div_floor`.
///
/// # Examples
///
@ -222,7 +221,7 @@ impl Quot<T,T> for T {
/// ~~~
///
#[inline(always)]
fn quot(&self, other: &T) -> T { *self / *other }
fn div(&self, other: &T) -> T { *self / *other }
}
#[cfg(notest)]
@ -297,25 +296,25 @@ impl Integer for T {
/// # Examples
///
/// ~~~
/// assert!(( 8).div( 3) == 2);
/// assert!(( 8).div(-3) == -3);
/// assert!((-8).div( 3) == -3);
/// assert!((-8).div(-3) == 2);
/// assert!(( 8).div_floor( 3) == 2);
/// assert!(( 8).div_floor(-3) == -3);
/// assert!((-8).div_floor( 3) == -3);
/// assert!((-8).div_floor(-3) == 2);
///
/// assert!(( 1).div( 2) == 0);
/// assert!(( 1).div(-2) == -1);
/// assert!((-1).div( 2) == -1);
/// assert!((-1).div(-2) == 0);
/// assert!(( 1).div_floor( 2) == 0);
/// assert!(( 1).div_floor(-2) == -1);
/// assert!((-1).div_floor( 2) == -1);
/// assert!((-1).div_floor(-2) == 0);
/// ~~~
///
#[inline(always)]
fn div(&self, other: &T) -> T {
fn div_floor(&self, other: &T) -> T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.quot_rem(other) {
(q, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => q - 1,
(q, _) => q,
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => d - 1,
(d, _) => d,
}
}
@ -323,25 +322,25 @@ impl Integer for T {
/// Integer modulo, satisfying:
///
/// ~~~
/// assert!(n.div(d) * d + n.modulo(d) == n)
/// assert!(n.div_floor(d) * d + n.mod_floor(d) == n)
/// ~~~
///
/// # Examples
///
/// ~~~
/// assert!(( 8).modulo( 3) == 2);
/// assert!(( 8).modulo(-3) == -1);
/// assert!((-8).modulo( 3) == 1);
/// assert!((-8).modulo(-3) == -2);
/// assert!(( 8).mod_floor( 3) == 2);
/// assert!(( 8).mod_floor(-3) == -1);
/// assert!((-8).mod_floor( 3) == 1);
/// assert!((-8).mod_floor(-3) == -2);
///
/// assert!(( 1).modulo( 2) == 1);
/// assert!(( 1).modulo(-2) == -1);
/// assert!((-1).modulo( 2) == 1);
/// assert!((-1).modulo(-2) == -1);
/// assert!(( 1).mod_floor( 2) == 1);
/// assert!(( 1).mod_floor(-2) == -1);
/// assert!((-1).mod_floor( 2) == 1);
/// assert!((-1).mod_floor(-2) == -1);
/// ~~~
///
#[inline(always)]
fn modulo(&self, other: &T) -> T {
fn mod_floor(&self, other: &T) -> T {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match *self % *other {
@ -351,21 +350,21 @@ impl Integer for T {
}
}
/// Calculates `div` and `modulo` simultaneously
/// Calculates `div_floor` and `mod_floor` simultaneously
#[inline(always)]
fn div_mod(&self, other: &T) -> (T,T) {
fn div_mod_floor(&self, other: &T) -> (T,T) {
// Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_,
// December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf)
match self.quot_rem(other) {
(q, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => (q - 1, r + *other),
(q, r) => (q, r),
match self.div_rem(other) {
(d, r) if (r > 0 && *other < 0)
|| (r < 0 && *other > 0) => (d - 1, r + *other),
(d, r) => (d, r),
}
}
/// Calculates `quot` (`\`) and `rem` (`%`) simultaneously
/// Calculates `div` (`\`) and `rem` (`%`) simultaneously
#[inline(always)]
fn quot_rem(&self, other: &T) -> (T,T) {
fn div_rem(&self, other: &T) -> (T,T) {
(*self / *other, *self % *other)
}
@ -589,42 +588,42 @@ mod tests {
}
#[test]
fn test_quot_rem() {
fn test_nd_qr(nd: (T,T), qr: (T,T)) {
fn test_div_rem() {
fn test_nd_dr(nd: (T,T), qr: (T,T)) {
let (n,d) = nd;
let separate_quot_rem = (n / d, n % d);
let combined_quot_rem = n.quot_rem(&d);
let separate_div_rem = (n / d, n % d);
let combined_div_rem = n.div_rem(&d);
assert_eq!(separate_quot_rem, qr);
assert_eq!(combined_quot_rem, qr);
assert_eq!(separate_div_rem, qr);
assert_eq!(combined_div_rem, qr);
test_division_rule(nd, separate_quot_rem);
test_division_rule(nd, combined_quot_rem);
test_division_rule(nd, separate_div_rem);
test_division_rule(nd, combined_div_rem);
}
test_nd_qr(( 8, 3), ( 2, 2));
test_nd_qr(( 8, -3), (-2, 2));
test_nd_qr((-8, 3), (-2, -2));
test_nd_qr((-8, -3), ( 2, -2));
test_nd_dr(( 8, 3), ( 2, 2));
test_nd_dr(( 8, -3), (-2, 2));
test_nd_dr((-8, 3), (-2, -2));
test_nd_dr((-8, -3), ( 2, -2));
test_nd_qr(( 1, 2), ( 0, 1));
test_nd_qr(( 1, -2), ( 0, 1));
test_nd_qr((-1, 2), ( 0, -1));
test_nd_qr((-1, -2), ( 0, -1));
test_nd_dr(( 1, 2), ( 0, 1));
test_nd_dr(( 1, -2), ( 0, 1));
test_nd_dr((-1, 2), ( 0, -1));
test_nd_dr((-1, -2), ( 0, -1));
}
#[test]
fn test_div_mod() {
fn test_div_mod_floor() {
fn test_nd_dm(nd: (T,T), dm: (T,T)) {
let (n,d) = nd;
let separate_div_mod = (n.div(&d), n.modulo(&d));
let combined_div_mod = n.div_mod(&d);
let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d));
let combined_div_mod_floor = n.div_mod_floor(&d);
assert_eq!(separate_div_mod, dm);
assert_eq!(combined_div_mod, dm);
assert_eq!(separate_div_mod_floor, dm);
assert_eq!(combined_div_mod_floor, dm);
test_division_rule(nd, separate_div_mod);
test_division_rule(nd, combined_div_mod);
test_division_rule(nd, separate_div_mod_floor);
test_division_rule(nd, combined_div_mod_floor);
}
test_nd_dm(( 8, 3), ( 2, 2));

View File

@ -10,7 +10,7 @@
//! An interface for numeric types
use cmp::{Eq, Ord};
use ops::{Add, Sub, Mul, Quot, Rem, Neg};
use ops::{Add, Sub, Mul, Div, Rem, Neg};
use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
use option::Option;
use kinds::Copy;
@ -25,7 +25,7 @@ pub trait Num: Eq + Zero + One
+ Add<Self,Self>
+ Sub<Self,Self>
+ Mul<Self,Self>
+ Quot<Self,Self>
+ Div<Self,Self>
+ Rem<Self,Self> {}
pub trait IntConvertible {
@ -69,12 +69,13 @@ pub fn abs<T:Ord + Zero + Neg<T>>(v: T) -> T {
pub trait Integer: Num
+ Orderable
+ Quot<Self,Self>
+ Div<Self,Self>
+ Rem<Self,Self> {
fn div(&self, other: &Self) -> Self;
fn modulo(&self, other: &Self) -> Self;
fn div_mod(&self, other: &Self) -> (Self,Self);
fn quot_rem(&self, other: &Self) -> (Self,Self);
fn div_rem(&self, other: &Self) -> (Self,Self);
fn div_floor(&self, other: &Self) -> Self;
fn mod_floor(&self, other: &Self) -> Self;
fn div_mod_floor(&self, other: &Self) -> (Self,Self);
fn gcd(&self, other: &Self) -> Self;
fn lcm(&self, other: &Self) -> Self;
@ -95,7 +96,7 @@ pub trait Round {
pub trait Fractional: Num
+ Orderable
+ Round
+ Quot<Self,Self> {
+ Div<Self,Self> {
fn recip(&self) -> Self;
}
@ -219,7 +220,7 @@ pub trait Primitive: Num
+ Add<Self,Self>
+ Sub<Self,Self>
+ Mul<Self,Self>
+ Quot<Self,Self>
+ Div<Self,Self>
+ Rem<Self,Self> {
// FIXME (#5527): These should be associated constants
fn bits() -> uint;
@ -364,7 +365,7 @@ pub trait FromStrRadix {
/// - If code written to use this function doesn't care about it, it's
/// probably assuming that `x^0` always equals `1`.
///
pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Quot<T,T>+Mul<T,T>>(
pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
radix: uint, pow: uint) -> T {
let _0: T = Zero::zero();
let _1: T = One::one();
@ -384,18 +385,19 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Quot<T,T>+Mul<T,T>>(
total
}
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
assert_eq!(ten.add(&two), cast(12));
assert_eq!(ten.sub(&two), cast(8));
assert_eq!(ten.mul(&two), cast(20));
assert_eq!(ten.quot(&two), cast(5));
assert_eq!(ten.div(&two), cast(5));
assert_eq!(ten.rem(&two), cast(0));
assert_eq!(ten.add(&two), ten + two);
assert_eq!(ten.sub(&two), ten - two);
assert_eq!(ten.mul(&two), ten * two);
assert_eq!(ten.quot(&two), ten / two);
assert_eq!(ten.div(&two), ten / two);
assert_eq!(ten.rem(&two), ten % two);
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
use core::cmp::{Ord, Eq};
use ops::{Add, Sub, Mul, Quot, Rem, Neg};
use ops::{Add, Sub, Mul, Div, Rem, Neg};
use option::{None, Option, Some};
use char;
use str;
@ -58,7 +58,7 @@ fn is_neg_inf<T:Eq+NumStrConv>(num: &T) -> bool {
}
#[inline(always)]
fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Quot<T,T>>(num: &T) -> bool {
fn is_neg_zero<T:Eq+One+Zero+NumStrConv+Div<T,T>>(num: &T) -> bool {
let _0: T = Zero::zero();
let _1: T = One::one();
@ -171,7 +171,7 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8];
* - Fails if `radix` < 2 or `radix` > 36.
*/
pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
Quot<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
num: &T, radix: uint, negative_zero: bool,
sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
if (radix as int) < 2 {
@ -379,7 +379,7 @@ pub fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
*/
#[inline(always)]
pub fn to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Copy+
Quot<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
num: &T, radix: uint, negative_zero: bool,
sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
let (bytes, special) = to_str_bytes_common(num, radix,
@ -432,7 +432,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
* - Fails if `radix` > 18 and `special == true` due to conflict
* between digit and lowest first character in `inf` and `NaN`, the `'i'`.
*/
pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+
pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
NumStrConv>(
buf: &[u8], radix: uint, negative: bool, fractional: bool,
@ -629,7 +629,7 @@ pub fn from_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+
* `from_str_bytes_common()`, for details see there.
*/
#[inline(always)]
pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Quot<T,T>+Mul<T,T>+
pub fn from_str_common<T:NumCast+Zero+One+Eq+Ord+Copy+Div<T,T>+Mul<T,T>+
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv>(
buf: &str, radix: uint, negative: bool, fractional: bool,
special: bool, exponent: ExponentFormat, empty_zero: bool,

View File

@ -11,7 +11,6 @@
use T = self::inst::T;
use T_SIGNED = self::inst::T_SIGNED;
use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix};
use num::{Zero, One, strconv};
use prelude::*;
@ -31,7 +30,7 @@ pub fn sub(x: T, y: T) -> T { x - y }
#[inline(always)]
pub fn mul(x: T, y: T) -> T { x * y }
#[inline(always)]
pub fn quot(x: T, y: T) -> T { x / y }
pub fn div(x: T, y: T) -> T { x / y }
#[inline(always)]
pub fn rem(x: T, y: T) -> T { x % y }
@ -167,9 +166,9 @@ impl Mul<T,T> for T {
}
#[cfg(notest)]
impl Quot<T,T> for T {
impl Div<T,T> for T {
#[inline(always)]
fn quot(&self, other: &T) -> T { *self / *other }
fn div(&self, other: &T) -> T { *self / *other }
}
#[cfg(notest)]
@ -187,23 +186,23 @@ impl Neg<T> for T {
impl Unsigned for T {}
impl Integer for T {
/// Unsigned integer division. Returns the same result as `quot` (`/`).
/// Calculates `div` (`\`) and `rem` (`%`) simultaneously
#[inline(always)]
fn div(&self, other: &T) -> T { *self / *other }
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
#[inline(always)]
fn modulo(&self, other: &T) -> T { *self / *other }
/// Calculates `div` and `modulo` simultaneously
#[inline(always)]
fn div_mod(&self, other: &T) -> (T,T) {
fn div_rem(&self, other: &T) -> (T,T) {
(*self / *other, *self % *other)
}
/// Calculates `quot` (`\`) and `rem` (`%`) simultaneously
/// Unsigned integer division. Returns the same result as `div` (`/`).
#[inline(always)]
fn quot_rem(&self, other: &T) -> (T,T) {
fn div_floor(&self, other: &T) -> T { *self / *other }
/// Unsigned integer modulo operation. Returns the same result as `rem` (`%`).
#[inline(always)]
fn mod_floor(&self, other: &T) -> T { *self / *other }
/// Calculates `div_floor` and `modulo_floor` simultaneously
#[inline(always)]
fn div_mod_floor(&self, other: &T) -> (T,T) {
(*self / *other, *self % *other)
}

View File

@ -30,9 +30,9 @@ pub trait Mul<RHS,Result> {
fn mul(&self, rhs: &RHS) -> Result;
}
#[lang="quot"]
pub trait Quot<RHS,Result> {
fn quot(&self, rhs: &RHS) -> Result;
#[lang="div"]
pub trait Div<RHS,Result> {
fn div(&self, rhs: &RHS) -> Result;
}
#[lang="rem"]

View File

@ -461,11 +461,3 @@ fn test_get_or_zero() {
let no_stuff: Option<int> = None;
assert!(no_stuff.get_or_zero() == 0);
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -38,6 +38,7 @@ use ptr;
use str;
use task;
use uint;
use unstable::finally::Finally;
use vec;
pub use libc::fclose;
@ -372,8 +373,9 @@ pub fn pipe() -> Pipe {
// inheritance has to be handled in a different way that I do not
// fully understand. Here we explicitly make the pipe non-inheritable,
// which means to pass it to a subprocess they need to be duplicated
// first, as in rust_run_program.
let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int};
// first, as in core::run.
let mut fds = Pipe {in: 0 as c_int,
out: 0 as c_int };
let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint,
(libc::O_BINARY | libc::O_NOINHERIT) as c_int);
assert!((res == 0 as c_int));
@ -770,6 +772,28 @@ pub fn list_dir_path(p: &Path) -> ~[~Path] {
list_dir(p).map(|f| ~p.push(*f))
}
/// Removes a directory at the specified path, after removing
/// all its contents. Use carefully!
pub fn remove_dir_recursive(p: &Path) -> bool {
let mut error_happened = false;
for walk_dir(p) |inner| {
if !error_happened {
if path_is_dir(inner) {
if !remove_dir_recursive(inner) {
error_happened = true;
}
}
else {
if !remove_file(inner) {
error_happened = true;
}
}
}
};
// Directory should now be empty
!error_happened && remove_dir(p)
}
/// Removes a directory at the specified path
pub fn remove_dir(p: &Path) -> bool {
return rmdir(p);
@ -817,6 +841,36 @@ pub fn change_dir(p: &Path) -> bool {
}
}
/// Changes the current working directory to the specified
/// path while acquiring a global lock, then calls `action`.
/// If the change is successful, releases the lock and restores the
/// CWD to what it was before, returning true.
/// Returns false if the directory doesn't exist or if the directory change
/// is otherwise unsuccessful.
pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
use unstable::global::global_data_clone_create;
use unstable::{Exclusive, exclusive};
fn key(_: Exclusive<()>) { }
let result = unsafe {
global_data_clone_create(key, || {
~exclusive(())
})
};
do result.with_imm() |_| {
let old_dir = os::getcwd();
if change_dir(p) {
action();
change_dir(&old_dir)
}
else {
false
}
}
}
/// Copies a file from one location to another
pub fn copy_file(from: &Path, to: &Path) -> bool {
return do_copy_file(from, to);
@ -845,6 +899,10 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
if istream as uint == 0u {
return false;
}
// Preserve permissions
let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \
for source file");
let ostream = do as_c_charp(to.to_str()) |top| {
do as_c_charp("w+b") |modebuf| {
libc::fopen(top, modebuf)
@ -876,6 +934,15 @@ pub fn copy_file(from: &Path, to: &Path) -> bool {
}
fclose(istream);
fclose(ostream);
// Give the new file the old file's permissions
unsafe {
if do str::as_c_str(to.to_str()) |to_buf| {
libc::chmod(to_buf, from_mode as mode_t)
} != 0 {
return false; // should be a condition...
}
}
return ok;
}
}
@ -1152,6 +1219,88 @@ pub fn set_args(new_args: ~[~str]) {
}
}
// FIXME #6100 we should really use an internal implementation of this - using
// the POSIX glob functions isn't portable to windows, probably has slight
// inconsistencies even where it is implemented, and makes extending
// functionality a lot more difficult
// FIXME #6101 also provide a non-allocating version - each_glob or so?
/// Returns a vector of Path objects that match the given glob pattern
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn glob(pattern: &str) -> ~[Path] {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn default_glob_t () -> libc::glob_t {
libc::glob_t {
gl_pathc: 0,
gl_pathv: ptr::null(),
gl_offs: 0,
__unused1: ptr::null(),
__unused2: ptr::null(),
__unused3: ptr::null(),
__unused4: ptr::null(),
__unused5: ptr::null(),
}
}
#[cfg(target_os = "freebsd")]
fn default_glob_t () -> libc::glob_t {
libc::glob_t {
gl_pathc: 0,
__unused1: 0,
gl_offs: 0,
__unused2: 0,
gl_pathv: ptr::null(),
__unused3: ptr::null(),
__unused4: ptr::null(),
__unused5: ptr::null(),
__unused6: ptr::null(),
__unused7: ptr::null(),
__unused8: ptr::null(),
}
}
#[cfg(target_os = "macos")]
fn default_glob_t () -> libc::glob_t {
libc::glob_t {
gl_pathc: 0,
__unused1: 0,
gl_offs: 0,
__unused2: 0,
gl_pathv: ptr::null(),
__unused3: ptr::null(),
__unused4: ptr::null(),
__unused5: ptr::null(),
__unused6: ptr::null(),
__unused7: ptr::null(),
__unused8: ptr::null(),
}
}
let mut g = default_glob_t();
do str::as_c_str(pattern) |c_pattern| {
unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) }
};
do(|| {
let paths = unsafe {
vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint)
};
do paths.map |&c_str| {
Path(unsafe { str::raw::from_c_str(c_str) })
}
}).finally {
unsafe { libc::globfree(&mut g) };
}
}
/// Returns a vector of Path objects that match the given glob pattern
#[cfg(target_os = "win32")]
pub fn glob(pattern: &str) -> ~[Path] {
fail!(~"glob() is unimplemented on Windows")
}
#[cfg(target_os = "macos")]
extern {
// These functions are in crt_externs.h.
@ -1480,6 +1629,7 @@ mod tests {
== buf.len() as size_t))
}
assert!((libc::fclose(ostream) == (0u as c_int)));
let in_mode = in.get_mode();
let rs = os::copy_file(&in, &out);
if (!os::path_exists(&in)) {
fail!(fmt!("%s doesn't exist", in.to_str()));
@ -1487,6 +1637,7 @@ mod tests {
assert!((rs));
let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]);
assert!((rslt == 0));
assert!(out.get_mode() == in_mode);
assert!((remove_file(&in)));
assert!((remove_file(&out)));
}

View File

@ -31,4 +31,3 @@ impl<T:Ord> Ord for ~T {
#[inline(always)]
fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
}

View File

@ -86,7 +86,9 @@ use cast::{forget, transmute, transmute_copy};
use either::{Either, Left, Right};
use kinds::Owned;
use libc;
use ops::Drop;
use option::{None, Option, Some};
use unstable::finally::Finally;
use unstable::intrinsics;
use ptr;
use task;
@ -301,7 +303,7 @@ struct BufferResource<T> {
}
#[unsafe_destructor]
impl<T> ::ops::Drop for BufferResource<T> {
impl<T> Drop for BufferResource<T> {
fn finalize(&self) {
unsafe {
let b = move_it!(self.buffer);
@ -395,26 +397,22 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(p: RecvPacketBuffered<T, Tbuffer>)
let p_ = p.unwrap();
let p = unsafe { &*p_ };
#[unsafe_destructor]
struct DropState<'self> {
p: &'self PacketHeader,
drop {
unsafe {
if task::failing() {
self.p.state = Terminated;
let old_task = swap_task(&mut self.p.blocked_task,
ptr::null());
if !old_task.is_null() {
rustrt::rust_task_deref(old_task);
}
do (|| {
try_recv_(p)
}).finally {
unsafe {
if task::failing() {
p.header.state = Terminated;
let old_task = swap_task(&mut p.header.blocked_task, ptr::null());
if !old_task.is_null() {
rustrt::rust_task_deref(old_task);
}
}
}
};
let _drop_state = DropState { p: &p.header };
}
}
fn try_recv_<T:Owned>(p: &Packet<T>) -> Option<T> {
// optimistic path
match p.header.state {
Full => {
@ -451,7 +449,7 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(p: RecvPacketBuffered<T, Tbuffer>)
Blocked);
match old_state {
Empty => {
debug!("no data available on %?, going to sleep.", p_);
debug!("no data available on %?, going to sleep.", p);
if count == 0 {
wait_event(this);
}
@ -641,7 +639,7 @@ pub struct SendPacketBuffered<T, Tbuffer> {
}
#[unsafe_destructor]
impl<T:Owned,Tbuffer:Owned> ::ops::Drop for SendPacketBuffered<T,Tbuffer> {
impl<T:Owned,Tbuffer:Owned> Drop for SendPacketBuffered<T,Tbuffer> {
fn finalize(&self) {
//if self.p != none {
// debug!("drop send %?", option::get(self.p));
@ -710,7 +708,7 @@ pub struct RecvPacketBuffered<T, Tbuffer> {
}
#[unsafe_destructor]
impl<T:Owned,Tbuffer:Owned> ::ops::Drop for RecvPacketBuffered<T,Tbuffer> {
impl<T:Owned,Tbuffer:Owned> Drop for RecvPacketBuffered<T,Tbuffer> {
fn finalize(&self) {
//if self.p != none {
// debug!("drop recv %?", option::get(self.p));

View File

@ -14,7 +14,7 @@
pub use either::{Either, Left, Right};
pub use kinds::{Const, Copy, Owned, Durable};
pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop};
pub use ops::{Shl, Shr, Index};
@ -28,7 +28,7 @@ pub use io::{print, println};
/* Reexported types and traits */
pub use clone::Clone;
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use container::{Container, Mutable, Map, Set};
pub use hash::Hash;
pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter};
@ -48,6 +48,7 @@ pub use path::WindowsPath;
pub use ptr::Ptr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr};
pub use str::{StrSlice, OwnedStr};
pub use from_str::{FromStr};
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};

View File

@ -16,6 +16,9 @@ and so can be used to generate any type that implements `Rand`. Type inference
means that often a simple call to `rand::random()` or `rng.gen()` will
suffice, but sometimes an annotation is required, e.g. `rand::random::<float>()`.
See the `distributions` submodule for sampling random numbers from
distributions like normal and exponential.
# Examples
~~~
use core::rand::RngUtil;
@ -47,6 +50,9 @@ use util;
use vec;
use libc::size_t;
#[path="rand/distributions.rs"]
pub mod distributions;
/// A type that can be randomly generated using an Rng
pub trait Rand {
fn rand<R: Rng>(rng: &R) -> Self;
@ -1067,12 +1073,3 @@ mod tests {
}
}
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -0,0 +1,148 @@
// Copyright 2013 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.
//! Sampling from random distributions
// Some implementations use the Ziggurat method
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
//
// The version used here is ZIGNOR [Doornik 2005, "An Improved
// Ziggurat Method to Generate Normal Random Samples"] which is slower
// (about double, it generates an extra random number) than the
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
// Generating Random Variables"], but more robust. If one wanted, one
// could implement VIZIGNOR the ZIGNOR paper for more speed.
use prelude::*;
use rand::{Rng,Rand};
mod ziggurat_tables;
// inlining should mean there is no performance penalty for this
#[inline(always)]
fn ziggurat<R:Rng>(rng: &R,
center_u: bool,
X: ziggurat_tables::ZigTable,
F: ziggurat_tables::ZigTable,
F_DIFF: ziggurat_tables::ZigTable,
pdf: &'static fn(f64) -> f64, // probability density function
zero_case: &'static fn(&R, f64) -> f64) -> f64 {
loop {
let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
let i: uint = rng.gen::<uint>() & 0xff;
let x = u * X[i];
let test_x = if center_u {f64::abs(x)} else {x};
// algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
if test_x < X[i + 1] {
return x;
}
if i == 0 {
return zero_case(rng, u);
}
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
return x;
}
}
}
/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a
/// standard normal, or Gaussian). Multiplying the generated values by the
/// desired standard deviation `sigma` then adding the desired mean `mu` will
/// give N(mu, sigma^2) distributed random numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::StandardNormal;
///
/// fn main() {
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
/// println(fmt!("%f is from a N(2, 9) distribution", normal))
/// }
/// ~~~
pub struct StandardNormal(f64);
impl Rand for StandardNormal {
fn rand<R:Rng>(rng: &R) -> StandardNormal {
#[inline(always)]
fn pdf(x: f64) -> f64 {
f64::exp((-x*x/2.0) as f64) as f64
}
#[inline(always)]
fn zero_case<R:Rng>(rng: &R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
// do-while, so the condition should be true on the first
// run, they get overwritten anyway (0 < 1, so these are
// good).
let mut x = 1.0, y = 0.0;
// XXX infinities?
while -2.0*y < x * x {
x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R;
y = f64::ln(rng.gen());
}
if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x}
}
StandardNormal(ziggurat(
rng,
true, // this is symmetric
&ziggurat_tables::ZIG_NORM_X,
&ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
pdf, zero_case))
}
}
/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
/// the desired rate `lambda` will give Exp(lambda) distributed random
/// numbers.
///
/// Note that this has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// # Example
///
/// ~~~
/// use core::rand::distributions::Exp1;
///
/// fn main() {
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
/// println(fmt!("%f is from a Exp(2) distribution", exp2));
/// }
/// ~~~
pub struct Exp1(f64);
// This could be done via `-f64::ln(rng.gen::<f64>())` but that is slower.
impl Rand for Exp1 {
#[inline]
fn rand<R:Rng>(rng: &R) -> Exp1 {
#[inline(always)]
fn pdf(x: f64) -> f64 {
f64::exp(-x)
}
#[inline(always)]
fn zero_case<R:Rng>(rng: &R, _u: f64) -> f64 {
ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen())
}
Exp1(ziggurat(rng, false,
&ziggurat_tables::ZIG_EXP_X,
&ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
pdf, zero_case))
}
}

View File

@ -0,0 +1,412 @@
// Copyright 2013 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.
// Tables for distributions which are sampled using the ziggurat
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &'static [f64, .. 257];
pub static ZIG_NORM_R: f64 = 3.654152885361008796;
pub static ZIG_NORM_X: [f64, .. 257] =
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
0.000000000000000000];
pub static ZIG_NORM_F: [f64, .. 257] =
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
1.000000000000000000];
pub static ZIG_NORM_F_DIFF: [f64, .. 257] =
[0.000000000000000000, 0.000782818165911943, 0.001348786815607765, 0.001428899847265509,
0.001484430705892882, 0.001528472172127356, 0.001565707298030807, 0.001598388670308183,
0.001627786418212004, 0.001654692743837703, 0.001679637706201265, 0.001702994844613767,
0.001725038123187510, 0.001745974954326004, 0.001765966477270568, 0.001785140598493315,
0.001803600702759419, 0.001821431661060659, 0.001838704088536796, 0.001855477433793579,
0.001871802266665008, 0.001887722003144375, 0.001903274226858077, 0.001918491715965767,
0.001933403251421835, 0.001948034260540625, 0.001962407334827158, 0.001976542650643127,
0.001990458313945481, 0.002004170645086643, 0.002017694415851860, 0.002031043048104267,
0.002044228781321551, 0.002057262814738517, 0.002070155428613822, 0.002082916088226049,
0.002095553533492583, 0.002108075856553551, 0.002120490569226280, 0.002132804661891696,
0.002145024655099026, 0.002157156644953973, 0.002169206343177243, 0.002181179112575302,
0.002193079998548175, 0.002204913757158977, 0.002216684880213121, 0.002228397617726446,
0.002240055998106505, 0.002251663846325885, 0.002263224800326716, 0.002274742325862292,
0.002286219729956393, 0.002297660173134250, 0.002309066680560787, 0.002320442152205823,
0.002331789372137141, 0.002343111017035562, 0.002354409664009627, 0.002365687797781804,
0.002376947817308683, 0.002388192041889739, 0.002399422716815966, 0.002410642018598946,
0.002421852059823287, 0.002433054893654529, 0.002444252518034679, 0.002455446879594508,
0.002466639877306970, 0.002477833365903986, 0.002489029159078809, 0.002500229032490808,
0.002511434726590794, 0.002522647949281448, 0.002533870378427505, 0.002545103664226889,
0.002556349431455662, 0.002567609281597438, 0.002578884794865288, 0.002590177532127119,
0.002601489036740262, 0.002612820836305291, 0.002624174444343735, 0.002635551361907296,
0.002646953079123743, 0.002658381076686089, 0.002669836827288052, 0.002681321797012387,
0.002692837446676144, 0.002704385233135737, 0.002715966610556786, 0.002727583031652520,
0.002739235948893221, 0.002750926815690169, 0.002762657087557796, 0.002774428223256353,
0.002786241685917290, 0.002798098944155558, 0.002810001473169871, 0.002821950755833219,
0.002833948283778004, 0.002845995558475284, 0.002858094092312607, 0.002870245409671041,
0.002882451048004164, 0.002894712558920987, 0.002907031509275432, 0.002919409482262880,
0.002931848078526783, 0.002944348917277934, 0.002956913637427061, 0.002969543898733384,
0.002982241382970874, 0.002995007795115689, 0.003007844864553855, 0.003020754346314269,
0.003033738022328147, 0.003046797702715820, 0.003059935227105459, 0.003073152465984053,
0.003086451322084072, 0.003099833731808721, 0.003113301666695822, 0.003126857134927052,
0.003140502182881588, 0.003154238896738770, 0.003168069404132778, 0.003181995875862154,
0.003196020527657495, 0.003210145622009941, 0.003224373470066433, 0.003238706433592253,
0.003253146927007733, 0.003267697419501892, 0.003282360437226572, 0.003297138565578506,
0.003312034451571411, 0.003327050806304299, 0.003342190407532641, 0.003357456102345890,
0.003372850809960137, 0.003388377524629727, 0.003404039318688046, 0.003419839345721265,
0.003435780843885239, 0.003451867139373843, 0.003468101650046629, 0.003484487889225119,
0.003501029469670069, 0.003517730107746697, 0.003534593627793237, 0.003551623966702611,
0.003568825178730639, 0.003586201440546166, 0.003603757056536316, 0.003621496464384588,
0.003639424240937217, 0.003657545108379068, 0.003675863940735269, 0.003694385770723563,
0.003713115796977806, 0.003732059391668707, 0.003751222108547281, 0.003770609691440940,
0.003790228083232539, 0.003810083435355216, 0.003830182117840641, 0.003850530729957835,
0.003871136111486317, 0.003892005354668437, 0.003913145816891062, 0.003934565134149914,
0.003956271235355358, 0.003978272357543333, 0.004000577062061084, 0.004023194251800533,
0.004046133189565926, 0.004069403517661885, 0.004093015278800460, 0.004116978938436600,
0.004141305408647655, 0.004166006073685835, 0.004191092817346642, 0.004216578052307351,
0.004242474751606884, 0.004268796482457593, 0.004295557442594244, 0.004322772499391836,
0.004350457232007221, 0.004378627976825644, 0.004407301876525049, 0.004436496933105327,
0.004466232065271192, 0.004496527170598785, 0.004527403192966406, 0.004558882195791591,
0.004590987441673855, 0.004623743479123199, 0.004657176237135574, 0.004691313128472929,
0.004726183162616859, 0.004761817069491636, 0.004798247435199299, 0.004835508851176451,
0.004873638078381815, 0.004912674228345848, 0.004952658963181422, 0.004993636716962402,
0.005035654941235035, 0.005078764377854039, 0.005123019362831771, 0.005168478165478940,
0.005215203367812893, 0.005263262290042703, 0.005312727468930079, 0.005363677197016692,
0.005416196132139284, 0.005470375988385734, 0.005526316321746716, 0.005584125426278286,
0.005643921359735682, 0.005705833121505521, 0.005770002010457520, 0.005836583196307310,
0.005905747545561058, 0.005977683752542928, 0.006052600837980204, 0.006130731092920838,
0.006212333565464245, 0.006297698213369562, 0.006387150879090475, 0.006481059288027780,
0.006579840329791975, 0.006683968961788356, 0.006793989182803495, 0.006910527673723577,
0.007034310911336661, 0.007166186857056056, 0.007307152748134871, 0.007458391141830445,
0.007621317291194862, 0.007797642342679434, 0.007989459040836144, 0.008199360125510702,
0.008430605346682607, 0.008687362737884952, 0.008975066840784529, 0.009300967772353674,
0.009675004947253041, 0.010111261142904171, 0.010630518154258861, 0.011265064987797335,
0.012068570920629962, 0.013138877484087819, 0.014680138359337902, 0.017222609470315398,
0.022898298717268672];
pub static ZIG_EXP_R: f64 = 7.697117470131050077;
pub static ZIG_EXP_X: [f64, .. 257] =
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
0.000000000000000000];
pub static ZIG_EXP_F: [f64, .. 257] =
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
1.000000000000000000];
pub static ZIG_EXP_F_DIFF: [f64, .. 257] =
[0.000000000000000000, 0.000287067661533533, 0.000513134928485678, 0.000569030497974398,
0.000609667963417335, 0.000642831049855169, 0.000671465984262828, 0.000697030342996893,
0.000720360862708599, 0.000741986223663093, 0.000762263730113694, 0.000781447246315807,
0.000799724254382053, 0.000817237547791934, 0.000834098656693235, 0.000850396538527769,
0.000866203416804620, 0.000881578828420777, 0.000896572504999613, 0.000911226471926952,
0.000925576608509206, 0.000939653828282008, 0.000953484986066785, 0.000967093584871414,
0.000980500333784669, 0.000993723593313716, 0.001006779734568374, 0.001019683431705467,
0.001032447902101660, 0.001045085105172934, 0.001057605908173612, 0.001070020225402434,
0.001082337135821582, 0.001094564983022843, 0.001106711460658764, 0.001118783685829211,
0.001130788262427001, 0.001142731336065933, 0.001154618641914802, 0.001166455546523074,
0.001178247084534012, 0.001189997991027938, 0.001201712730115490, 0.001213395520299268,
0.001225050357040701, 0.001236681032901414, 0.001248291155571943, 0.001259884164055092,
0.001271463343231895, 0.001283031837006378, 0.001294592660197942, 0.001306148709326875,
0.001317702772419903, 0.001329257537945404, 0.001340815602974395, 0.001352379480650950,
0.001363951607045839, 0.001375534347457789, 0.001387130002219621, 0.001398740812059381,
0.001410368963061376, 0.001422016591266340, 0.001433685786946429, 0.001445378598586011,
0.001457097036596827, 0.001468843076792140, 0.001480618663643060, 0.001492425713336909,
0.001504266116655995, 0.001516141741693663, 0.001528054436422108, 0.001540006031125918,
0.001551998340713470, 0.001564033166917514, 0.001576112300394977, 0.001588237522735750,
0.001600410608388780, 0.001612633326513305, 0.001624907442762655, 0.001637234721007311,
0.001649616925003372, 0.001662055820012304, 0.001674553174376953, 0.001687110761059388,
0.001699730359144919, 0.001712413755316500, 0.001725162745304071, 0.001737979135312442,
0.001750864743431488, 0.001763821401032123, 0.001776850954151601, 0.001789955264870927,
0.001803136212688003, 0.001816395695889220, 0.001829735632922019, 0.001843157963772116,
0.001856664651347151, 0.001870257682870316, 0.001883939071285826, 0.001897710856679738,
0.001911575107717528, 0.001925533923102574, 0.001939589433056721, 0.001953743800826108,
0.001967999224215228, 0.001982357937151347, 0.001996822211282223, 0.002011394357609747,
0.002026076728162574, 0.002040871717710169, 0.002055781765521847, 0.002070809357173103,
0.002085957026402963, 0.002101227357025226, 0.002116622984897121, 0.002132146599948981,
0.002147800948277823, 0.002163588834309782, 0.002179513123034188, 0.002195576742314159,
0.002211782685277469, 0.002228134012792427, 0.002244633856033434, 0.002261285419141418,
0.002278091981983449, 0.002295056903017983, 0.002312183622271174, 0.002329475664429648,
0.002346936642057179, 0.002364570258941101, 0.002382380313575932, 0.002400370702791893,
0.002418545425535629, 0.002436908586812392, 0.002455464401797752, 0.002474217200128692,
0.002493171430384328, 0.002512331664766249, 0.002531702603989994, 0.002551289082400404,
0.002571096073321844, 0.002591128694658967, 0.002611392214760672, 0.002631892058563845,
0.002652633814032662, 0.002673623238910738, 0.002694866267805934, 0.002716369019626269,
0.002738137805389534, 0.002760179136428037, 0.002782499733014893, 0.002805106533435520,
0.002828006703534697, 0.002851207646767162, 0.002874717014785921, 0.002898542718600849,
0.002922692940346749, 0.002947176145699226, 0.002972001096982591, 0.002997176867015228,
0.003022712853742948, 0.003048618795714386, 0.003074904788455568, 0.003101581301807876,
0.003128659198296080, 0.003156149752600867, 0.003184064672214937, 0.003212416119368622,
0.003241216734320596, 0.003270479660111680, 0.003300218568896729, 0.003330447689969929,
0.003361181839619420, 0.003392436452949343, 0.003424227617828290, 0.003456572111131984,
0.003489487437467131, 0.003522991870580083, 0.003557104497672658, 0.003591845266868621,
0.003627235038102472, 0.003663295637722386, 0.003700049917134574, 0.003737521815846301,
0.003775736429304177, 0.003814720081962375, 0.003854500406067995, 0.003895106426696382,
0.003936568653631844, 0.003978919180756157, 0.004022191793678687, 0.004066422086428989,
0.004111647588127876, 0.004157907900659452, 0.004205244848493050, 0.004253702641940915,
0.004303328055299205, 0.004354170621502118, 0.004406282845128784, 0.004459720435841752,
0.004514542564613699, 0.004570812145417769, 0.004628596145424491, 0.004687965927177740,
0.004748997626717266, 0.004811772572194672, 0.004876377748206484, 0.004942906311860507,
0.005011458167522187, 0.005082140608288488, 0.005155069033533799, 0.005230367753417398,
0.005308170893076836, 0.005388623411430704, 0.005471882252147620, 0.005558117647517014,
0.005647514599798176, 0.005740274569295156, 0.005836617404105682, 0.005936783553485037,
0.006041036615386131, 0.006149666279423593, 0.006262991739818591, 0.006381365669577810,
0.006505178868201678, 0.006634865721946159, 0.006770910649812723, 0.006913855752425535,
0.007064309938019209, 0.007222959874423007, 0.007390583214465396, 0.007568064673498798,
0.007756415714389786, 0.007956798835585532, 0.008170557788458321, 0.008399255510700199,
0.008644722212900025, 0.008909116987305010, 0.009195007664428712, 0.009505475652925033,
0.009844255532840629, 0.010215923852312625, 0.010626158965710175, 0.011082105722287849,
0.011592898788496009, 0.012170432837851575, 0.012830529553771619, 0.013594766864701180,
0.014493463190219380, 0.015570784932380066, 0.016894014550512759, 0.018571645120042057,
0.020792203980939394, 0.023918831757214210, 0.028765597544542998, 0.037673750936428774,
0.061856319137823523];

View File

@ -564,7 +564,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) {
}
}
#[test]
#[cfg(test)]
struct P {a: int, b: float}
#[test]

View File

@ -207,4 +207,3 @@ pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
use core::sys::size_of;
(ptr as int + count * (size_of::<T>() as int)) as *mut T
}

View File

@ -56,4 +56,3 @@ impl<W: Writer> WriterChan<W> {
impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> {
fn send(&self, _x: ~[u8]) { fail!() }
}

View File

@ -9,13 +9,9 @@
// except according to those terms.
use prelude::*;
use super::misc::PathLike;
use super::support::PathLike;
use super::{Reader, Writer, Seek, Close};
use super::{IoError, SeekStyle};
/// Open a file with the default FileMode and FileAccess
/// # XXX are there sane defaults here?
pub fn open_file<P: PathLike>(_path: &P) -> FileStream { fail!() }
use super::SeekStyle;
/// # XXX
/// * Ugh, this is ridiculous. What is the best way to represent these options?
@ -46,7 +42,7 @@ impl FileStream {
pub fn open<P: PathLike>(_path: &P,
_mode: FileMode,
_access: FileAccess
) -> Result<FileStream, IoError> {
) -> Option<FileStream> {
fail!()
}
}

View File

@ -17,7 +17,7 @@
use prelude::*;
use super::*;
use cmp::min;
/// Writes to an owned, growable byte vector
pub struct MemWriter {
@ -29,13 +29,15 @@ impl MemWriter {
}
impl Writer for MemWriter {
fn write(&mut self, _buf: &[u8]) { fail!() }
fn write(&mut self, buf: &[u8]) {
self.buf.push_all(buf)
}
fn flush(&mut self) { /* no-op */ }
}
impl Seek for MemWriter {
fn tell(&self) -> u64 { fail!() }
fn tell(&self) -> u64 { self.buf.len() as u64 }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}
@ -77,13 +79,27 @@ impl MemReader {
}
impl Reader for MemReader {
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
{ if self.eof() { return None; } }
fn eof(&mut self) -> bool { fail!() }
let write_len = min(buf.len(), self.buf.len() - self.pos);
{
let input = self.buf.slice(self.pos, self.pos + write_len);
let output = vec::mut_slice(buf, 0, write_len);
assert!(input.len() == output.len());
vec::bytes::copy_memory(output, input, write_len);
}
self.pos += write_len;
assert!(self.pos <= self.buf.len());
return Some(write_len);
}
fn eof(&mut self) -> bool { self.pos == self.buf.len() }
}
impl Seek for MemReader {
fn tell(&self) -> u64 { fail!() }
fn tell(&self) -> u64 { self.pos as u64 }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}
@ -163,4 +179,43 @@ impl<'self> Seek for BufReader<'self> {
fn tell(&self) -> u64 { fail!() }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}
}
#[cfg(test)]
mod test {
use prelude::*;
use super::*;
#[test]
fn test_mem_writer() {
let mut writer = MemWriter::new();
assert!(writer.tell() == 0);
writer.write([0]);
assert!(writer.tell() == 1);
writer.write([1, 2, 3]);
writer.write([4, 5, 6, 7]);
assert!(writer.tell() == 8);
assert!(writer.inner() == ~[0, 1, 2, 3, 4, 5 , 6, 7]);
}
#[test]
fn test_mem_reader() {
let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert!(reader.read(buf) == Some(0));
assert!(reader.tell() == 0);
let mut buf = [0];
assert!(reader.read(buf) == Some(1));
assert!(reader.tell() == 1);
assert!(buf == [0]);
let mut buf = [0, ..4];
assert!(reader.read(buf) == Some(4));
assert!(reader.tell() == 5);
assert!(buf == [1, 2, 3, 4]);
assert!(reader.read(buf) == Some(3));
assert!(buf.slice(0, 3) == [5, 6, 7]);
assert!(reader.eof());
assert!(reader.read(buf) == None);
assert!(reader.eof());
}
}

View File

@ -11,7 +11,13 @@
/*! Synchronous I/O
This module defines the Rust interface for synchronous I/O.
It supports file access,
It models byte-oriented input and output with the Reader and Writer traits.
Types that implement both `Reader` and `Writer` and called 'streams',
and automatically implement trait `Stream`.
Implementations are provided for common I/O streams like
file, TCP, UDP, Unix domain sockets.
Readers and Writers may be composed to add capabilities like string
parsing, encoding, and compression.
This will likely live in core::io, not core::rt::io.
@ -27,44 +33,177 @@ Some examples of obvious things you might want to do
* Read a complete file to a string, (converting newlines?)
let contents = open("message.txt").read_to_str(); // read_to_str??
let contents = File::open("message.txt").read_to_str(); // read_to_str??
* Write a line to a file
let file = FileStream::open("message.txt", Create, Write);
let file = File::open("message.txt", Create, Write);
file.write_line("hello, file!");
* Iterate over the lines of a file
do File::open("message.txt").each_line |line| {
println(line)
}
* Pull the lines of a file into a vector of strings
let lines = File::open("message.txt").line_iter().to_vec();
* Make an simple HTTP request
let socket = TcpStream::open("localhost:8080");
socket.write_line("GET / HTTP/1.0");
socket.write_line("");
let response = socket.read_to_end();
* Connect based on URL? Requires thinking about where the URL type lives
and how to make protocol handlers extensible, e.g. the "tcp" protocol
yields a `TcpStream`.
connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /");
connect("tcp://localhost:8080");
# Terms
* reader
* writer
* stream
* Blocking vs. non-blocking
* synchrony and asynchrony
* Reader - An I/O source, reads bytes into a buffer
* Writer - An I/O sink, writes bytes from a buffer
* Stream - Typical I/O sources like files and sockets are both Readers and Writers,
and are collectively referred to a `streams`.
* Decorator - A Reader or Writer that composes with others to add additional capabilities
such as encoding or decoding
I tend to call this implementation non-blocking, because performing I/O
doesn't block the progress of other tasks. Is that how we want to present
it, 'synchronous but non-blocking'?
# Blocking and synchrony
When discussing I/O you often hear the terms 'synchronous' and
'asynchronous', along with 'blocking' and 'non-blocking' compared and
contrasted. A synchronous I/O interface performs each I/O operation to
completion before proceeding to the next. Synchronous interfaces are
usually used in imperative style as a sequence of commands. An
asynchronous interface allows multiple I/O requests to be issued
simultaneously, without waiting for each to complete before proceeding
to the next.
Asynchronous interfaces are used to achieve 'non-blocking' I/O. In
traditional single-threaded systems, performing a synchronous I/O
operation means that the program stops all activity (it 'blocks')
until the I/O is complete. Blocking is bad for performance when
there are other computations that could be done.
Asynchronous interfaces are most often associated with the callback
(continuation-passing) style popularised by node.js. Such systems rely
on all computations being run inside an event loop which maintains a
list of all pending I/O events; when one completes the registered
callback is run and the code that made the I/O request continiues.
Such interfaces achieve non-blocking at the expense of being more
difficult to reason about.
Rust's I/O interface is synchronous - easy to read - and non-blocking by default.
Remember that Rust tasks are 'green threads', lightweight threads that
are multiplexed onto a single operating system thread. If that system
thread blocks then no other task may proceed. Rust tasks are
relatively cheap to create, so as long as other tasks are free to
execute then non-blocking code may be written by simply creating a new
task.
When discussing blocking in regards to Rust's I/O model, we are
concerned with whether performing I/O blocks other Rust tasks from
proceeding. In other words, when a task calls `read`, it must then
wait (or 'sleep', or 'block') until the call to `read` is complete.
During this time, other tasks may or may not be executed, depending on
how `read` is implemented.
Rust's default I/O implementation is non-blocking; by cooperating
directly with the task scheduler it arranges to never block progress
of *other* tasks. Under the hood, Rust uses asynchronous I/O via a
per-scheduler (and hence per-thread) event loop. Synchronous I/O
requests are implemented by descheduling the running task and
performing an asynchronous request; the task is only resumed once the
asynchronous request completes.
For blocking (but possibly more efficient) implementations, look
in the `io::native` module.
# Error Handling
I/O is an area where nearly every operation can result in unexpected
errors. It should allow errors to be handled efficiently.
It needs to be convenient to use I/O when you don't care
about dealing with specific errors.
Rust's I/O employs a combination of techniques to reduce boilerplate
while still providing feedback about errors. The basic strategy:
* Errors are fatal by default, resulting in task failure
* Errors raise the `io_error` conditon which provides an opportunity to inspect
an IoError object containing details.
* Return values must have a sensible null or zero value which is returned
if a condition is handled successfully. This may be an `Option`, an empty
vector, or other designated error value.
* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`,
so that nullable values do not have to be 'unwrapped' before use.
These features combine in the API to allow for expressions like
`File::new("diary.txt").write_line("met a girl")` without having to
worry about whether "diary.txt" exists or whether the write
succeeds. As written, if either `new` or `write_line` encounters
an error the task will fail.
If you wanted to handle the error though you might write
let mut error = None;
do io_error::cond(|e: IoError| {
error = Some(e);
}).in {
File::new("diary.txt").write_line("met a girl");
}
if error.is_some() {
println("failed to write my diary");
}
XXX: Need better condition handling syntax
In this case the condition handler will have the opportunity to
inspect the IoError raised by either the call to `new` or the call to
`write_line`, but then execution will continue.
So what actually happens if `new` encounters an error? To understand
that it's important to know that what `new` returns is not a `File`
but an `Option<File>`. If the file does not open, and the condition
is handled, then `new` will simply return `None`. Because there is an
implementation of `Writer` (the trait required ultimately required for
types to implement `write_line`) there is no need to inspect or unwrap
the `Option<File>` and we simply call `write_line` on it. If `new`
returned a `None` then the followup call to `write_line` will also
raise an error.
## Concerns about this strategy
This structure will encourage a programming style that is prone
to errors similar to null pointer dereferences.
In particular code written to ignore errors and expect conditions to be unhandled
will start passing around null or zero objects when wrapped in a condition handler.
* XXX: How should we use condition handlers that return values?
# Issues withi/o scheduler affinity, work stealing, task pinning
# Resource management
* `close` vs. RAII
# Paths and URLs
# Paths, URLs and overloaded constructors
# std
# Scope
In scope for core
* Url?
Some I/O things don't belong in core
@ -73,7 +212,12 @@ Some I/O things don't belong in core
- http
- flate
# XXX
Out of scope
* Async I/O. We'll probably want it eventually
# XXX Questions and issues
* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose.
Overloading would be nice.
@ -83,6 +227,7 @@ Some I/O things don't belong in core
* fsync
* relationship with filesystem querying, Directory, File types etc.
* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic?
* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>?
* Trait for things that are both readers and writers, Stream?
* How to handle newline conversion
* String conversion
@ -92,6 +237,7 @@ Some I/O things don't belong in core
* Do we need `close` at all? dtors might be good enough
* How does I/O relate to the Iterator trait?
* std::base64 filters
* Using conditions is a big unknown since we don't have much experience with them
*/
@ -104,25 +250,29 @@ pub use self::stdio::stderr;
pub use self::stdio::print;
pub use self::stdio::println;
pub use self::file::open_file;
pub use self::file::FileStream;
pub use self::net::Listener;
pub use self::net::ip::IpAddr;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
pub use self::net::udp::UdpStream;
// Some extension traits that all Readers and Writers get.
pub use self::util::ReaderUtil;
pub use self::util::ReaderByteConversions;
pub use self::util::WriterByteConversions;
pub use self::extensions::ReaderUtil;
pub use self::extensions::ReaderByteConversions;
pub use self::extensions::WriterByteConversions;
/// Synchronous, non-blocking file I/O.
pub mod file;
/// Synchronous, non-blocking network I/O.
#[path = "net/mod.rs"]
pub mod net;
pub mod net {
pub mod tcp;
pub mod udp;
pub mod ip;
#[cfg(unix)]
pub mod unix;
pub mod http;
}
/// Readers and Writers for memory buffers and strings.
pub mod mem;
@ -130,6 +280,10 @@ pub mod mem;
/// Non-blocking access to stdin, stdout, stderr
pub mod stdio;
/// Implementations for Option
#[cfg(not(stage0))] // Requires condition! fixes
mod option;
/// Basic stream compression. XXX: Belongs with other flate code
pub mod flate;
@ -137,10 +291,10 @@ pub mod flate;
pub mod comm_adapters;
/// Extension traits
mod util;
mod extensions;
/// Non-I/O things needed by the I/O module
mod misc;
mod support;
/// Thread-blocking implementations
pub mod native {
@ -170,12 +324,14 @@ pub struct IoError {
detail: Option<~str>
}
#[deriving(Eq)]
pub enum IoErrorKind {
FileNotFound,
FilePermission,
ConnectionFailed,
Closed,
OtherIoError
OtherIoError,
PreviousIoError
}
// XXX: Can't put doc comments on macros
@ -208,9 +364,9 @@ pub trait Reader {
/// println(reader.read_line());
/// }
///
/// # XXX
/// # Failue
///
/// What does this return if the Reader is in an error state?
/// Returns `true` on failure.
fn eof(&mut self) -> bool;
}
@ -250,9 +406,30 @@ pub enum SeekStyle {
/// * Are `u64` and `i64` the right choices?
pub trait Seek {
fn tell(&self) -> u64;
/// Seek to an offset in a stream
///
/// A successful seek clears the EOF indicator.
///
/// # XXX
///
/// * What is the behavior when seeking past the end of a stream?
fn seek(&mut self, pos: i64, style: SeekStyle);
}
/// A listener is a value that listens for connections
pub trait Listener<S> {
/// Wait for and accept an incoming connection
///
/// Returns `None` on timeout.
///
/// # Failure
///
/// Raises `io_error` condition. If the condition is handled,
/// then `accept` returns `None`.
fn accept(&mut self) -> Option<S>;
}
/// Common trait for decorator types.
///
/// Provides accessors to get the inner, 'decorated' values. The I/O library
@ -278,3 +455,16 @@ pub trait Decorator<T> {
/// Take a mutable reference to the decorated value
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T;
}
pub fn standard_error(kind: IoErrorKind) -> IoError {
match kind {
PreviousIoError => {
IoError {
kind: PreviousIoError,
desc: "Failing due to a previous I/O error",
detail: None
}
}
_ => fail!()
}
}

View File

@ -12,4 +12,3 @@ pub enum IpAddr {
Ipv4(u8, u8, u8, u8, u16),
Ipv6
}

View File

@ -9,14 +9,13 @@
// except according to those terms.
use prelude::*;
use super::*;
use super::super::*;
use super::ip::IpAddr;
pub struct TcpStream;
impl TcpStream {
pub fn connect(_addr: IpAddr) -> Result<TcpStream, IoError> {
pub fn connect(_addr: IpAddr) -> Option<TcpStream> {
fail!()
}
}
@ -40,7 +39,7 @@ impl Close for TcpStream {
pub struct TcpListener;
impl TcpListener {
pub fn new(_addr: IpAddr) -> TcpListener {
pub fn bind(_addr: IpAddr) -> Option<TcpListener> {
fail!()
}
}
@ -48,3 +47,28 @@ impl TcpListener {
impl Listener<TcpStream> for TcpListener {
fn accept(&mut self) -> Option<TcpStream> { fail!() }
}
#[cfg(test)]
mod test {
#[test] #[ignore]
fn smoke_test() {
/*do run_in_newsched_task {
let addr = next_test_ip4();
do spawn_immediately {
let listener = TcpListener::bind(addr);
do listener.accept() {
let mut buf = [0];
listener.read(buf);
assert!(buf[0] == 99);
}
}
do spawn_immediately {
let stream = TcpStream::connect(addr);
stream.write([99]);
}
}*/
}
}

View File

@ -9,14 +9,13 @@
// except according to those terms.
use prelude::*;
use super::*;
use super::super::*;
use super::ip::IpAddr;
pub struct UdpStream;
impl UdpStream {
pub fn connect(_addr: IpAddr) -> Result<UdpStream, IoError> {
pub fn connect(_addr: IpAddr) -> Option<UdpStream> {
fail!()
}
}
@ -40,7 +39,7 @@ impl Close for UdpStream {
pub struct UdpListener;
impl UdpListener {
pub fn new(_addr: IpAddr) -> UdpListener {
pub fn bind(_addr: IpAddr) -> Option<UdpListener> {
fail!()
}
}
@ -48,4 +47,3 @@ impl UdpListener {
impl Listener<UdpStream> for UdpListener {
fn accept(&mut self) -> Option<UdpStream> { fail!() }
}

View File

@ -9,14 +9,13 @@
// except according to those terms.
use prelude::*;
use super::*;
use super::super::*;
use super::super::misc::PathLike;
use super::super::support::PathLike;
pub struct UnixStream;
impl UnixStream {
pub fn connect<P: PathLike>(_path: &P) -> Result<UnixStream, IoError> {
pub fn connect<P: PathLike>(_path: &P) -> Option<UnixStream> {
fail!()
}
}
@ -40,7 +39,7 @@ impl Close for UnixStream {
pub struct UnixListener;
impl UnixListener {
pub fn new<P: PathLike>(_path: &P) -> UnixListener {
pub fn bind<P: PathLike>(_path: &P) -> Option<UnixListener> {
fail!()
}
}
@ -48,4 +47,3 @@ impl UnixListener {
impl Listener<UnixStream> for UnixListener {
fn accept(&mut self) -> Option<UnixStream> { fail!() }
}

153
src/libcore/rt/io/option.rs Normal file
View File

@ -0,0 +1,153 @@
// Copyright 2013 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.
//! Implementations of I/O traits for the Option type
//!
//! I/O constructors return option types to allow errors to be handled.
//! These implementations allow e.g. `Option<FileStream>` to be used
//! as a `Reader` without unwrapping the option first.
//!
//! # XXX Seek and Close
use option::*;
use super::{Reader, Writer, Listener};
use super::{standard_error, PreviousIoError, io_error, IoError};
fn prev_io_error() -> IoError {
standard_error(PreviousIoError)
}
impl<W: Writer> Writer for Option<W> {
fn write(&mut self, buf: &[u8]) {
match *self {
Some(ref mut writer) => writer.write(buf),
None => io_error::cond.raise(prev_io_error())
}
}
fn flush(&mut self) {
match *self {
Some(ref mut writer) => writer.flush(),
None => io_error::cond.raise(prev_io_error())
}
}
}
impl<R: Reader> Reader for Option<R> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match *self {
Some(ref mut reader) => reader.read(buf),
None => {
io_error::cond.raise(prev_io_error());
None
}
}
}
fn eof(&mut self) -> bool {
match *self {
Some(ref mut reader) => reader.eof(),
None => {
io_error::cond.raise(prev_io_error());
true
}
}
}
}
impl<L: Listener<S>, S> Listener<S> for Option<L> {
fn accept(&mut self) -> Option<S> {
match *self {
Some(ref mut listener) => listener.accept(),
None => {
io_error::cond.raise(prev_io_error());
None
}
}
}
}
#[cfg(test)]
mod test {
use option::*;
use super::super::mem::*;
use rt::test::*;
use super::super::{PreviousIoError, io_error};
#[test]
fn test_option_writer() {
do run_in_newsched_task {
let mut writer: Option<MemWriter> = Some(MemWriter::new());
writer.write([0, 1, 2]);
writer.flush();
assert!(writer.unwrap().inner() == ~[0, 1, 2]);
}
}
#[test]
fn test_option_writer_error() {
do run_in_newsched_task {
let mut writer: Option<MemWriter> = None;
let mut called = false;
do io_error::cond.trap(|err| {
assert!(err.kind == PreviousIoError);
called = true;
}).in {
writer.write([0, 0, 0]);
}
assert!(called);
let mut called = false;
do io_error::cond.trap(|err| {
assert!(err.kind == PreviousIoError);
called = true;
}).in {
writer.flush();
}
assert!(called);
}
}
#[test]
fn test_option_reader() {
do run_in_newsched_task {
let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
let mut buf = [0, 0];
reader.read(buf);
assert!(buf == [0, 1]);
assert!(!reader.eof());
}
}
#[test]
fn test_option_reader_error() {
let mut reader: Option<MemReader> = None;
let mut buf = [];
let mut called = false;
do io_error::cond.trap(|err| {
assert!(err.kind == PreviousIoError);
called = true;
}).in {
reader.read(buf);
}
assert!(called);
let mut called = false;
do io_error::cond.trap(|err| {
assert!(err.kind == PreviousIoError);
called = true;
}).in {
assert!(reader.eof());
}
assert!(called);
}
}

View File

@ -0,0 +1,80 @@
// Copyright 2013 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.
//! The local, garbage collected heap
use libc::{c_void, uintptr_t, size_t};
use ops::Drop;
type MemoryRegion = c_void;
type BoxedRegion = c_void;
pub type OpaqueBox = c_void;
pub type TypeDesc = c_void;
pub struct LocalHeap {
memory_region: *MemoryRegion,
boxed_region: *BoxedRegion
}
impl LocalHeap {
pub fn new() -> LocalHeap {
unsafe {
// Don't need synchronization for the single-threaded local heap
let synchronized = false as uintptr_t;
// XXX: These usually come from the environment
let detailed_leaks = false as uintptr_t;
let poison_on_free = false as uintptr_t;
let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free);
assert!(region.is_not_null());
let boxed = rust_new_boxed_region(region, poison_on_free);
assert!(boxed.is_not_null());
LocalHeap {
memory_region: region,
boxed_region: boxed
}
}
}
pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
}
}
pub fn free(&mut self, box: *OpaqueBox) {
unsafe {
return rust_boxed_region_free(self.boxed_region, box);
}
}
}
impl Drop for LocalHeap {
fn finalize(&self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);
rust_delete_memory_region(self.memory_region);
}
}
}
extern {
fn rust_new_memory_region(synchronized: uintptr_t,
detailed_leaks: uintptr_t,
poison_on_free: uintptr_t) -> *MemoryRegion;
fn rust_delete_memory_region(region: *MemoryRegion);
fn rust_new_boxed_region(region: *MemoryRegion,
poison_on_free: uintptr_t) -> *BoxedRegion;
fn rust_delete_boxed_region(region: *BoxedRegion);
fn rust_boxed_region_malloc(region: *BoxedRegion,
td: *TypeDesc,
size: size_t) -> *OpaqueBox;
fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox);
}

View File

@ -0,0 +1,223 @@
// Copyright 2013 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.
//! Language-level runtime services that should reasonably expected
//! to be available 'everywhere'. Local heaps, GC, unwinding,
//! local storage, and logging. Even a 'freestanding' Rust would likely want
//! to implement this.
//! Local services may exist in at least three different contexts:
//! when running as a task, when running in the scheduler's context,
//! or when running outside of a scheduler but with local services
//! (freestanding rust with local services?).
use prelude::*;
use libc::{c_void, uintptr_t};
use cast::transmute;
use super::sched::local_sched;
use super::local_heap::LocalHeap;
pub struct LocalServices {
heap: LocalHeap,
gc: GarbageCollector,
storage: LocalStorage,
logger: Logger,
unwinder: Option<Unwinder>,
destroyed: bool
}
pub struct GarbageCollector;
pub struct LocalStorage(*c_void, Option<~fn(*c_void)>);
pub struct Logger;
pub struct Unwinder {
unwinding: bool,
}
impl LocalServices {
pub fn new() -> LocalServices {
LocalServices {
heap: LocalHeap::new(),
gc: GarbageCollector,
storage: LocalStorage(ptr::null(), None),
logger: Logger,
unwinder: Some(Unwinder { unwinding: false }),
destroyed: false
}
}
pub fn without_unwinding() -> LocalServices {
LocalServices {
heap: LocalHeap::new(),
gc: GarbageCollector,
storage: LocalStorage(ptr::null(), None),
logger: Logger,
unwinder: None,
destroyed: false
}
}
pub fn run(&mut self, f: &fn()) {
// This is just an assertion that `run` was called unsafely
// and this instance of LocalServices is still accessible.
do borrow_local_services |sched| {
assert!(ptr::ref_eq(sched, self));
}
match self.unwinder {
Some(ref mut unwinder) => {
// If there's an unwinder then set up the catch block
unwinder.try(f);
}
None => {
// Otherwise, just run the body
f()
}
}
self.destroy();
}
/// Must be called manually before finalization to clean up
/// thread-local resources. Some of the routines here expect
/// LocalServices to be available recursively so this must be
/// called unsafely, without removing LocalServices from
/// thread-local-storage.
fn destroy(&mut self) {
// This is just an assertion that `destroy` was called unsafely
// and this instance of LocalServices is still accessible.
do borrow_local_services |sched| {
assert!(ptr::ref_eq(sched, self));
}
match self.storage {
LocalStorage(ptr, Some(ref dtor)) => {
(*dtor)(ptr)
}
_ => ()
}
self.destroyed = true;
}
}
impl Drop for LocalServices {
fn finalize(&self) { assert!(self.destroyed) }
}
// Just a sanity check to make sure we are catching a Rust-thrown exception
static UNWIND_TOKEN: uintptr_t = 839147;
impl Unwinder {
pub fn try(&mut self, f: &fn()) {
use sys::Closure;
unsafe {
let closure: Closure = transmute(f);
let code = transmute(closure.code);
let env = transmute(closure.env);
let token = rust_try(try_fn, code, env);
assert!(token == 0 || token == UNWIND_TOKEN);
}
extern fn try_fn(code: *c_void, env: *c_void) {
unsafe {
let closure: Closure = Closure {
code: transmute(code),
env: transmute(env),
};
let closure: &fn() = transmute(closure);
closure();
}
}
extern {
#[rust_stack]
fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t;
}
}
pub fn begin_unwind(&mut self) -> ! {
self.unwinding = true;
unsafe {
rust_begin_unwind(UNWIND_TOKEN);
return transmute(());
}
extern {
fn rust_begin_unwind(token: uintptr_t);
}
}
}
/// Borrow a pointer to the installed local services.
/// Fails (likely aborting the process) if local services are not available.
pub fn borrow_local_services(f: &fn(&mut LocalServices)) {
do local_sched::borrow |sched| {
match sched.current_task {
Some(~ref mut task) => {
f(&mut task.local_services)
}
None => {
fail!(~"no local services for schedulers yet")
}
}
}
}
pub unsafe fn unsafe_borrow_local_services() -> &mut LocalServices {
use cast::transmute_mut_region;
match local_sched::unsafe_borrow().current_task {
Some(~ref mut task) => {
transmute_mut_region(&mut task.local_services)
}
None => {
fail!(~"no local services for schedulers yet")
}
}
}
#[cfg(test)]
mod test {
use rt::test::*;
#[test]
fn local_heap() {
do run_in_newsched_task() {
let a = @5;
let b = a;
assert!(*a == 5);
assert!(*b == 5);
}
}
#[test]
fn tls() {
use task::local_data::*;
do run_in_newsched_task() {
unsafe {
fn key(_x: @~str) { }
local_data_set(key, @~"data");
assert!(*local_data_get(key).get() == ~"data");
fn key2(_x: @~str) { }
local_data_set(key2, @~"data");
assert!(*local_data_get(key2).get() == ~"data");
}
}
}
#[test]
fn unwind() {
do run_in_newsched_task() {
let result = spawntask_try(||());
assert!(result.is_ok());
let result = spawntask_try(|| fail!());
assert!(result.is_err());
}
}
}

View File

@ -8,30 +8,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*! The Rust runtime, including the scheduler and I/O interface */
#[doc(hidden)];
use libc::c_char;
// Some basic logging
macro_rules! rtdebug_ (
($( $arg:expr),+) => ( {
dumb_println(fmt!( $($arg),+ ));
fn dumb_println(s: &str) {
use io::WriterUtil;
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
dbg.write_str(s);
dbg.write_str("\n");
}
} )
)
// An alternate version with no output, for turning off logging
macro_rules! rtdebug (
($( $arg:expr),+) => ( $(let _ = $arg)*; )
)
#[path = "sched/mod.rs"]
mod sched;
mod rtio;
@ -48,6 +30,12 @@ mod stack;
mod context;
mod thread;
pub mod env;
pub mod local_services;
mod local_heap;
/// Tools for testing the runtime
#[cfg(test)]
pub mod test;
pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int {
use self::sched::{Scheduler, Task};
@ -72,7 +60,7 @@ pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int {
/// Different runtime services are available depending on context.
#[deriving(Eq)]
pub enum RuntimeContext {
// Only default services, e.g. exchange heap
// Only the exchange heap is available
GlobalContext,
// The scheduler may be accessed
SchedulerContext,
@ -139,24 +127,3 @@ fn test_context() {
sched.run();
}
}
// For setting up tests of the new scheduler
#[cfg(test)]
pub fn run_in_newsched_task(f: ~fn()) {
use cell::Cell;
use unstable::run_in_bare_thread;
use self::sched::Task;
use self::uvio::UvEventLoop;
let f = Cell(Cell(f));
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let f = f.take();
let task = ~do Task::new(&mut sched.stack_pool) {
(f.take())();
};
sched.task_queue.push_back(task);
sched.run();
}
}

View File

@ -143,4 +143,3 @@ fn borrow_smoke_test() {
}
let _scheduler = take();
}

View File

@ -16,6 +16,7 @@ use super::work_queue::WorkQueue;
use super::stack::{StackPool, StackSegment};
use super::rtio::{EventLoop, EventLoopObject};
use super::context::Context;
use super::local_services::LocalServices;
use cell::Cell;
#[cfg(test)] use super::uvio::UvEventLoop;
@ -38,7 +39,7 @@ pub struct Scheduler {
/// Always valid when a task is executing, otherwise not
priv saved_context: Context,
/// The currently executing task
priv current_task: Option<~Task>,
current_task: Option<~Task>,
/// An action performed after a context switch on behalf of the
/// code running before the context switch
priv cleanup_job: Option<CleanupJob>
@ -147,7 +148,7 @@ pub impl Scheduler {
}
}
// Control never reaches here
abort!("control reached end of task");
}
fn schedule_new_task(~self, task: ~Task) {
@ -324,10 +325,18 @@ pub struct Task {
/// These are always valid when the task is not running, unless
/// the task is dead
priv saved_context: Context,
/// The heap, GC, unwinding, local storage, logging
local_services: LocalServices
}
pub impl Task {
fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task {
Task::with_local(stack_pool, LocalServices::new(), start)
}
fn with_local(stack_pool: &mut StackPool,
local_services: LocalServices,
start: ~fn()) -> Task {
let start = Task::build_start_wrapper(start);
let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE);
// NB: Context holds a pointer to that ~fn
@ -335,6 +344,7 @@ pub impl Task {
return Task {
current_stack_segment: stack,
saved_context: initial_context,
local_services: local_services
};
}
@ -347,9 +357,12 @@ pub impl Task {
unsafe {
let sched = local_sched::unsafe_borrow();
sched.run_cleanup_job();
}
start();
let sched = local_sched::unsafe_borrow();
let task = sched.current_task.get_mut_ref();
// FIXME #6141: shouldn't neet to put `start()` in another closure
task.local_services.run(||start());
}
let sched = local_sched::take();
sched.terminate_current_task();

120
src/libcore/rt/test.rs Normal file
View File

@ -0,0 +1,120 @@
// Copyright 2013 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 cell::Cell;
use result::{Result, Ok, Err};
use super::io::net::ip::{IpAddr, Ipv4};
use rt::local_services::LocalServices;
/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit. Failure of the task
/// will abort the process.
pub fn run_in_newsched_task(f: ~fn()) {
use unstable::run_in_bare_thread;
use super::sched::Task;
use super::uvio::UvEventLoop;
let f = Cell(f);
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let task = ~Task::with_local(&mut sched.stack_pool,
LocalServices::without_unwinding(),
f.take());
sched.task_queue.push_back(task);
sched.run();
}
}
/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
use super::sched::*;
let mut sched = local_sched::take();
let task = ~Task::with_local(&mut sched.stack_pool,
LocalServices::without_unwinding(),
f);
do sched.switch_running_tasks_and_then(task) |task| {
let task = Cell(task);
let sched = local_sched::take();
sched.schedule_new_task(task.take());
}
}
/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_immediately(f: ~fn()) {
use super::sched::*;
let mut sched = local_sched::take();
let task = ~Task::with_local(&mut sched.stack_pool,
LocalServices::without_unwinding(),
f);
do sched.switch_running_tasks_and_then(task) |task| {
let task = Cell(task);
do local_sched::borrow |sched| {
sched.task_queue.push_front(task.take());
}
}
}
/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
use cell::Cell;
use super::sched::*;
use task;
use unstable::finally::Finally;
// Our status variables will be filled in from the scheduler context
let mut failed = false;
let failed_ptr: *mut bool = &mut failed;
// Switch to the scheduler
let f = Cell(Cell(f));
let mut sched = local_sched::take();
do sched.deschedule_running_task_and_then() |old_task| {
let old_task = Cell(old_task);
let f = f.take();
let mut sched = local_sched::take();
let new_task = ~do Task::new(&mut sched.stack_pool) {
do (|| {
(f.take())()
}).finally {
// Check for failure then resume the parent task
unsafe { *failed_ptr = task::failing(); }
let sched = local_sched::take();
do sched.switch_running_tasks_and_then(old_task.take()) |new_task| {
let new_task = Cell(new_task);
do local_sched::borrow |sched| {
sched.task_queue.push_front(new_task.take());
}
}
}
};
sched.resume_task_immediately(new_task);
}
if !failed { Ok(()) } else { Err(()) }
}
/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
unsafe {
return rust_dbg_next_port() as u16;
}
extern {
fn rust_dbg_next_port() -> ::libc::uintptr_t;
}
}
/// Get a unique localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
Ipv4(127, 0, 0, 1, next_test_port())
}

View File

@ -301,7 +301,8 @@ struct WatcherData {
write_cb: Option<ConnectionCallback>,
connect_cb: Option<ConnectionCallback>,
close_cb: Option<NullCallback>,
alloc_cb: Option<AllocCallback>
alloc_cb: Option<AllocCallback>,
buf: Option<Buf>
}
pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
@ -311,7 +312,8 @@ pub fn install_watcher_data<H, W: Watcher + NativeHandle<*H>>(watcher: &mut W) {
write_cb: None,
connect_cb: None,
close_cb: None,
alloc_cb: None
alloc_cb: None,
buf: None
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(watcher.native_handle(), data);

View File

@ -19,12 +19,10 @@ use super::{Loop, Watcher, Request, UvError, Buf, Callback, NativeHandle, NullCa
vec_to_uv_buf, vec_from_uv_buf};
use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6};
#[cfg(test)]
use unstable::run_in_bare_thread;
#[cfg(test)]
use super::super::thread::Thread;
#[cfg(test)]
use cell::Cell;
#[cfg(test)] use cell::Cell;
#[cfg(test)] use unstable::run_in_bare_thread;
#[cfg(test)] use super::super::thread::Thread;
#[cfg(test)] use super::super::test::*;
fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in)) {
match addr {
@ -109,21 +107,25 @@ pub impl StreamWatcher {
let req = WriteRequest::new();
let buf = vec_to_uv_buf(msg);
// XXX: Allocation
let bufs = ~[buf];
assert!(data.buf.is_none());
data.buf = Some(buf);
let bufs = [buf];
unsafe {
assert!(0 == uvll::write(req.native_handle(),
self.native_handle(),
&bufs, write_cb));
bufs, write_cb));
}
// XXX: Freeing immediately after write. Is this ok?
let _v = vec_from_uv_buf(buf);
extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
let write_request: WriteRequest = NativeHandle::from_native_handle(req);
let mut stream_watcher = write_request.stream();
write_request.delete();
let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap();
let cb = {
let data = get_watcher_data(&mut stream_watcher);
let _vec = vec_from_uv_buf(data.buf.swap_unwrap());
let cb = data.write_cb.swap_unwrap();
cb
};
let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status);
cb(stream_watcher, status);
}
@ -361,7 +363,7 @@ fn connect_close() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
// Connect to a port where nobody is listening
let addr = Ipv4(127, 0, 0, 1, 2923);
let addr = next_test_ip4();
do tcp_watcher.connect(addr) |stream_watcher, status| {
rtdebug!("tcp_watcher.connect!");
assert!(status.is_some());
@ -373,47 +375,13 @@ fn connect_close() {
}
}
#[test]
#[ignore(reason = "need a server to connect to")]
fn connect_read() {
do run_in_bare_thread() {
let mut loop_ = Loop::new();
let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = Ipv4(127, 0, 0, 1, 2924);
do tcp_watcher.connect(addr) |stream_watcher, status| {
let mut stream_watcher = stream_watcher;
rtdebug!("tcp_watcher.connect!");
assert!(status.is_none());
let alloc: AllocCallback = |size| {
vec_to_uv_buf(vec::from_elem(size, 0))
};
do stream_watcher.read_start(alloc)
|stream_watcher, _nread, buf, status| {
let buf = vec_from_uv_buf(buf);
rtdebug!("read cb!");
if status.is_none() {
let _bytes = buf.unwrap();
rtdebug!("%s", bytes.slice(0, nread as uint).to_str());
} else {
rtdebug!("status after read: %s", status.get().to_str());
rtdebug!("closing");
stream_watcher.close(||());
}
}
}
loop_.run();
loop_.close();
}
}
#[test]
fn listen() {
do run_in_bare_thread() {
static MAX: int = 10;
let mut loop_ = Loop::new();
let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
let addr = Ipv4(127, 0, 0, 1, 2925);
let addr = next_test_ip4();
server_tcp_watcher.bind(addr);
let loop_ = loop_;
rtdebug!("listening");

View File

@ -19,10 +19,9 @@ use cell::{Cell, empty_cell};
use cast::transmute;
use super::sched::{Scheduler, local_sched};
#[cfg(test)] use super::io::net::ip::Ipv4;
#[cfg(test)] use super::sched::Task;
#[cfg(test)] use unstable::run_in_bare_thread;
#[cfg(test)] use uint;
#[cfg(test)] use unstable::run_in_bare_thread;
#[cfg(test)] use super::test::*;
pub struct UvEventLoop {
uvio: UvIoFactory
@ -319,38 +318,22 @@ impl Stream for UvStream {
}
#[test]
#[ignore(reason = "ffi struct issues")]
fn test_simple_io_no_connect() {
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let task = ~do Task::new(&mut sched.stack_pool) {
let io = unsafe { local_sched::unsafe_borrow_io() };
let addr = Ipv4(127, 0, 0, 1, 2926);
let maybe_chan = io.connect(addr);
assert!(maybe_chan.is_none());
};
sched.task_queue.push_back(task);
sched.run();
do run_in_newsched_task {
let io = unsafe { local_sched::unsafe_borrow_io() };
let addr = next_test_ip4();
let maybe_chan = io.connect(addr);
assert!(maybe_chan.is_none());
}
}
#[test]
#[ignore(reason = "ffi struct issues")]
fn test_simple_tcp_server_and_client() {
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let addr = Ipv4(127, 0, 0, 1, 2929);
do run_in_newsched_task {
let addr = next_test_ip4();
let client_task = ~do Task::new(&mut sched.stack_pool) {
unsafe {
let io = local_sched::unsafe_borrow_io();
let mut stream = io.connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.close();
}
};
let server_task = ~do Task::new(&mut sched.stack_pool) {
// Start the server first so it's listening when we connect
do spawntask_immediately {
unsafe {
let io = local_sched::unsafe_borrow_io();
let mut listener = io.bind(addr).unwrap();
@ -365,32 +348,25 @@ fn test_simple_tcp_server_and_client() {
stream.close();
listener.close();
}
};
}
// Start the server first so it listens before the client connects
sched.task_queue.push_back(server_task);
sched.task_queue.push_back(client_task);
sched.run();
do spawntask_immediately {
unsafe {
let io = local_sched::unsafe_borrow_io();
let mut stream = io.connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.close();
}
}
}
}
#[test] #[ignore(reason = "busted")]
fn test_read_and_block() {
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let addr = Ipv4(127, 0, 0, 1, 2930);
do run_in_newsched_task {
let addr = next_test_ip4();
let client_task = ~do Task::new(&mut sched.stack_pool) {
let io = unsafe { local_sched::unsafe_borrow_io() };
let mut stream = io.connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.close();
};
let server_task = ~do Task::new(&mut sched.stack_pool) {
do spawntask_immediately {
let io = unsafe { local_sched::unsafe_borrow_io() };
let mut listener = io.bind(addr).unwrap();
let mut stream = listener.listen().unwrap();
@ -426,36 +402,58 @@ fn test_read_and_block() {
stream.close();
listener.close();
};
}
do spawntask_immediately {
let io = unsafe { local_sched::unsafe_borrow_io() };
let mut stream = io.connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.close();
}
// Start the server first so it listens before the client connects
sched.task_queue.push_back(server_task);
sched.task_queue.push_back(client_task);
sched.run();
}
}
#[test] #[ignore(reason = "needs server")]
#[test]
fn test_read_read_read() {
do run_in_bare_thread {
let mut sched = ~UvEventLoop::new_scheduler();
let addr = Ipv4(127, 0, 0, 1, 2931);
do run_in_newsched_task {
let addr = next_test_ip4();
static MAX: uint = 500000;
let client_task = ~do Task::new(&mut sched.stack_pool) {
do spawntask_immediately {
unsafe {
let io = local_sched::unsafe_borrow_io();
let mut listener = io.bind(addr).unwrap();
let mut stream = listener.listen().unwrap();
let mut buf = [1, .. 2048];
let mut total_bytes_written = 0;
while total_bytes_written < MAX {
stream.write(buf);
total_bytes_written += buf.len();
}
stream.close();
listener.close();
}
}
do spawntask_immediately {
let io = unsafe { local_sched::unsafe_borrow_io() };
let mut stream = io.connect(addr).unwrap();
let mut buf = [0, .. 2048];
let mut total_bytes_read = 0;
while total_bytes_read < 500000000 {
while total_bytes_read < MAX {
let nread = stream.read(buf).unwrap();
rtdebug!("read %u bytes", nread as uint);
total_bytes_read += nread;
for uint::range(0, nread) |i| {
assert!(buf[i] == 1);
}
}
rtdebug_!("read %u bytes total", total_bytes_read as uint);
rtdebug!("read %u bytes total", total_bytes_read as uint);
stream.close();
};
sched.task_queue.push_back(client_task);
sched.run();
}
}
}

View File

@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int {
let buf_ptr = vec::raw::to_ptr(*buf_in);
let buf_cnt = vec::len(*buf_in) as i32;
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = vec::len(buf_in) as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int {

View File

@ -22,31 +22,6 @@ use str;
use task;
use vec;
pub mod rustrt {
use libc::{c_int, c_void};
use libc;
use run;
#[abi = "cdecl"]
pub extern {
unsafe fn rust_run_program(argv: **libc::c_char,
envp: *c_void,
dir: *libc::c_char,
in_fd: c_int,
out_fd: c_int,
err_fd: c_int) -> run::RunProgramResult;
unsafe fn rust_process_wait(pid: c_int) -> c_int;
}
}
pub struct RunProgramResult {
// the process id of the program, or -1 if in case of errors
pid: pid_t,
// a handle to the process - on unix this will always be NULL, but on windows it will be a
// HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
handle: *(),
}
/// A value representing a child process
pub struct Program {
priv pid: pid_t,
@ -191,21 +166,262 @@ pub fn spawn_process(prog: &str, args: &[~str],
return res.pid;
}
struct RunProgramResult {
// the process id of the program (this should never be negative)
pid: pid_t,
// a handle to the process - on unix this will always be NULL, but on windows it will be a
// HANDLE to the process, which will prevent the pid being re-used until the handle is closed.
handle: *(),
}
#[cfg(windows)]
fn spawn_process_internal(prog: &str, args: &[~str],
env: &Option<~[(~str,~str)]>,
dir: &Option<~str>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
TRUE, FALSE,
STARTF_USESTDHANDLES,
INVALID_HANDLE_VALUE,
DUPLICATE_SAME_ACCESS
};
use libc::funcs::extra::kernel32::{
GetCurrentProcess,
DuplicateHandle,
CloseHandle,
CreateProcessA
};
use libc::funcs::extra::msvcrt::get_osfhandle;
unsafe {
do with_argv(prog, args) |argv| {
do with_envp(env) |envp| {
do with_dirp(dir) |dirp| {
rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd)
let mut si = zeroed_startupinfo();
si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
si.dwFlags = STARTF_USESTDHANDLES;
let cur_proc = GetCurrentProcess();
let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE;
if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
}
if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
}
let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE;
if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
}
if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
}
let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE;
if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE {
fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error()));
}
if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error()));
}
let cmd = make_command_line(prog, args);
let mut pi = zeroed_process_information();
let mut create_err = None;
do with_envp(env) |envp| {
do with_dirp(dir) |dirp| {
do str::as_c_str(cmd) |cmdp| {
let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
ptr::mut_null(), ptr::mut_null(), TRUE,
0, envp, dirp, &mut si, &mut pi);
if created == FALSE {
create_err = Some(os::last_os_error());
}
}
}
}
CloseHandle(si.hStdInput);
CloseHandle(si.hStdOutput);
CloseHandle(si.hStdError);
for create_err.each |msg| {
fail!(fmt!("failure in CreateProcess: %s", *msg));
}
// We close the thread handle because we don't care about keeping the thread id valid,
// and we aren't keeping the thread handle around to be able to close it later. We don't
// close the process handle however because we want the process id to stay valid at least
// until the calling code closes the process handle.
CloseHandle(pi.hThread);
RunProgramResult {
pid: pi.dwProcessId as pid_t,
handle: pi.hProcess as *()
}
}
}
#[cfg(windows)]
fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
libc::types::os::arch::extra::STARTUPINFO {
cb: 0,
lpReserved: ptr::mut_null(),
lpDesktop: ptr::mut_null(),
lpTitle: ptr::mut_null(),
dwX: 0,
dwY: 0,
dwXSize: 0,
dwYSize: 0,
dwXCountChars: 0,
dwYCountCharts: 0,
dwFillAttribute: 0,
dwFlags: 0,
wShowWindow: 0,
cbReserved2: 0,
lpReserved2: ptr::mut_null(),
hStdInput: ptr::mut_null(),
hStdOutput: ptr::mut_null(),
hStdError: ptr::mut_null()
}
}
#[cfg(windows)]
fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
libc::types::os::arch::extra::PROCESS_INFORMATION {
hProcess: ptr::mut_null(),
hThread: ptr::mut_null(),
dwProcessId: 0,
dwThreadId: 0
}
}
// FIXME: this is only pub so it can be tested (see issue #4536)
#[cfg(windows)]
pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
let mut cmd = ~"";
append_arg(&mut cmd, prog);
for args.each |arg| {
cmd.push_char(' ');
append_arg(&mut cmd, *arg);
}
return cmd;
fn append_arg(cmd: &mut ~str, arg: &str) {
let quote = arg.any(|c| c == ' ' || c == '\t');
if quote {
cmd.push_char('"');
}
for uint::range(0, arg.len()) |i| {
append_char_at(cmd, arg, i);
}
if quote {
cmd.push_char('"');
}
}
fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
match arg[i] as char {
'"' => {
// Escape quotes.
cmd.push_str("\\\"");
}
'\\' => {
if backslash_run_ends_in_quote(arg, i) {
// Double all backslashes that are in runs before quotes.
cmd.push_str("\\\\");
} else {
// Pass other backslashes through unescaped.
cmd.push_char('\\');
}
}
c => {
cmd.push_char(c);
}
}
}
fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
while i < s.len() && s[i] as char == '\\' {
i += 1;
}
return i < s.len() && s[i] as char == '"';
}
}
#[cfg(unix)]
fn spawn_process_internal(prog: &str, args: &[~str],
env: &Option<~[(~str,~str)]>,
dir: &Option<~str>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult {
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
mod rustrt {
use libc::c_void;
#[abi = "cdecl"]
pub extern {
unsafe fn rust_unset_sigprocmask();
unsafe fn rust_set_environ(envp: *c_void);
}
}
unsafe {
let pid = fork();
if pid < 0 {
fail!(fmt!("failure in fork: %s", os::last_os_error()));
} else if pid > 0 {
return RunProgramResult {pid: pid, handle: ptr::null()};
}
rustrt::rust_unset_sigprocmask();
if in_fd > 0 && dup2(in_fd, 0) == -1 {
fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error()));
}
if out_fd > 0 && dup2(out_fd, 1) == -1 {
fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error()));
}
if err_fd > 0 && dup2(err_fd, 2) == -1 {
fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error()));
}
// close all other fds
for int::range_rev(getdtablesize() as int - 1, 2) |fd| {
close(fd as c_int);
}
for dir.each |dir| {
do str::as_c_str(*dir) |dirp| {
if chdir(dirp) == -1 {
fail!(fmt!("failure in chdir: %s", os::last_os_error()));
}
}
}
do with_envp(env) |envp| {
if !envp.is_null() {
rustrt::rust_set_environ(envp);
}
do with_argv(prog, args) |argv| {
execvp(*argv, argv);
// execvp only returns if an error occurred
fail!(fmt!("failure in execvp: %s", os::last_os_error()));
}
}
}
}
#[cfg(unix)]
fn with_argv<T>(prog: &str, args: &[~str],
cb: &fn(**libc::c_char) -> T) -> T {
let mut argptrs = str::as_c_str(prog, |b| ~[b]);
@ -246,7 +462,7 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
#[cfg(windows)]
fn with_envp<T>(env: &Option<~[(~str,~str)]>,
cb: &fn(*c_void) -> T) -> T {
cb: &fn(*mut c_void) -> T) -> T {
// On win32 we pass an "environment block" which is not a char**, but
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
@ -264,11 +480,12 @@ fn with_envp<T>(env: &Option<~[(~str,~str)]>,
blk += ~[0_u8];
vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p)))
}
_ => cb(ptr::null())
_ => cb(ptr::mut_null())
}
}
}
#[cfg(windows)]
fn with_dirp<T>(d: &Option<~str>,
cb: &fn(*libc::c_char) -> T) -> T {
match *d {
@ -312,8 +529,6 @@ priv fn free_handle(_handle: *()) {
pub fn run_program(prog: &str, args: &[~str]) -> int {
let res = spawn_process_internal(prog, args, &None, &None,
0i32, 0i32, 0i32);
if res.pid == -1 as pid_t { fail!(); }
let code = waitpid(res.pid);
free_handle(res.handle);
return code;
@ -345,7 +560,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program {
pipe_err.out);
unsafe {
if res.pid == -1 as pid_t { fail!(); }
libc::close(pipe_input.in);
libc::close(pipe_output.out);
libc::close(pipe_err.out);
@ -398,13 +612,6 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput {
os::close(pipe_in.in);
os::close(pipe_out.out);
os::close(pipe_err.out);
if res.pid == -1i32 {
os::close(pipe_in.out);
os::close(pipe_out.in);
os::close(pipe_err.in);
fail!();
}
os::close(pipe_in.out);
// Spawn two entire schedulers to read both stdout and sterr
@ -485,11 +692,46 @@ pub fn waitpid(pid: pid_t) -> int {
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
let status = unsafe { rustrt::rust_process_wait(pid) };
if status < 0 {
fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error()));
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
SYNCHRONIZE,
PROCESS_QUERY_INFORMATION,
FALSE,
STILL_ACTIVE,
INFINITE,
WAIT_FAILED
};
use libc::funcs::extra::kernel32::{
OpenProcess,
GetExitCodeProcess,
CloseHandle,
WaitForSingleObject
};
unsafe {
let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
if proc.is_null() {
fail!(fmt!("failure in OpenProcess: %s", os::last_os_error()));
}
loop {
let mut status = 0;
if GetExitCodeProcess(proc, &mut status) == FALSE {
CloseHandle(proc);
fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error()));
}
if status != STILL_ACTIVE {
CloseHandle(proc);
return status as int;
}
if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
CloseHandle(proc);
fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error()));
}
}
}
return status as int;
}
#[cfg(unix)]
@ -539,10 +781,30 @@ mod tests {
use libc;
use option::None;
use os;
use path::Path;
use run::{readclose, writeclose};
use run;
#[test]
#[cfg(windows)]
fn test_make_command_line() {
assert_eq!(
run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
~"prog aaa bbb ccc"
);
assert_eq!(
run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
);
assert_eq!(
run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
~"\"C:\\Program Files\\test\" aa\\\"bb"
);
assert_eq!(
run::make_command_line("echo", [~"a b c"]),
~"echo \"a b c\""
);
}
// Regression test for memory leaks
#[test]
fn test_leaks() {
@ -607,43 +869,60 @@ mod tests {
p.destroy(); // ...and nor should this (and nor should the destructor)
}
#[cfg(unix)] // there is no way to sleep on windows from inside libcore...
fn test_destroy_actually_kills(force: bool) {
let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force));
os::remove_file(&path);
#[cfg(unix)]
static BLOCK_COMMAND: &'static str = "cat";
let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str());
let mut p = run::start_program("sh", [~"-c", cmd]);
#[cfg(windows)]
static BLOCK_COMMAND: &'static str = "cmd";
p.destroy(); // destroy the program before it has a chance to echo its message
unsafe {
// wait to ensure the program is really destroyed and not just waiting itself
libc::sleep(10);
#[cfg(unix)]
fn process_exists(pid: libc::pid_t) -> bool {
run::program_output("ps", [~"-p", pid.to_str()]).out.contains(pid.to_str())
}
// the program should not have had chance to echo its message
assert!(!path.exists());
#[cfg(windows)]
fn process_exists(pid: libc::pid_t) -> bool {
use libc::types::os::arch::extra::DWORD;
use libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess};
use libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE };
unsafe {
let proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
if proc.is_null() {
return false;
}
// proc will be non-null if the process is alive, or if it died recently
let mut status = 0;
GetExitCodeProcess(proc, &mut status);
CloseHandle(proc);
return status == STILL_ACTIVE;
}
}
// this program will stay alive indefinitely trying to read from stdin
let mut p = run::start_program(BLOCK_COMMAND, []);
assert!(process_exists(p.get_id()));
if force {
p.force_destroy();
} else {
p.destroy();
}
assert!(!process_exists(p.get_id()));
}
#[test]
#[cfg(unix)]
fn test_unforced_destroy_actually_kills() {
test_destroy_actually_kills(false);
}
#[test]
#[cfg(unix)]
fn test_forced_destroy_actually_kills() {
test_destroy_actually_kills(true);
}
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -93,10 +93,6 @@ pub mod rustrt {
pub mod rusti {
#[abi = "rust-intrinsic"]
pub extern "rust-intrinsic" {
#[cfg(stage0)]
pub fn frame_address(f: &once fn(x: *u8));
#[cfg(not(stage0))]
pub fn frame_address(+f: &once fn(x: *u8));
}
}

View File

@ -77,6 +77,7 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
}
/// Copy a slice into a new unique str
#[inline(always)]
pub fn from_slice(s: &str) -> ~str {
unsafe { raw::slice_bytes_owned(s, 0, len(s)) }
}
@ -240,38 +241,132 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str {
/// Concatenate a vector of strings
pub fn concat(v: &[~str]) -> ~str {
let mut s: ~str = ~"";
for vec::each(v) |ss| {
push_str(&mut s, *ss);
if v.is_empty() { return ~""; }
let mut len = 0;
for v.each |ss| {
len += ss.len();
}
let mut s = ~"";
reserve(&mut s, len);
unsafe {
do as_buf(s) |buf, _len| {
let mut buf = ::cast::transmute_mut_unsafe(buf);
for v.each |ss| {
do as_buf(*ss) |ssbuf, sslen| {
let sslen = sslen - 1;
ptr::copy_memory(buf, ssbuf, sslen);
buf = buf.offset(sslen);
}
}
}
raw::set_len(&mut s, len);
}
s
}
/// Concatenate a vector of strings, placing a given separator between each
pub fn connect(v: &[~str], sep: &str) -> ~str {
if v.is_empty() { return ~""; }
// concat is faster
if sep.is_empty() { return concat(v); }
// this is wrong without the guarantee that v is non-empty
let mut len = sep.len() * (v.len() - 1);
for v.each |ss| {
len += ss.len();
}
let mut s = ~"", first = true;
for vec::each(v) |ss| {
if first { first = false; } else { push_str(&mut s, sep); }
push_str(&mut s, *ss);
reserve(&mut s, len);
unsafe {
do as_buf(s) |buf, _len| {
do as_buf(sep) |sepbuf, seplen| {
let seplen = seplen - 1;
let mut buf = ::cast::transmute_mut_unsafe(buf);
for v.each |ss| {
do as_buf(*ss) |ssbuf, sslen| {
let sslen = sslen - 1;
if first {
first = false;
} else {
ptr::copy_memory(buf, sepbuf, seplen);
buf = buf.offset(seplen);
}
ptr::copy_memory(buf, ssbuf, sslen);
buf = buf.offset(sslen);
}
}
}
}
raw::set_len(&mut s, len);
}
s
}
/// Concatenate a vector of strings, placing a given separator between each
pub fn connect_slices(v: &[&str], sep: &str) -> ~str {
if v.is_empty() { return ~""; }
// this is wrong without the guarantee that v is non-empty
let mut len = sep.len() * (v.len() - 1);
for v.each |ss| {
len += ss.len();
}
let mut s = ~"", first = true;
for vec::each(v) |ss| {
if first { first = false; } else { push_str(&mut s, sep); }
push_str(&mut s, *ss);
reserve(&mut s, len);
unsafe {
do as_buf(s) |buf, _len| {
do as_buf(sep) |sepbuf, seplen| {
let seplen = seplen - 1;
let mut buf = ::cast::transmute_mut_unsafe(buf);
for vec::each(v) |ss| {
do as_buf(*ss) |ssbuf, sslen| {
let sslen = sslen - 1;
if first {
first = false;
} else if seplen > 0 {
ptr::copy_memory(buf, sepbuf, seplen);
buf = buf.offset(seplen);
}
ptr::copy_memory(buf, ssbuf, sslen);
buf = buf.offset(sslen);
}
}
}
}
raw::set_len(&mut s, len);
}
s
}
/// Given a string, make a new string with repeated copies of it
pub fn repeat(ss: &str, nn: uint) -> ~str {
let mut acc = ~"";
for nn.times { acc += ss; }
acc
do as_buf(ss) |buf, len| {
let mut ret = ~"";
// ignore the NULL terminator
let len = len - 1;
reserve(&mut ret, nn * len);
unsafe {
do as_buf(ret) |rbuf, _len| {
let mut rbuf = ::cast::transmute_mut_unsafe(rbuf);
for nn.times {
ptr::copy_memory(rbuf, buf, len);
rbuf = rbuf.offset(len);
}
}
raw::set_len(&mut ret, nn * len);
}
ret
}
}
/*
@ -820,6 +915,7 @@ Section: Comparing strings
/// Bytewise slice equality
#[cfg(notest)]
#[lang="str_eq"]
#[inline]
pub fn eq_slice(a: &str, b: &str) -> bool {
do as_buf(a) |ap, alen| {
do as_buf(b) |bp, blen| {
@ -836,6 +932,7 @@ pub fn eq_slice(a: &str, b: &str) -> bool {
}
#[cfg(test)]
#[inline]
pub fn eq_slice(a: &str, b: &str) -> bool {
do as_buf(a) |ap, alen| {
do as_buf(b) |bp, blen| {
@ -854,15 +951,18 @@ pub fn eq_slice(a: &str, b: &str) -> bool {
/// Bytewise string equality
#[cfg(notest)]
#[lang="uniq_str_eq"]
#[inline]
pub fn eq(a: &~str, b: &~str) -> bool {
eq_slice(*a, *b)
}
#[cfg(test)]
#[inline]
pub fn eq(a: &~str, b: &~str) -> bool {
eq_slice(*a, *b)
}
#[inline]
fn cmp(a: &str, b: &str) -> Ordering {
let low = uint::min(a.len(), b.len());
@ -879,20 +979,24 @@ fn cmp(a: &str, b: &str) -> Ordering {
#[cfg(notest)]
impl<'self> TotalOrd for &'self str {
#[inline]
fn cmp(&self, other: & &'self str) -> Ordering { cmp(*self, *other) }
}
#[cfg(notest)]
impl TotalOrd for ~str {
#[inline]
fn cmp(&self, other: &~str) -> Ordering { cmp(*self, *other) }
}
#[cfg(notest)]
impl TotalOrd for @str {
#[inline]
fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) }
}
/// Bytewise slice less than
#[inline]
fn lt(a: &str, b: &str) -> bool {
let (a_len, b_len) = (a.len(), b.len());
let end = uint::min(a_len, b_len);
@ -909,16 +1013,19 @@ fn lt(a: &str, b: &str) -> bool {
}
/// Bytewise less than or equal
#[inline]
pub fn le(a: &str, b: &str) -> bool {
!lt(b, a)
}
/// Bytewise greater than or equal
#[inline]
fn ge(a: &str, b: &str) -> bool {
!lt(a, b)
}
/// Bytewise greater than
#[inline]
fn gt(a: &str, b: &str) -> bool {
!le(a, b)
}
@ -1595,6 +1702,7 @@ Section: String properties
*/
/// Returns true if the string has length 0
#[inline(always)]
pub fn is_empty(s: &str) -> bool { len(s) == 0u }
/**
@ -1616,11 +1724,13 @@ fn is_alphanumeric(s: &str) -> bool {
}
/// Returns the string length/size in bytes not counting the null terminator
#[inline(always)]
pub fn len(s: &str) -> uint {
do as_buf(s) |_p, n| { n - 1u }
}
/// Returns the number of characters that a string holds
#[inline(always)]
pub fn char_len(s: &str) -> uint { count_chars(s, 0u, len(s)) }
/*
@ -1752,7 +1862,8 @@ pub fn count_chars(s: &str, start: uint, end: uint) -> uint {
return len;
}
/// Counts the number of bytes taken by the `n` in `s` starting from `start`.
/// Counts the number of bytes taken by the first `n` chars in `s`
/// starting from `start`.
pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint {
assert!(is_char_boundary(s, start));
let mut end = start, cnt = n;
@ -1988,6 +2099,7 @@ static tag_six_b: uint = 252u;
* let i = str::as_bytes("Hello World") { |bytes| vec::len(bytes) };
* ~~~
*/
#[inline]
pub fn as_bytes<T>(s: &const ~str, f: &fn(&~[u8]) -> T) -> T {
unsafe {
let v: *~[u8] = cast::transmute(copy s);
@ -2023,6 +2135,7 @@ pub fn as_bytes_slice<'a>(s: &'a str) -> &'a [u8] {
* let s = str::as_c_str("PATH", { |path| libc::getenv(path) });
* ~~~
*/
#[inline]
pub fn as_c_str<T>(s: &str, f: &fn(*libc::c_char) -> T) -> T {
do as_buf(s) |buf, len| {
// NB: len includes the trailing null.
@ -2099,6 +2212,7 @@ pub fn subslice_offset(outer: &str, inner: &str) -> uint {
* * s - A string
* * n - The number of bytes to reserve space for
*/
#[inline(always)]
pub fn reserve(s: &mut ~str, n: uint) {
unsafe {
let v: *mut ~[u8] = cast::transmute(s);
@ -2126,6 +2240,7 @@ pub fn reserve(s: &mut ~str, n: uint) {
* * s - A string
* * n - The number of bytes to reserve space for
*/
#[inline(always)]
pub fn reserve_at_least(s: &mut ~str, n: uint) {
reserve(s, uint::next_power_of_two(n + 1u) - 1u)
}
@ -2314,6 +2429,7 @@ pub mod raw {
}
/// Sets the length of the string and adds the null terminator
#[inline]
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **mut vec::raw::VecRepr = cast::transmute(v);
let repr: *mut vec::raw::VecRepr = *v;
@ -2483,7 +2599,7 @@ impl<'self> StrSlice<'self> for &'self str {
#[inline]
fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) }
/// Returns the size in bytes not counting the null terminator
#[inline]
#[inline(always)]
fn len(&self) -> uint { len(*self) }
/// Returns the number of characters that a string holds
#[inline]
@ -2593,10 +2709,11 @@ pub trait OwnedStr {
}
impl OwnedStr for ~str {
#[inline]
fn push_str(&mut self, v: &str) {
push_str(self, v);
}
#[inline]
fn push_char(&mut self, c: char) {
push_char(self, c);
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Operations on ASCII strings and characters.
use to_str::{ToStr,ToStrConsume};
use str;
use cast;

View File

@ -10,6 +10,7 @@
//! Misc low level stuff
use option::{Some, None};
use cast;
use cmp::{Eq, Ord};
use gc;
@ -199,36 +200,33 @@ impl FailWithCause for &'static str {
}
}
// NOTE: remove function after snapshot
#[cfg(stage0)]
pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
do str::as_buf(msg) |msg_buf, _msg_len| {
do str::as_buf(file) |file_buf, _file_len| {
// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
use rt::{context, OldTaskContext};
use rt::local_services::unsafe_borrow_local_services;
match context() {
OldTaskContext => {
unsafe {
let msg_buf = cast::transmute(msg_buf);
let file_buf = cast::transmute(file_buf);
begin_unwind_(msg_buf, file_buf, line as libc::size_t)
gc::cleanup_stack_for_failure();
rustrt::rust_upcall_fail(msg, file, line);
cast::transmute(())
}
}
_ => {
// XXX: Need to print the failure message
gc::cleanup_stack_for_failure();
unsafe {
let local_services = unsafe_borrow_local_services();
match local_services.unwinder {
Some(ref mut unwinder) => unwinder.begin_unwind(),
None => abort!("failure without unwinder. aborting process")
}
}
}
}
}
// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
unsafe {
gc::cleanup_stack_for_failure();
rustrt::rust_upcall_fail(msg, file, line);
cast::transmute(())
}
}
// NOTE: remove function after snapshot
#[cfg(stage0)]
pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! {
let (msg, file) = (msg.to_owned(), file.to_owned());
begin_unwind(~"assertion failed: " + msg, file, line)
}
#[cfg(test)]
mod tests {
use cast;
@ -343,11 +341,3 @@ mod tests {
#[should_fail]
fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) }
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:

View File

@ -27,8 +27,7 @@ magic.
*/
use prelude::*;
use task::local_data_priv::{local_get, local_pop, local_modify, local_set};
use task::rt;
use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle};
/**
* Indexes a task-local data slot. The function's code pointer is used for
@ -53,7 +52,7 @@ pub type LocalDataKey<'self,T> = &'self fn(v: @T);
pub unsafe fn local_data_pop<T:Durable>(
key: LocalDataKey<T>) -> Option<@T> {
local_pop(rt::rust_get_task(), key)
local_pop(Handle::new(), key)
}
/**
* Retrieve a task-local data value. It will also be kept alive in the
@ -62,7 +61,7 @@ pub unsafe fn local_data_pop<T:Durable>(
pub unsafe fn local_data_get<T:Durable>(
key: LocalDataKey<T>) -> Option<@T> {
local_get(rt::rust_get_task(), key)
local_get(Handle::new(), key)
}
/**
* Store a value in task-local data. If this key already has a value,
@ -71,7 +70,7 @@ pub unsafe fn local_data_get<T:Durable>(
pub unsafe fn local_data_set<T:Durable>(
key: LocalDataKey<T>, data: @T) {
local_set(rt::rust_get_task(), key, data)
local_set(Handle::new(), key, data)
}
/**
* Modify a task-local data value. If the function returns 'None', the
@ -81,7 +80,7 @@ pub unsafe fn local_data_modify<T:Durable>(
key: LocalDataKey<T>,
modify_fn: &fn(Option<@T>) -> Option<@T>) {
local_modify(rt::rust_get_task(), key, modify_fn)
local_modify(Handle::new(), key, modify_fn)
}
#[test]

View File

@ -18,6 +18,30 @@ use task::rt;
use task::local_data::LocalDataKey;
use super::rt::rust_task;
use rt::local_services::LocalStorage;
pub enum Handle {
OldHandle(*rust_task),
NewHandle(*mut LocalStorage)
}
impl Handle {
pub fn new() -> Handle {
use rt::{context, OldTaskContext};
use rt::local_services::unsafe_borrow_local_services;
unsafe {
match context() {
OldTaskContext => {
OldHandle(rt::rust_get_task())
}
_ => {
let local_services = unsafe_borrow_local_services();
NewHandle(&mut local_services.storage)
}
}
}
}
}
pub trait LocalData { }
impl<T:Durable> LocalData for @T { }
@ -25,8 +49,8 @@ impl<T:Durable> LocalData for @T { }
impl Eq for @LocalData {
fn eq(&self, other: &@LocalData) -> bool {
unsafe {
let ptr_a: (uint, uint) = cast::transmute(*self);
let ptr_b: (uint, uint) = cast::transmute(*other);
let ptr_a: &(uint, uint) = cast::transmute(self);
let ptr_b: &(uint, uint) = cast::transmute(other);
return ptr_a == ptr_b;
}
}
@ -39,7 +63,7 @@ type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData);
// Has to be a pointer at outermost layer; the foreign call returns void *.
type TaskLocalMap = @mut ~[Option<TaskLocalElement>];
extern fn cleanup_task_local_map(map_ptr: *libc::c_void) {
fn cleanup_task_local_map(map_ptr: *libc::c_void) {
unsafe {
assert!(!map_ptr.is_null());
// Get and keep the single reference that was created at the
@ -50,8 +74,19 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) {
}
// Gets the map from the runtime. Lazily initialises if not done so already.
unsafe fn get_local_map(handle: Handle) -> TaskLocalMap {
match handle {
OldHandle(task) => get_task_local_map(task),
NewHandle(local_storage) => get_newsched_local_map(local_storage)
}
}
unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) {
cleanup_task_local_map(map_ptr);
}
// Relies on the runtime initialising the pointer to null.
// Note: The map's box lives in TLS invisibly referenced once. Each time
// we retrieve it for get/set, we make another reference, which get/set
@ -60,7 +95,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
if map_ptr.is_null() {
let map: TaskLocalMap = @mut ~[];
rt::rust_set_task_local_data(task, cast::transmute(map));
rt::rust_task_local_data_atexit(task, cleanup_task_local_map);
rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb);
// Also need to reference it an extra time to keep it for now.
let nonmut = cast::transmute::<TaskLocalMap,
@~[Option<TaskLocalElement>]>(map);
@ -75,6 +110,27 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
}
}
unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap {
match &mut *local {
&LocalStorage(map_ptr, Some(_)) => {
assert!(map_ptr.is_not_null());
let map = cast::transmute(map_ptr);
let nonmut = cast::transmute::<TaskLocalMap,
@~[Option<TaskLocalElement>]>(map);
cast::bump_box_refcount(nonmut);
return map;
}
&LocalStorage(ref mut map_ptr, ref mut at_exit) => {
assert!((*map_ptr).is_null());
let map: TaskLocalMap = @mut ~[];
*map_ptr = cast::transmute(map);
let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p);
*at_exit = Some(at_exit_fn);
return map;
}
}
}
unsafe fn key_to_key_value<T:Durable>(key: LocalDataKey<T>) -> *libc::c_void {
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
// Use reintepret_cast -- transmute would leak (forget) the closure.
@ -102,10 +158,10 @@ unsafe fn local_data_lookup<T:Durable>(
}
unsafe fn local_get_helper<T:Durable>(
task: *rust_task, key: LocalDataKey<T>,
handle: Handle, key: LocalDataKey<T>,
do_pop: bool) -> Option<@T> {
let map = get_task_local_map(task);
let map = get_local_map(handle);
// Interpreturn our findings from the map
do local_data_lookup(map, key).map |result| {
// A reference count magically appears on 'data' out of thin air. It
@ -124,23 +180,23 @@ unsafe fn local_get_helper<T:Durable>(
pub unsafe fn local_pop<T:Durable>(
task: *rust_task,
handle: Handle,
key: LocalDataKey<T>) -> Option<@T> {
local_get_helper(task, key, true)
local_get_helper(handle, key, true)
}
pub unsafe fn local_get<T:Durable>(
task: *rust_task,
handle: Handle,
key: LocalDataKey<T>) -> Option<@T> {
local_get_helper(task, key, false)
local_get_helper(handle, key, false)
}
pub unsafe fn local_set<T:Durable>(
task: *rust_task, key: LocalDataKey<T>, data: @T) {
handle: Handle, key: LocalDataKey<T>, data: @T) {
let map = get_task_local_map(task);
let map = get_local_map(handle);
// Store key+data as *voids. Data is invisibly referenced once; key isn't.
let keyval = key_to_key_value(key);
// We keep the data in two forms: one as an unsafe pointer, so we can get
@ -148,7 +204,7 @@ pub unsafe fn local_set<T:Durable>(
// own on it can be dropped when the box is destroyed. The unsafe pointer
// does not have a reference associated with it, so it may become invalid
// when the box is destroyed.
let data_ptr = cast::transmute(data);
let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data);
let data_box = @data as @LocalData;
// Construct new entry to store in the map.
let new_entry = Some((keyval, data_ptr, data_box));
@ -170,12 +226,12 @@ pub unsafe fn local_set<T:Durable>(
}
pub unsafe fn local_modify<T:Durable>(
task: *rust_task, key: LocalDataKey<T>,
handle: Handle, key: LocalDataKey<T>,
modify_fn: &fn(Option<@T>) -> Option<@T>) {
// Could be more efficient by doing the lookup work, but this is easy.
let newdata = modify_fn(local_pop(task, key));
let newdata = modify_fn(local_pop(handle, key));
if newdata.is_some() {
local_set(task, key, newdata.unwrap());
local_set(handle, key, newdata.unwrap());
}
}

View File

@ -39,9 +39,10 @@ use result::Result;
use comm::{stream, Chan, GenericChan, GenericPort, Port};
use prelude::*;
use result;
use task::rt::{task_id, sched_id, rust_task};
use task::rt::{task_id, sched_id};
use util;
use util::replace;
use unstable::finally::Finally;
#[cfg(test)] use comm::SharedChan;
@ -558,8 +559,31 @@ pub fn yield() {
pub fn failing() -> bool {
//! True if the running task has failed
unsafe {
rt::rust_task_is_unwinding(rt::rust_get_task())
use rt::{context, OldTaskContext};
use rt::local_services::borrow_local_services;
match context() {
OldTaskContext => {
unsafe {
rt::rust_task_is_unwinding(rt::rust_get_task())
}
}
_ => {
let mut unwinding = false;
do borrow_local_services |local| {
unwinding = match local.unwinder {
Some(unwinder) => {
unwinder.unwinding
}
None => {
// Because there is no unwinder we can't be unwinding.
// (The process will abort on failure)
false
}
}
}
return unwinding;
}
}
}
@ -591,48 +615,24 @@ pub fn get_scheduler() -> Scheduler {
* ~~~
*/
pub unsafe fn unkillable<U>(f: &fn() -> U) -> U {
struct AllowFailure {
t: *rust_task,
drop {
unsafe {
rt::rust_task_allow_kill(self.t);
}
}
}
fn AllowFailure(t: *rust_task) -> AllowFailure{
AllowFailure {
t: t
}
}
let t = rt::rust_get_task();
let _allow_failure = AllowFailure(t);
rt::rust_task_inhibit_kill(t);
f()
do (|| {
rt::rust_task_inhibit_kill(t);
f()
}).finally {
rt::rust_task_allow_kill(t);
}
}
/// The inverse of unkillable. Only ever to be used nested in unkillable().
pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
struct DisallowFailure {
t: *rust_task,
drop {
unsafe {
rt::rust_task_inhibit_kill(self.t);
}
}
}
fn DisallowFailure(t: *rust_task) -> DisallowFailure {
DisallowFailure {
t: t
}
}
let t = rt::rust_get_task();
let _allow_failure = DisallowFailure(t);
rt::rust_task_allow_kill(t);
f()
do (|| {
rt::rust_task_allow_kill(t);
f()
}).finally {
rt::rust_task_inhibit_kill(t);
}
}
/**
@ -640,27 +640,15 @@ pub unsafe fn rekillable<U>(f: &fn() -> U) -> U {
* For use with exclusive ARCs, which use pthread mutexes directly.
*/
pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
struct DeferInterrupts {
t: *rust_task,
drop {
unsafe {
rt::rust_task_allow_yield(self.t);
rt::rust_task_allow_kill(self.t);
}
}
}
fn DeferInterrupts(t: *rust_task) -> DeferInterrupts {
DeferInterrupts {
t: t
}
}
let t = rt::rust_get_task();
let _interrupts = DeferInterrupts(t);
rt::rust_task_inhibit_kill(t);
rt::rust_task_inhibit_yield(t);
f()
do (|| {
rt::rust_task_inhibit_kill(t);
rt::rust_task_inhibit_yield(t);
f()
}).finally {
rt::rust_task_allow_yield(t);
rt::rust_task_allow_kill(t);
}
}
#[test] #[should_fail] #[ignore(cfg(windows))]
@ -832,7 +820,7 @@ fn test_run_basic() {
po.recv();
}
#[test]
#[cfg(test)]
struct Wrapper {
mut f: Option<Chan<()>>
}
@ -1229,7 +1217,7 @@ fn test_spawn_thread_on_demand() {
#[test]
fn test_simple_newsched_spawn() {
use rt::run_in_newsched_task;
use rt::test::run_in_newsched_task;
do run_in_newsched_task {
spawn(||())

View File

@ -80,7 +80,7 @@ use prelude::*;
use unstable;
use ptr;
use hashmap::HashSet;
use task::local_data_priv::{local_get, local_set};
use task::local_data_priv::{local_get, local_set, OldHandle};
use task::rt::rust_task;
use task::rt;
use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded};
@ -451,7 +451,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
/*##################################################################*
* Step 1. Get spawner's taskgroup info.
*##################################################################*/
let spawner_group = match local_get(spawner, taskgroup_key!()) {
let spawner_group = match local_get(OldHandle(spawner), taskgroup_key!()) {
None => {
// Main task, doing first spawn ever. Lazily initialise here.
let mut members = new_taskset();
@ -463,7 +463,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool)
// Main task/group has no ancestors, no notifier, etc.
let group =
@TCB(spawner, tasks, AncestorList(None), true, None);
local_set(spawner, taskgroup_key!(), group);
local_set(OldHandle(spawner), taskgroup_key!(), group);
group
}
Some(group) => group
@ -627,7 +627,7 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) {
let group = @TCB(child, child_arc, ancestors,
is_main, notifier);
unsafe {
local_set(child, taskgroup_key!(), group);
local_set(OldHandle(child), taskgroup_key!(), group);
}
// Run the child's body.

View File

@ -419,8 +419,7 @@ impl<A> IterBytes for *const A {
}
}
trait ToBytes {
pub trait ToBytes {
fn to_bytes(&self, lsb0: bool) -> ~[u8];
}

Some files were not shown because too many files have changed in this diff Show More