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:
commit
4300d4d2fa
661 changed files with 7136 additions and 5629 deletions
9
.gitattributes
vendored
Normal file
9
.gitattributes
vendored
Normal 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
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
~~~~
|
||||
|
|
|
@ -7,4 +7,3 @@
|
|||
</center>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -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, \
|
||||
|
|
76
mk/docs.mk
76
mk/docs.mk
|
@ -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)
|
||||
|
|
38
mk/host.mk
38
mk/host.mk
|
@ -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), \
|
||||
|
|
|
@ -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
|
||||
|
|
22
mk/rt.mk
22
mk/rt.mk
|
@ -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))" \
|
||||
|
|
|
@ -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
|
||||
|
|
32
mk/target.mk
32
mk/target.mk
|
@ -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:
|
||||
|
|
|
@ -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))))
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -14,4 +14,3 @@ while (<>) {
|
|||
$indent -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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"])
|
||||
|
||||
|
||||
|
|
|
@ -243,4 +243,3 @@ int main() {
|
|||
extra_consts();
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -96,4 +96,3 @@ def check_license(name, contents):
|
|||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -33,6 +33,3 @@ for line in f.readlines():
|
|||
print("got download with ok hash")
|
||||
else:
|
||||
raise Exception("bad hash on download")
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -77,4 +77,3 @@ while (my ($key, $substs) = each %funcs) {
|
|||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -81,4 +81,3 @@ except UnicodeDecodeError, e:
|
|||
|
||||
|
||||
sys.exit(err)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
121
src/etc/ziggurat_tables.py
Executable 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))
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
@ -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) });
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
//! Utilities for manipulating the char type
|
||||
|
||||
#[cfg(notest)]
|
||||
use cmp::Ord;
|
||||
use option::{None, Option, Some};
|
||||
use str;
|
||||
|
|
|
@ -258,4 +258,3 @@ pub mod rustrt {
|
|||
pub unsafe fn rust_get_task() -> *c_void;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
39
src/libcore/macros.rs
Normal 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(); }
|
||||
} )
|
||||
)
|
|
@ -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:
|
||||
//
|
||||
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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:
|
||||
//
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -31,4 +31,3 @@ impl<T:Ord> Ord for ~T {
|
|||
#[inline(always)]
|
||||
fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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:
|
||||
|
|
148
src/libcore/rand/distributions.rs
Normal file
148
src/libcore/rand/distributions.rs
Normal 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))
|
||||
}
|
||||
}
|
412
src/libcore/rand/ziggurat_tables.rs
Normal file
412
src/libcore/rand/ziggurat_tables.rs
Normal 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];
|
|
@ -564,7 +564,7 @@ pub fn write_repr<T>(writer: @Writer, object: &T) {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(test)]
|
||||
struct P {a: int, b: float}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -56,4 +56,3 @@ impl<W: Writer> WriterChan<W> {
|
|||
impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> {
|
||||
fn send(&self, _x: ~[u8]) { fail!() }
|
||||
}
|
||||
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,3 @@ pub enum IpAddr {
|
|||
Ipv4(u8, u8, u8, u8, u16),
|
||||
Ipv6
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!() }
|
||||
}
|
||||
|
||||
|
|
|
@ -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
153
src/libcore/rt/io/option.rs
Normal 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);
|
||||
}
|
||||
}
|
80
src/libcore/rt/local_heap.rs
Normal file
80
src/libcore/rt/local_heap.rs
Normal 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);
|
||||
}
|
223
src/libcore/rt/local_services.rs
Normal file
223
src/libcore/rt/local_services.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,4 +143,3 @@ fn borrow_smoke_test() {
|
|||
}
|
||||
let _scheduler = take();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
120
src/libcore/rt/test.rs
Normal 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())
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(||())
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue