[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
-* text=auto
+* text eol=lf
*.cpp rust
*.h rust
*.rs rust
src/rt/vg/* -whitespace
src/rt/linenoise/* -whitespace
src/rt/jemalloc/**/* -whitespace
-src/rt/jemalloc/include/jemalloc/jemalloc.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/jemalloc_defs.h.in text eol=lf
-src/rt/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in text eol=lf
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
+ $$(HBIN$(1)_H_$(3))/rustdoc_ng$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rusti$$(X_$(3)) \
$$(HBIN$(1)_H_$(3))/rust$$(X_$(3)) \
$$(HLIB$(1)_H_$(3))/$(CFG_LIBRUSTPKG_$(3)) \
| '\x5c' [ '\x22' | common_escape ] ;
common_escape : '\x5c'
- | 'n' | 'r' | 't'
+ | 'n' | 'r' | 't' | '0'
| 'x' hex_digit 2
| 'u' hex_digit 4
| 'U' hex_digit 8 ;
of that type.
-#### Unsafe functions
-
-Unsafe functions are those containing unsafe operations that are not contained in an [`unsafe` block](#unsafe-blocks).
-Such a function must be prefixed with the keyword `unsafe`.
+#### Unsafety
Unsafe operations are those that potentially violate the memory-safety guarantees of Rust's static semantics.
-Specifically, the following operations are considered unsafe:
+
+The following language level features cannot be used in the safe subset of Rust:
- Dereferencing a [raw pointer](#pointer-types).
- - Casting a [raw pointer](#pointer-types) to a safe pointer type.
- - Calling an unsafe function.
+ - Calling an unsafe function (including an intrinsic or foreign function).
-##### Unsafe blocks
+##### Unsafe functions
-A block of code can also be prefixed with the `unsafe` keyword, to permit a sequence of unsafe operations in an otherwise-safe function.
-This facility exists because the static semantics of Rust are a necessary approximation of the dynamic semantics.
-When a programmer has sufficient conviction that a sequence of unsafe operations is actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The compiler will consider uses of such code "safe", to the surrounding context.
+Unsafe functions are functions that are not safe in all contexts and/or for all possible inputs.
+Such a function must be prefixed with the keyword `unsafe`.
+
+##### Unsafe blocks
+A block of code can also be prefixed with the `unsafe` keyword, to permit calling `unsafe` functions
+or dereferencing raw pointers within a safe function.
+
+When a programmer has sufficient conviction that a sequence of potentially unsafe operations is
+actually safe, they can encapsulate that sequence (taken as a whole) within an `unsafe` block. The
+compiler will consider uses of such code safe, in the surrounding context.
+
+Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features
+not directly present in the language. For example, Rust provides the language features necessary to
+implement memory-safe concurrency in the language but the implementation of tasks and message
+passing is in the standard library.
+
+Rust's type system is a conservative approximation of the dynamic safety requirements, so in some
+cases there is a performance cost to using safe code. For example, a doubly-linked list is not a
+tree structure and can only be represented with managed or reference-counted pointers in safe code.
+By using `unsafe` blocks to represent the reverse links as raw pointers, it can be implemented with
+only owned pointers.
+
+##### Behavior considered unsafe
+
+This is a list of behavior which is forbidden in all Rust code. Type checking provides the guarantee
+that these issues are never caused by safe code. An `unsafe` block or function is responsible for
+never invoking this behaviour or exposing an API making it possible for it to occur in safe code.
+
+* Data races
+* Dereferencing a null/dangling raw pointer
+* Mutating an immutable value/reference, if it is not marked as non-`Freeze`
+* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values) (uninitialized) memory
+* Breaking the [pointer aliasing rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
+ with raw pointers (a subset of the rules used by C)
+* Invoking undefined behavior via compiler intrinsics:
+ * Indexing outside of the bounds of an object with `std::ptr::offset` (`offset` intrinsic), with
+ the exception of one byte past the end which is permitted.
+ * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64` instrinsics) on
+ overlapping buffers
+* Invalid values in primitive types, even in private fields/locals:
+ * Dangling/null pointers in non-raw pointers, or slices
+ * A value other than `false` (0) or `true` (1) in a `bool`
+ * A discriminant in an `enum` not included in the type definition
+ * A value in a `char` which is a surrogate or above `char::MAX`
+ * non-UTF-8 byte sequences in a `str`
+
+##### Behaviour not considered unsafe
+
+This is a list of behaviour not considered *unsafe* in Rust terms, but that may be undesired.
+
+* Deadlocks
+* Reading data from private fields (`std::repr`, `format!("{:?}", x)`)
+* Leaks due to reference count cycles, even in the global heap
+* Exiting without calling destructors
+* Sending signals
+* Accessing/modifying the file system
+* Unsigned integer overflow (well-defined as wrapping)
+* Signed integer overflow (well-defined as two's complement representation wrapping)
#### Diverging functions
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment];
#[inline(never)];
--- /dev/null
+% Rust Packaging Tutorial
+
+# Introduction
+
+Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
+package up your Rust code and share it with other people. This tutorial will
+get you started on all of the concepts and commands you need to give the gift
+of Rust code to someone else.
+
+## Installing External Packages
+
+First, let's try to use an external package somehow. I've made a sample package
+called `hello` to demonstrate how to do so. Here's how `hello` is used:
+
+~~~~
+extern mod hello;
+
+fn main() {
+ hello::world();
+}
+~~~~
+
+Easy! But if you try to compile this, you'll get an error:
+
+~~~~ {.notrust}
+$ rustc main.rs
+main.rs:1:0: 1:17 error: can't find crate for `hello`
+main.rs:1 extern mod hello;
+ ^~~~~~~~~~~~~~~~~
+
+~~~~
+
+This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
+`rustpkg` has an easy way to fetch others' code: the `install` command. It's
+used like this:
+
+~~~ {.notrust}
+$ rustpkg install pkg_id
+~~~
+
+This will install a package named 'pkg_id' into your current Rust environment.
+I called it 'pkg_id' in this example because `rustpkg` calls this a 'package
+identifier.' When using it with an external package like this, it's often a
+URI fragment. You see, Rust has no central authority for packages. You can
+build your own `hello` library if you want, and that's fine. We'd both host
+them in different places and different projects would rely on whichever version
+they preferred.
+
+To install the `hello` library, simply run this in your terminal:
+
+~~~ {.notrust}
+$ rustpkg install github.com/steveklabnik/hello
+~~~
+
+You should see a message that looks like this:
+
+~~~ {.notrust}
+note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
+~~~
+
+Now, compiling our example should work:
+
+~~~ {.notrust}
+$ rustc main.rs
+$ ./main
+Hello, world.
+~~~
+
+Simple! That's all it takes.
+
+## Workspaces
+
+Before we can talk about how to make packages of your own, you have to
+understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
+a directory that has certain sub-directories that `rustpkg` expects. Different
+Rust projects will go into different workspaces.
+
+A workspace consists of any directory that has the following
+directories:
+
+* `src`: The directory where all the source code goes.
+* `build`: This directory contains all of the build output.
+* `lib`: The directory where any libraries distributed with the package go.
+* `bin`: This directory holds any binaries distributed with the package.
+
+There are also default file names you'll want to follow as well:
+
+* `main.rs`: A file that's going to become an executable.
+* `lib.rs`: A file that's going to become a library.
+
+## Building your own Package
+
+Now that you've got workspaces down, let's build your own copy of `hello`. Go
+to wherever you keep your personal projects, and let's make all of the
+directories we'll need. I'll refer to this personal project directory as
+`~/src` for the rest of this tutorial.
+
+### Creating our workspace
+
+~~~ {.notrust}
+$ cd ~/src
+$ mkdir -p hello/src/hello
+$ cd hello
+~~~
+
+Easy enough! Let's do one or two more things that are nice to do:
+
+~~~ {.notrust}
+$ git init .
+$ cat > README.md
+# hello
+
+A simple package for Rust.
+
+## Installation
+
+```
+$ rustpkg install github.com/YOUR_USERNAME/hello
+```
+^D
+$ cat > .gitignore
+.rust
+build
+^D
+$ git commit -am "Initial commit."
+~~~
+
+If you're not familliar with the `cat >` idiom, it will make files with the
+text you type inside. Control-D (`^D`) ends the text for the file.
+
+Anyway, we've got a README and a `.gitignore`. Let's talk about that
+`.gitignore` for a minute: we are ignoring two directories, `build` and
+`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
+want to check those into a repository. `.rust` is a directory that `rustpkg`
+uses to keep track of its own settings, as well as the source code of any other
+external packages that this workspace uses. This is where that `rustpkg
+install` puts all of its files. Those are also not to go into our repository,
+so we ignore it all as well.
+
+Next, let's add a source file:
+
+~~~
+#[desc = "A hello world Rust package."];
+#[license = "MIT"];
+
+pub fn world() {
+ println("Hello, world.");
+}
+~~~
+
+Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
+
+### Crate attributes for packages
+
+`license` is equally simple: the license we want this code to have. I chose MIT
+here, but you should pick whatever license makes the most sense for you.
+
+`desc` is a description of the package and what it does. This should just be a
+sentence or two.
+
+### Building your package
+
+Building your package is simple:
+
+~~~ {.notrust}
+$ rustpkg build hello
+~~~
+
+This will compile `src/hello/lib.rs` into a library. After this process
+completes, you'll want to check out `build`:
+
+~~~ {.notrust}
+$ ls build/x86_64-unknown-linux-gnu/hello/
+libhello-ed8619dad9ce7d58-0.1.0.so
+~~~
+
+This directory naming structure is called a 'build triple,' and is because I'm
+on 64 bit Linux. Yours may differ based on platform.
+
+You'll also notice that `src/hello/lib.rs` turned into
+`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
+library name, a hash of its content, and the version.
+
+Now that your library builds, you'll want to commit:
+
+~~~ {.notrust}
+$ git add src
+$ git commit -m "Adding source code."
+~~~
+
+If you're using GitHub, after creating the project, do this:
+
+~~~ {.notrust}
+$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
+$ git push origin -u master
+~~~
+
+Now you can install and use it! Go anywhere else in your filesystem:
+
+~~~ {.notrust}
+$ cd ~/src/foo
+$ rustpkg install github/YOUR_USERNAME/hello
+WARNING: The Rust package manager is experimental and may be unstable
+note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
+~~~
+
+That's it!
+
+## More resources
+
+There's a lot more going on with `rustpkg`, this is just to get you started.
+Check out [the rustpkg manual](rustpkg.html) for the full details on how to
+customize `rustpkg`.
+
+A tag was created on GitHub specifically for `rustpkg`-related issues. You can
+[see all the Issues for rustpkg
+here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
+with bugs as well as new feature plans. `rustpkg` is still under development,
+and so may be a bit flaky at the moment.
+
+You may also want to check out [this blog
+post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
+design decisions and justifications.
* [`std::task`] - All code relating to tasks and task scheduling,
* [`std::comm`] - The message passing interface,
-* [`std::pipes`] - The underlying messaging infrastructure,
-* [`extra::comm`] - Additional messaging types based on `std::pipes`,
+* [`extra::comm`] - Additional messaging types based on `std::comm`,
* [`extra::sync`] - More exotic synchronization tools, including locks,
* [`extra::arc`] - The Arc (atomically reference counted) type,
for safely sharing immutable data,
[`std::task`]: std/task.html
[`std::comm`]: std/comm.html
-[`std::pipes`]: std/pipes.html
[`extra::comm`]: extra/comm.html
[`extra::sync`]: extra/sync.html
[`extra::arc`]: extra/arc.html
come in a variety of forms, each one appropriate for a different use case. In
what follows, we cover the most commonly used varieties.
-The simplest way to create a pipe is to use the `pipes::stream`
+The simplest way to create a pipe is to use the `comm::stream`
function to create a `(Port, Chan)` pair. In Rust parlance, a *channel*
is a sending endpoint of a pipe, and a *port* is the receiving
endpoint. Consider the following example of calculating two results
}
impl Drop for TimeBomb {
- fn drop(&self) {
+ fn drop(&mut self) {
for _ in range(0, self.explosivity) {
println("blam!");
}
* [The foreign function interface][ffi]
* [Containers and iterators](tutorial-container.html)
* [Error-handling and Conditions](tutorial-conditions.html)
+* [Packaging up Rust code](rustpkg)
There is further documentation on the [wiki], however those tend to be even more out of date as this document.
[tasks]: tutorial-tasks.html
[macros]: tutorial-macros.html
[ffi]: tutorial-ffi.html
+[rustpkg]: tutorial-rustpkg.html
[wiki]: https://github.com/mozilla/rust/wiki/Docs
available at <\fBhttps://www.rust-lang.org\fR>. It provides commands to build,
install and test Rust programs.
+\fBrustpkg\fR is still a work in progress. See \fBdoc/rustpkg.md\fR in the Rust source distribution for future plans.
+
.SH COMMANDS
.TP
Builds the specified target, and all its dependencies, and then installs the
build products into the \fIlib\fR and \fIbin\fR directories of their respective
workspaces.
-.TP
-\fBtest\fR
-Builds the module called \fItest.rs\fR in the specified workspace, and then runs
-the resulting executable in test mode.
.SS "BUILD COMMAND"
Examples:
- $ rustpkg install git://github.com/mozilla/servo.git#1.2
+ $ rustpkg install github.com/mozilla/servo.git#1.2
$ rustpkg install rust-glfw
-.SS "TEST COMMAND"
-
- rustpkg test \fI[pkgname]\fR
-
-The test command is a shortcut for the command line:
-
- $ rustc --test <filename> -o <filestem>test~ && ./<filestem>test~
-
-Note the suffix on the output filename (the word "test" followed by a tilde),
-which should ensure the file does not clash with a user-generated files.
-
.SH "ENVIRONMENT"
.TP
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
.SH "AUTHOR"
-See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare
+See \fBAUTHORS.txt\fR in the Rust source distribution. Graydon Hoare
<\fIgraydon@mozilla.com\fR> is the project leader.
.SH "COPYRIGHT"
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustpkg$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/serializer$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc$(X_$(2))
+ $(Q)rm -f $$(HBIN$(1)_H_$(2))/rustdoc_ng$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rusti$(X_$(2))
$(Q)rm -f $$(HBIN$(1)_H_$(2))/rust$(X_$(2))
$(Q)rm -f $$(HLIB$(1)_H_$(2))/$(CFG_LIBRUSTPKG_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustpkg$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/serializer$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc$(X_$(2))
+ $(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rustdoc_ng$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rusti$(X_$(2))
$(Q)rm -f $$(TBIN$(1)_T_$(2)_H_$(3))/rust$(X_$(2))
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTPKG_$(2))
libsyntax \
rt \
librustdoc \
+ rustdoc_ng \
rustllvm \
snapshots.txt \
test) \
$(Q)$(call INSTALL,$(HB2),$(PHB),rustc$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustpkg$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc$(X_$(CFG_BUILD_TRIPLE)))
+ $(Q)$(call INSTALL,$(HB2),$(PHB),rustdoc_ng$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rusti$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL,$(HB2),$(PHB),rust$(X_$(CFG_BUILD_TRIPLE)))
$(Q)$(call INSTALL_LIB,$(STDLIB_GLOB_$(CFG_BUILD_TRIPLE)))
$(Q)rm -f $(PHB)/rusti$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rust$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHB)/rustdoc$(X_$(CFG_BUILD_TRIPLE))
+ $(Q)rm -f $(PHB)/rustdoc_ng$(X_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))
$(Q)rm -f $(PHL)/$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))
$(Q)for i in \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE))) \
+ $(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTDOCNG_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE))) \
$(call HOST_LIB_FROM_HL_GLOB,$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE))) \
; \
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
@$$(call E, make: llvm)
- $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV)
+ $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1))
$$(Q)touch $$(LLVM_CONFIG_$(1))
endif
CFG_GCCISH_CFLAGS += -O2
endif
+# The soname thing is for supporting a statically linked jemalloc.
+# see https://blog.mozilla.org/jseward/2012/06/05/valgrind-now-supports-jemalloc-builds-directly/
ifdef CFG_VALGRIND
CFG_VALGRIND += --error-exitcode=100 \
+ --soname-synonyms=somalloc=NONE \
--quiet \
--suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
$(OS_SUPP)
CFG_LDPATH_mips-unknown-linux-gnu :=
CFG_RUN_mips-unknown-linux-gnu=
CFG_RUN_TARG_mips-unknown-linux-gnu=
+RUSTC_FLAGS_mips-unknown-linux-gnu := --linker=$(CXX_mips-unknown-linux-gnu) --target-cpu mips32r2 --target-feature +mips32r2,+o32
# i686-pc-mingw32 configuration
CC_i686-pc-mingw32=$(CC)
CFG_LIB_NAME_i686-pc-mingw32=$(1).dll
CFG_LIB_GLOB_i686-pc-mingw32=$(1)-*.dll
CFG_LIB_DSYM_GLOB_i686-pc-mingw32=$(1)-*.dylib.dSYM
-CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600
+CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -m32 -march=i686 -D_WIN32_WINNT=0x0600 -I$(CFG_SRC_DIR)src/etc/mingw-fix-include
CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti
CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g -m32
CFG_GCCISH_DEF_FLAG_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
+CFG_LLVM_BUILD_ENV_i686-pc-mingw32 := CPATH=$(CFG_SRC_DIR)src/etc/mingw-fix-include
CFG_EXE_SUFFIX_i686-pc-mingw32 := .exe
CFG_WINDOWSY_i686-pc-mingw32 := 1
CFG_UNIXY_i686-pc-mingw32 :=
$$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
$$(call CFG_INSTALL_NAME_$(1),$$(4))
- ifneq ($(HOST_$(1)),arm)
+ ifeq ($$(findstring $(HOST_$(1)),arm mips),)
# We're using llvm-mc as our assembler because it supports
# .cfi pseudo-ops on mac
-o=$$(1)
else
- # For the ARM crosses, use the toolchain assembler
+ # For the ARM and MIPS crosses, use the toolchain assembler
# XXX: We should be able to use the LLVM assembler
CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
# working under these assumptions).
# Hack for passing flags into LIBUV, see below.
-LIBUV_FLAGS_i386 = -m32 -fPIC
+LIBUV_FLAGS_i386 = -m32 -fPIC -I$(S)src/etc/mingw-fix-include
LIBUV_FLAGS_x86_64 = -m64 -fPIC
ifeq ($(OSTYPE_$(1)), linux-androideabi)
LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99
rt/sync/lock_and_signal.cpp \
rt/sync/rust_thread.cpp \
rt/rust_builtin.cpp \
- rt/rust_run_program.cpp \
rt/rust_rng.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
# The names of crates that must be tested
TEST_TARGET_CRATES = std extra
-TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc syntax
+TEST_HOST_CRATES = rust rusti rustpkg rustc rustdoc rustdocng syntax
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
@$$(call E, compile_and_link: $$@)
$$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
+$(3)/stage$(1)/test/rustdocngtest-$(2)$$(X_$(2)): \
+ $$(RUSTDOCNG_LIB) $$(RUSTDOCNG_INPUTS) \
+ $$(SREQ$(1)_T_$(2)_H_$(3)) \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBSYNTAX_$(2)) \
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(CFG_LIBRUSTC_$(2))
+ @$$(call E, compile_and_link: $$@)
+ $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< --test
+
endef
$(foreach host,$(CFG_HOST_TRIPLES), \
# rustdoc_ng, the next generation documentation tool
-RUSTDOCNG_LIB := $(S)src/rustdoc_ng/lib.rs
+RUSTDOCNG_LIB := $(S)src/rustdoc_ng/rustdoc_ng.rs
RUSTDOCNG_INPUTS := $(wildcard $(S)src/rustdoc_ng/*.rs)
# Rusti, the JIT REPL
$$(wildcard $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTDOCNG_DSYM_GLOB_$(4))) \
$$(HLIB$(2)_H_$(4))
+$$(HBIN$(2)_H_$(4))/rustdoc_ng$$(X_$(4)): \
+ $$(TBIN$(1)_T_$(4)_H_$(3))/rustdoc_ng$$(X_$(4)) \
+ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTDOCNG_$(4)) \
+ $$(HSREQ$(2)_H_$(4)) \
+ | $$(HBIN$(2)_H_$(4))/
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
+
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTI_$(4)): \
$$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_LIBRUSTI_$(4)) \
$$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \
use std::os;
use std::rt;
-use std::f64;
use extra::getopts;
use extra::getopts::groups::{optopt, optflag, reqopt};
let matches =
&match getopts::groups::getopts(args_, groups) {
Ok(m) => m,
- Err(f) => fail!(getopts::fail_str(f))
+ Err(f) => fail!(f.to_err_msg())
};
- if getopts::opt_present(matches, "h") || getopts::opt_present(matches, "help") {
+ if matches.opt_present("h") || matches.opt_present("help") {
let message = fmt!("Usage: %s [OPTIONS] [TESTNAME...]", argv0);
println(getopts::groups::usage(message, groups));
println("");
}
fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
- Path(getopts::opt_str(m, nm))
+ Path(m.opt_str(nm).unwrap())
}
config {
- compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
- run_lib_path: getopts::opt_str(matches, "run-lib-path"),
+ compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
+ run_lib_path: matches.opt_str("run-lib-path").unwrap(),
rustc_path: opt_path(matches, "rustc-path"),
- clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)),
- llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)),
+ clang_path: matches.opt_str("clang-path").map_move(|s| Path(s)),
+ llvm_bin_path: matches.opt_str("llvm-bin-path").map_move(|s| Path(s)),
src_base: opt_path(matches, "src-base"),
build_base: opt_path(matches, "build-base"),
aux_base: opt_path(matches, "aux-base"),
- stage_id: getopts::opt_str(matches, "stage-id"),
- mode: str_mode(getopts::opt_str(matches, "mode")),
- run_ignored: getopts::opt_present(matches, "ignored"),
+ stage_id: matches.opt_str("stage-id").unwrap(),
+ mode: str_mode(matches.opt_str("mode").unwrap()),
+ run_ignored: matches.opt_present("ignored"),
filter:
if !matches.free.is_empty() {
Some(matches.free[0].clone())
} else {
None
},
- logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)),
- save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)),
+ logfile: matches.opt_str("logfile").map_move(|s| Path(s)),
+ save_metrics: matches.opt_str("save-metrics").map_move(|s| Path(s)),
ratchet_metrics:
- getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)),
+ matches.opt_str("ratchet-metrics").map_move(|s| Path(s)),
ratchet_noise_percent:
- getopts::opt_maybe_str(matches,
- "ratchet-noise-percent").map_move(|s|
- f64::from_str(s).unwrap()),
- runtool: getopts::opt_maybe_str(matches, "runtool"),
- rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
- jit: getopts::opt_present(matches, "jit"),
- target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
- adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
+ matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
+ runtool: matches.opt_str("runtool"),
+ rustcflags: matches.opt_str("rustcflags"),
+ jit: matches.opt_present("jit"),
+ target: opt_str2(matches.opt_str("target")).to_str(),
+ adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
adb_test_dir:
- opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
+ opt_str2(matches.opt_str("adb-test-dir")).to_str(),
adb_device_status:
- if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
+ if (opt_str2(matches.opt_str("target")) ==
~"arm-linux-androideabi") {
- if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+ if (opt_str2(matches.opt_str("adb-test-dir")) !=
~"(none)" &&
- opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
+ opt_str2(matches.opt_str("adb-test-dir")) !=
~"") { true }
else { false }
} else { false },
- test_shard: test::opt_shard(getopts::opt_maybe_str(matches, "test-shard")),
- verbose: getopts::opt_present(matches, "verbose")
+ test_shard: test::opt_shard(matches.opt_str("test-shard")),
+ verbose: matches.opt_present("verbose")
}
}
#[cfg(rustc)]
extern mod this(name = "rustc");
+#[cfg(rustdoc_ng)]
+extern mod this(name = "rustdoc_ng");
+
fn main() { this::main() }
--- /dev/null
+The purpose of these headers is to fix issues with mingw v4.0, as described in #9246.
+
+This works by adding this directory to GCC include search path before mingw system headers directories,
+so we can intercept their inclusions and add missing definitions without having to modify files in mingw/include.
+
+Once mingw fixes all 3 issues mentioned in #9246, this directory and all references to it from rust/mk/* may be removed.
--- /dev/null
+#ifndef _FIX_CXXCONFIG_H
+#define _FIX_CXXCONFIG_H 1
+
+#define _GLIBCXX_HAVE_FENV_H 1
+
+#include_next <bits/c++config.h>
+
+#endif
--- /dev/null
+#ifndef _FIX_WINBASE_H
+#define _FIX_WINBASE_H 1
+
+#define NTDDK_VERSION NTDDI_VERSION
+
+#include_next <winbase.h>
+
+#endif
--- /dev/null
+#ifndef _FIX_WINSOCK2_H
+#define _FIX_WINSOCK2_H 1
+
+#include_next <winsock2.h>
+
+typedef struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+
+#endif
}
impl Drop for PoisonOnFail {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
/* assert!(!*self.failed);
-- might be false in case of cond.wait() */
#[unsafe_destructor]
impl Drop for Arena {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
destroy_chunk(&self.head);
do self.chunks.each |chunk| {
#[unsafe_destructor]
impl Drop for DtorRes {
- fn drop(&self) {
+ fn drop(&mut self) {
match self.dtor {
option::None => (),
option::Some(f) => f()
#[unsafe_destructor]
impl<T> Drop for DList<T> {
- fn drop(&self) {
- let mut_self = unsafe {
- cast::transmute_mut(self)
- };
+ fn drop(&mut self) {
// Dissolve the dlist in backwards direction
// Just dropping the list_head can lead to stack exhaustion
// when length is >> 1_000_000
- let mut tail = mut_self.list_tail;
+ let mut tail = self.list_tail;
loop {
match tail.resolve() {
None => break,
}
}
}
- mut_self.length = 0;
- mut_self.list_head = None;
- mut_self.list_tail = Rawlink::none();
+ self.length = 0;
+ self.list_head = None;
+ self.list_tail = Rawlink::none();
}
}
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_make_path_option_vec() {
let strs = [~"some/path",
~"some/other/path"];
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_fileinput_read_byte() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_fileinput_read() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec() {
let mut all_lines = ~[];
let filenames = make_path_option_vec(vec::from_fn(
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec_state() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_empty_files() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_no_trailing_newline() {
let f1 =
Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
#[test]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_next_file() {
let filenames = make_path_option_vec(vec::from_fn(
3,
#[test]
#[should_fail]
- #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec_missing_file() {
do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| {
println(line);
// over ~fn's that have pipes and so forth within!
#[unsafe_destructor]
impl<A> Drop for Future<A> {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
enum FutureState<A> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-/*!
- * Simple getopt alternative.
- *
- * Construct a vector of options, either by using reqopt, optopt, and optflag
- * or by building them from components yourself, and pass them to getopts,
- * along with a vector of actual arguments (not including argv[0]). You'll
- * either get a failure code back, or a match. You'll have to verify whether
- * the amount of 'free' arguments in the match is what you expect. Use opt_*
- * accessors to get argument values out of the matches object.
- *
- * Single-character options are expected to appear on the command line with a
- * single preceding dash; multiple-character options are expected to be
- * proceeded by two dashes. Options that expect an argument accept their
- * argument following either a space or an equals sign. Single-character
- * options don't require the space.
- *
- * # Example
- *
- * The following example shows simple command line parsing for an application
- * that requires an input file to be specified, accepts an optional output
- * file name following -o, and accepts both -h and --help as optional flags.
- *
- * ```
- * extern mod extra;
- * use extra::getopts::*;
- * use std::os;
- *
- * fn do_work(in: &str, out: Option<~str>) {
- * println(in);
- * println(match out {
- * Some(x) => x,
- * None => ~"No Output"
- * });
- * }
- *
- * fn print_usage(program: &str, _opts: &[Opt]) {
- * printfln!("Usage: %s [options]", program);
- * println("-o\t\tOutput");
- * println("-h --help\tUsage");
- * }
- *
- * fn main() {
- * let args = os::args();
- *
- * let program = args[0].clone();
- *
- * let opts = ~[
- * optopt("o"),
- * optflag("h"),
- * optflag("help")
- * ];
- * let matches = match getopts(args.tail(), opts) {
- * Ok(m) => { m }
- * Err(f) => { fail!(fail_str(f)) }
- * };
- * if opt_present(&matches, "h") || opt_present(&matches, "help") {
- * print_usage(program, opts);
- * return;
- * }
- * let output = opt_maybe_str(&matches, "o");
- * let input: &str = if !matches.free.is_empty() {
- * matches.free[0].clone()
- * } else {
- * print_usage(program, opts);
- * return;
- * };
- * do_work(input, output);
- * }
- * ```
- */
-
-#[allow(missing_doc)];
-
+//! Simple getopt alternative.
+//!
+//! Construct a vector of options, either by using reqopt, optopt, and optflag
+//! or by building them from components yourself, and pass them to getopts,
+//! along with a vector of actual arguments (not including argv[0]). You'll
+//! either get a failure code back, or a match. You'll have to verify whether
+//! the amount of 'free' arguments in the match is what you expect. Use opt_*
+//! accessors to get argument values out of the matches object.
+//!
+//! Single-character options are expected to appear on the command line with a
+//! single preceding dash; multiple-character options are expected to be
+//! proceeded by two dashes. Options that expect an argument accept their
+//! argument following either a space or an equals sign. Single-character
+//! options don't require the space.
+//!
+//! # Example
+//!
+//! The following example shows simple command line parsing for an application
+//! that requires an input file to be specified, accepts an optional output
+//! file name following -o, and accepts both -h and --help as optional flags.
+//!
+//! ```
+//! exter mod extra;
+//! use extra::getopts::*;
+//! use std::os;
+//!
+//! fn do_work(inp: &str, out: Option<~str>) {
+//! println(inp);
+//! println(match out {
+//! Some(x) => x,
+//! None => ~"No Output"
+//! });
+//! }
+//!
+//! fn print_usage(program: &str, _opts: &[Opt]) {
+//! printfln!("Usage: %s [options]", program);
+//! println("-o\t\tOutput");
+//! println("-h --help\tUsage");
+//! }
+//!
+//! fn main() {
+//! let args = os::args();
+//!
+//! let program = args[0].clone();
+//!
+//! let opts = ~[
+//! optopt("o"),
+//! optflag("h"),
+//! optflag("help")
+//! ];
+//! let matches = match getopts(args.tail(), opts) {
+//! Ok(m) => { m }
+//! Err(f) => { fail!(f.to_err_msg()) }
+//! };
+//! if matches.opt_present("h") || matches.opt_present("help") {
+//! print_usage(program, opts);
+//! return;
+//! }
+//! let output = matches.opt_str("o");
+//! let input: &str = if !matches.free.is_empty() {
+//! matches.free[0].clone()
+//! } else {
+//! print_usage(program, opts);
+//! return;
+//! };
+//! do_work(input, output);
+//! }
+//! ```
use std::cmp::Eq;
use std::result::{Err, Ok};
use std::result;
use std::option::{Some, None};
-use std::str;
use std::vec;
+/// Name of an option. Either a string or a single char.
#[deriving(Clone, Eq)]
pub enum Name {
Long(~str),
Short(char),
}
+/// Describes whether an option has an argument.
#[deriving(Clone, Eq)]
pub enum HasArg {
Yes,
Maybe,
}
+/// Describes how often an option may occur.
#[deriving(Clone, Eq)]
pub enum Occur {
Req,
Multi,
}
-/// A description of a possible option
+/// A description of a possible option.
#[deriving(Clone, Eq)]
pub struct Opt {
+ /// Name of the option
name: Name,
+ /// Wheter it has an argument
hasarg: HasArg,
+ /// How often it can occur
occur: Occur,
+ /// Which options it aliases
aliases: ~[Opt],
}
-fn mkname(nm: &str) -> Name {
- if nm.len() == 1u {
- Short(nm.char_at(0u))
- } else {
- Long(nm.to_owned())
- }
+/// Describes wether an option is given at all or has a value.
+#[deriving(Clone, Eq)]
+enum Optval {
+ Val(~str),
+ Given,
}
-/// Create an option that is required and takes an argument
-pub fn reqopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
+/// The result of checking command line arguments. Contains a vector
+/// of matches and a vector of free strings.
+#[deriving(Clone, Eq)]
+pub struct Matches {
+ /// Options that matched
+ opts: ~[Opt],
+ /// Values of the Options that matched
+ vals: ~[~[Optval]],
+ /// Free string fragments
+ free: ~[~str]
}
-/// Create an option that is optional and takes an argument
-pub fn optopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
+/// The type returned when the command line does not conform to the
+/// expected format. Pass this value to <fail_str> to get an error message.
+#[deriving(Clone, Eq, ToStr)]
+pub enum Fail_ {
+ ArgumentMissing(~str),
+ UnrecognizedOption(~str),
+ OptionMissing(~str),
+ OptionDuplicated(~str),
+ UnexpectedArgument(~str),
}
-/// Create an option that is optional and does not take an argument
-pub fn optflag(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
+/// The type of failure that occured.
+#[deriving(Eq)]
+pub enum FailType {
+ ArgumentMissing_,
+ UnrecognizedOption_,
+ OptionMissing_,
+ OptionDuplicated_,
+ UnexpectedArgument_,
}
-/** Create an option that is optional, does not take an argument,
- * and may occur multiple times.
- */
-pub fn optflagmulti(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
-}
+/// The result of parsing a command line with a set of options.
+pub type Result = result::Result<Matches, Fail_>;
-/// Create an option that is optional and takes an optional argument
-pub fn optflagopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
-}
+impl Name {
+ fn from_str(nm: &str) -> Name {
+ if nm.len() == 1u {
+ Short(nm.char_at(0u))
+ } else {
+ Long(nm.to_owned())
+ }
+ }
-/**
- * Create an option that is optional, takes an argument, and may occur
- * multiple times
- */
-pub fn optmulti(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
+ fn to_str(&self) -> ~str {
+ match *self {
+ Short(ch) => ch.to_str(),
+ Long(ref s) => s.to_owned()
+ }
+ }
}
-#[deriving(Clone, Eq)]
-enum Optval {
- Val(~str),
- Given,
-}
+impl Matches {
+ /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+ /// No idea what this does.
+ pub fn opt_vals(&self, nm: &str) -> ~[Optval] {
+ match find_opt(self.opts, Name::from_str(nm)) {
+ Some(id) => self.vals[id].clone(),
+ None => fail!("No option '%s' defined", nm)
+ }
+ }
-/**
- * The result of checking command line arguments. Contains a vector
- * of matches and a vector of free strings.
- */
-#[deriving(Clone, Eq)]
-pub struct Matches {
- opts: ~[Opt],
- vals: ~[~[Optval]],
- free: ~[~str]
-}
+ /// FIXME: #9311 This used to be private, but rustpkg somehow managed to depend on it.
+ /// No idea what this does.
+ pub fn opt_val(&self, nm: &str) -> Option<Optval> {
+ let vals = self.opt_vals(nm);
+ if (vals.is_empty()) {
+ None
+ } else {
+ Some(vals[0].clone())
+ }
+ }
+
+ /// Returns true if an option was matched.
+ pub fn opt_present(&self, nm: &str) -> bool {
+ !self.opt_vals(nm).is_empty()
+ }
+
+ /// Returns the number of times an option was matched.
+ pub fn opt_count(&self, nm: &str) -> uint {
+ self.opt_vals(nm).len()
+ }
+
+ /// Returns true if any of several options were matched.
+ pub fn opts_present(&self, names: &[~str]) -> bool {
+ for nm in names.iter() {
+ match find_opt(self.opts, Name::from_str(*nm)) {
+ Some(id) if !self.vals[id].is_empty() => return true,
+ _ => (),
+ };
+ }
+ false
+ }
+
+ /// Returns the string argument supplied to one of several matching options or `None`.
+ pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
+ for nm in names.iter() {
+ match self.opt_val(*nm) {
+ Some(Val(ref s)) => return Some(s.clone()),
+ _ => ()
+ }
+ }
+ None
+ }
+
+ /// Returns a vector of the arguments provided to all matches of the given
+ /// option.
+ ///
+ /// Used when an option accepts multiple values.
+ pub fn opt_strs(&self, nm: &str) -> ~[~str] {
+ let mut acc: ~[~str] = ~[];
+ let r = self.opt_vals(nm);
+ for v in r.iter() {
+ match *v {
+ Val(ref s) => acc.push((*s).clone()),
+ _ => ()
+ }
+ }
+ acc
+ }
+
+ /// Returns the string argument supplied to a matching option or `None`.
+ pub fn opt_str(&self, nm: &str) -> Option<~str> {
+ let vals = self.opt_vals(nm);
+ if vals.is_empty() {
+ return None::<~str>;
+ }
+ match vals[0] {
+ Val(ref s) => Some((*s).clone()),
+ _ => None
+ }
+ }
+
+
+ /// Returns the matching string, a default, or none.
+ ///
+ /// Returns none if the option was not present, `def` if the option was
+ /// present but no argument was provided, and the argument if the option was
+ /// present and an argument was provided.
+ pub fn opt_default(&self, nm: &str, def: &str) -> Option<~str> {
+ let vals = self.opt_vals(nm);
+ if vals.is_empty() { return None; }
+ match vals[0] {
+ Val(ref s) => Some((*s).clone()),
+ _ => Some(def.to_owned())
+ }
+ }
-fn is_arg(arg: &str) -> bool {
- return arg.len() > 1 && arg[0] == '-' as u8;
}
-fn name_str(nm: &Name) -> ~str {
- return match *nm {
- Short(ch) => str::from_char(ch),
- Long(ref s) => (*s).clone()
- };
+fn is_arg(arg: &str) -> bool {
+ arg.len() > 1 && arg[0] == '-' as u8
}
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
- // search main options
+ // Search main options.
let pos = opts.iter().position(|opt| opt.name == nm);
if pos.is_some() {
return pos
}
- // search in aliases
+ // Search in aliases.
for candidate in opts.iter() {
if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
return opts.iter().position(|opt| opt.name == candidate.name);
None
}
-/**
- * The type returned when the command line does not conform to the
- * expected format. Pass this value to <fail_str> to get an error message.
- */
-#[deriving(Clone, Eq, ToStr)]
-pub enum Fail_ {
- ArgumentMissing(~str),
- UnrecognizedOption(~str),
- OptionMissing(~str),
- OptionDuplicated(~str),
- UnexpectedArgument(~str),
+/// Create an option that is required and takes an argument.
+pub fn reqopt(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: Yes,
+ occur: Req,
+ aliases: ~[]
+ }
}
-/// Convert a `fail_` enum into an error string
-pub fn fail_str(f: Fail_) -> ~str {
- return match f {
- ArgumentMissing(ref nm) => {
- fmt!("Argument to option '%s' missing.", *nm)
- }
- UnrecognizedOption(ref nm) => {
- fmt!("Unrecognized option: '%s'.", *nm)
- }
- OptionMissing(ref nm) => {
- fmt!("Required option '%s' missing.", *nm)
- }
- OptionDuplicated(ref nm) => {
- fmt!("Option '%s' given more than once.", *nm)
- }
- UnexpectedArgument(ref nm) => {
- fmt!("Option '%s' does not take an argument.", *nm)
- }
- };
+/// Create an option that is optional and takes an argument.
+pub fn optopt(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: Yes,
+ occur: Optional,
+ aliases: ~[]
+ }
}
-/**
- * The result of parsing a command line with a set of options
- * (result::t<Matches, Fail_>)
- */
-pub type Result = result::Result<Matches, Fail_>;
+/// Create an option that is optional and does not take an argument.
+pub fn optflag(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: No,
+ occur: Optional,
+ aliases: ~[]
+ }
+}
+
+/// Create an option that is optional, does not take an argument,
+/// and may occur multiple times.
+pub fn optflagmulti(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: No,
+ occur: Multi,
+ aliases: ~[]
+ }
+}
+
+/// Create an option that is optional and takes an optional argument.
+pub fn optflagopt(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: Maybe,
+ occur: Optional,
+ aliases: ~[]
+ }
+}
+
+/// Create an option that is optional, takes an argument, and may occur
+/// multiple times.
+pub fn optmulti(name: &str) -> Opt {
+ Opt {
+ name: Name::from_str(name),
+ hasarg: Yes,
+ occur: Multi,
+ aliases: ~[]
+ }
+}
-/**
- * Parse command line arguments according to the provided options
- *
- * On success returns `ok(Opt)`. Use functions such as `opt_present`
- * `opt_str`, etc. to interrogate results. Returns `err(Fail_)` on failure.
- * Use <fail_str> to get an error message.
- */
+impl Fail_ {
+ /// Convert a `Fail_` enum into an error string.
+ pub fn to_err_msg(self) -> ~str {
+ match self {
+ ArgumentMissing(ref nm) => {
+ fmt!("Argument to option '%s' missing.", *nm)
+ }
+ UnrecognizedOption(ref nm) => {
+ fmt!("Unrecognized option: '%s'.", *nm)
+ }
+ OptionMissing(ref nm) => {
+ fmt!("Required option '%s' missing.", *nm)
+ }
+ OptionDuplicated(ref nm) => {
+ fmt!("Option '%s' given more than once.", *nm)
+ }
+ UnexpectedArgument(ref nm) => {
+ fmt!("Option '%s' does not take an argument.", *nm)
+ }
+ }
+ }
+}
+
+/// Parse command line arguments according to the provided options.
+///
+/// On success returns `Ok(Opt)`. Use methods such as `opt_present`
+/// `opt_str`, etc. to interrogate results. Returns `Err(Fail_)` on failure.
+/// Use `to_err_msg` to get an error message.
pub fn getopts(args: &[~str], opts: &[Opt]) -> Result {
let n_opts = opts.len();
+
fn f(_x: uint) -> ~[Optval] { return ~[]; }
+
let mut vals = vec::from_fn(n_opts, f);
let mut free: ~[~str] = ~[];
let l = args.len();
name_pos += 1;
let optid = match find_opt(opts, (*nm).clone()) {
Some(id) => id,
- None => return Err(UnrecognizedOption(name_str(nm)))
+ None => return Err(UnrecognizedOption(nm.to_str()))
};
match opts[optid].hasarg {
No => {
if !i_arg.is_none() {
- return Err(UnexpectedArgument(name_str(nm)));
+ return Err(UnexpectedArgument(nm.to_str()));
}
vals[optid].push(Given);
}
if !i_arg.is_none() {
vals[optid].push(Val(i_arg.clone().unwrap()));
} else if i + 1 == l {
- return Err(ArgumentMissing(name_str(nm)));
+ return Err(ArgumentMissing(nm.to_str()));
} else { i += 1; vals[optid].push(Val(args[i].clone())); }
}
}
let occ = opts[i].occur;
if occ == Req {
if n == 0 {
- return Err(OptionMissing(name_str(&(opts[i].name))));
+ return Err(OptionMissing(opts[i].name.to_str()));
}
}
if occ != Multi {
if n > 1 {
- return Err(OptionDuplicated(name_str(&(opts[i].name))));
+ return Err(OptionDuplicated(opts[i].name.to_str()));
}
}
i += 1;
}
- return Ok(Matches {opts: opts.to_owned(),
- vals: vals,
- free: free});
-}
-
-fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] {
- return match find_opt(mm.opts, mkname(nm)) {
- Some(id) => mm.vals[id].clone(),
- None => {
- error!("No option '%s' defined", nm);
- fail!()
- }
- };
-}
-
-fn opt_val(mm: &Matches, nm: &str) -> Option<Optval> {
- let vals = opt_vals(mm, nm);
- if (vals.is_empty()) {
- None
- } else {
- Some(opt_vals(mm, nm)[0].clone())
- }
-}
-
-/// Returns true if an option was matched
-pub fn opt_present(mm: &Matches, nm: &str) -> bool {
- !opt_vals(mm, nm).is_empty()
-}
-
-/// Returns the number of times an option was matched
-pub fn opt_count(mm: &Matches, nm: &str) -> uint {
- opt_vals(mm, nm).len()
-}
-
-/// Returns true if any of several options were matched
-pub fn opts_present(mm: &Matches, names: &[~str]) -> bool {
- for nm in names.iter() {
- match find_opt(mm.opts, mkname(*nm)) {
- Some(id) if !mm.vals[id].is_empty() => return true,
- _ => (),
- };
- }
- false
-}
-
-
-/**
- * Returns the string argument supplied to a matching option
- *
- * Fails if the option was not matched or if the match did not take an
- * argument
- */
-pub fn opt_str(mm: &Matches, nm: &str) -> ~str {
- return match opt_val(mm, nm) {
- Some(Val(s)) => s,
- _ => fail!()
- };
-}
-
-/**
- * Returns the string argument supplied to one of several matching options
- *
- * Fails if the no option was provided from the given list, or if the no such
- * option took an argument
- */
-pub fn opts_str(mm: &Matches, names: &[~str]) -> ~str {
- for nm in names.iter() {
- match opt_val(mm, *nm) {
- Some(Val(ref s)) => return (*s).clone(),
- _ => ()
- }
- }
- fail!();
+ Ok(Matches {
+ opts: opts.to_owned(),
+ vals: vals,
+ free: free
+ })
}
-
-/**
- * Returns a vector of the arguments provided to all matches of the given
- * option.
- *
- * Used when an option accepts multiple values.
- */
-pub fn opt_strs(mm: &Matches, nm: &str) -> ~[~str] {
- let mut acc: ~[~str] = ~[];
- let r = opt_vals(mm, nm);
- for v in r.iter() {
- match *v { Val(ref s) => acc.push((*s).clone()), _ => () }
- }
- acc
-}
-
-/// Returns the string argument supplied to a matching option or none
-pub fn opt_maybe_str(mm: &Matches, nm: &str) -> Option<~str> {
- let vals = opt_vals(mm, nm);
- if vals.is_empty() { return None::<~str>; }
- return match vals[0] {
- Val(ref s) => Some((*s).clone()),
- _ => None
- };
-}
-
-
-/**
- * Returns the matching string, a default, or none
- *
- * Returns none if the option was not present, `def` if the option was
- * present but no argument was provided, and the argument if the option was
- * present and an argument was provided.
- */
-pub fn opt_default(mm: &Matches, nm: &str, def: &str) -> Option<~str> {
- let vals = opt_vals(mm, nm);
- if vals.is_empty() { return None::<~str>; }
- return match vals[0] { Val(ref s) => Some::<~str>((*s).clone()),
- _ => Some::<~str>(def.to_owned()) }
-}
-
-#[deriving(Eq)]
-pub enum FailType {
- ArgumentMissing_,
- UnrecognizedOption_,
- OptionMissing_,
- OptionDuplicated_,
- UnexpectedArgument_,
-}
-
-/** A module which provides a way to specify descriptions and
- * groups of short and long option names, together.
- */
+/// A module which provides a way to specify descriptions and
+/// groups of short and long option names, together.
pub mod groups {
use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
use getopts::{Short, Yes};
- /** one group of options, e.g., both -h and --help, along with
- * their shared description and properties
- */
+ /// One group of options, e.g., both -h and --help, along with
+ /// their shared description and properties.
#[deriving(Clone, Eq)]
pub struct OptGroup {
+ /// Short Name of the `OptGroup`
short_name: ~str,
+ /// Long Name of the `OptGroup`
long_name: ~str,
+ /// Hint
hint: ~str,
+ /// Description
desc: ~str,
+ /// Whether it has an argument
hasarg: HasArg,
+ /// How often it can occur
occur: Occur
}
- /// Create a long option that is required and takes an argument
- pub fn reqopt(short_name: &str, long_name: &str,
- desc: &str, hint: &str) -> OptGroup {
+ impl OptGroup {
+ /// Translate OptGroup into Opt.
+ /// (Both short and long names correspond to different Opts).
+ pub fn long_to_short(&self) -> Opt {
+ let OptGroup {
+ short_name: short_name,
+ long_name: long_name,
+ hasarg: hasarg,
+ occur: occur,
+ _
+ } = (*self).clone();
+
+ match (short_name.len(), long_name.len()) {
+ (0,0) => fail!("this long-format option was given no name"),
+ (0,_) => Opt {
+ name: Long((long_name)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]
+ },
+ (1,0) => Opt {
+ name: Short(short_name.char_at(0)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]
+ },
+ (1,_) => Opt {
+ name: Long((long_name)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[
+ Opt {
+ name: Short(short_name.char_at(0)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]
+ }
+ ]
+ },
+ (_,_) => fail!("something is wrong with the long-form opt")
+ }
+ }
+ }
+
+ /// Create a long option that is required and takes an argument.
+ pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup { short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: hint.to_owned(),
- desc: desc.to_owned(),
- hasarg: Yes,
- occur: Req};
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: hint.to_owned(),
+ desc: desc.to_owned(),
+ hasarg: Yes,
+ occur: Req
+ }
}
- /// Create a long option that is optional and takes an argument
- pub fn optopt(short_name: &str, long_name: &str,
- desc: &str, hint: &str) -> OptGroup {
+ /// Create a long option that is optional and takes an argument.
+ pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup {short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: hint.to_owned(),
- desc: desc.to_owned(),
- hasarg: Yes,
- occur: Optional};
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: hint.to_owned(),
+ desc: desc.to_owned(),
+ hasarg: Yes,
+ occur: Optional
+ }
}
- /// Create a long option that is optional and does not take an argument
- pub fn optflag(short_name: &str, long_name: &str,
- desc: &str) -> OptGroup {
+ /// Create a long option that is optional and does not take an argument.
+ pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup {short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: ~"",
- desc: desc.to_owned(),
- hasarg: No,
- occur: Optional};
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: ~"",
+ desc: desc.to_owned(),
+ hasarg: No,
+ occur: Optional
+ }
}
/// Create a long option that can occur more than once and does not
- /// take an argument
- pub fn optflagmulti(short_name: &str, long_name: &str,
- desc: &str) -> OptGroup {
+ /// take an argument.
+ pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup {short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: ~"",
- desc: desc.to_owned(),
- hasarg: No,
- occur: Multi};
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: ~"",
+ desc: desc.to_owned(),
+ hasarg: No,
+ occur: Multi
+ }
}
- /// Create a long option that is optional and takes an optional argument
- pub fn optflagopt(short_name: &str, long_name: &str,
- desc: &str, hint: &str) -> OptGroup {
+ /// Create a long option that is optional and takes an optional argument.
+ pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup {short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: hint.to_owned(),
- desc: desc.to_owned(),
- hasarg: Maybe,
- occur: Optional};
- }
-
- /**
- * Create a long option that is optional, takes an argument, and may occur
- * multiple times
- */
- pub fn optmulti(short_name: &str, long_name: &str,
- desc: &str, hint: &str) -> OptGroup {
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: hint.to_owned(),
+ desc: desc.to_owned(),
+ hasarg: Maybe,
+ occur: Optional
+ }
+ }
+
+ /// Create a long option that is optional, takes an argument, and may occur
+ /// multiple times.
+ pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptGroup {
let len = short_name.len();
assert!(len == 1 || len == 0);
- return OptGroup {short_name: short_name.to_owned(),
- long_name: long_name.to_owned(),
- hint: hint.to_owned(),
- desc: desc.to_owned(),
- hasarg: Yes,
- occur: Multi};
- }
-
- // translate OptGroup into Opt
- // (both short and long names correspond to different Opts)
- pub fn long_to_short(lopt: &OptGroup) -> Opt {
- let OptGroup{short_name: short_name,
- long_name: long_name,
- hasarg: hasarg,
- occur: occur,
- _} = (*lopt).clone();
-
- match (short_name.len(), long_name.len()) {
- (0,0) => fail!("this long-format option was given no name"),
-
- (0,_) => Opt {name: Long((long_name)),
- hasarg: hasarg,
- occur: occur,
- aliases: ~[]},
-
- (1,0) => Opt {name: Short(short_name.char_at(0)),
- hasarg: hasarg,
- occur: occur,
- aliases: ~[]},
-
- (1,_) => Opt {name: Long((long_name)),
- hasarg: hasarg,
- occur: occur,
- aliases: ~[Opt {
- name: Short(short_name.char_at(0)),
- hasarg: hasarg,
- occur: occur,
- aliases: ~[]
- }]},
-
- (_,_) => fail!("something is wrong with the long-form opt")
- }
- }
-
- /*
- * Parse command line args with the provided long format options
- */
+ OptGroup {
+ short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: hint.to_owned(),
+ desc: desc.to_owned(),
+ hasarg: Yes,
+ occur: Multi
+ }
+ }
+
+ /// Parse command line args with the provided long format options.
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
- ::getopts::getopts(args, opts.map(long_to_short))
+ ::getopts::getopts(args, opts.map(|x| x.long_to_short()))
}
- /**
- * Derive a usage message from a set of long options
- */
+ /// Derive a usage message from a set of long options.
pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
let desc_sep = "\n" + " ".repeat(24);
row
});
- return brief.to_owned() +
- "\n\nOptions:\n" +
- rows.collect::<~[~str]>().connect("\n") +
- "\n";
- }
-
- /** Splits a string into substrings with possibly internal whitespace,
- * each of them at most `lim` bytes long. The substrings have leading and trailing
- * whitespace removed, and are only cut at whitespace boundaries.
- *
- * Note: Function was moved here from `std::str` because this module is the only place that
- * uses it, and because it was to specific for a general string function.
- *
- * #Failure:
- *
- * Fails during iteration if the string contains a non-whitespace
- * sequence longer than the limit.
- */
+ fmt!("%s\n\nOptions:\n%s\n", brief, rows.collect::<~[~str]>().connect("\n"))
+ }
+
+ /// Splits a string into substrings with possibly internal whitespace,
+ /// each of them at most `lim` bytes long. The substrings have leading and trailing
+ /// whitespace removed, and are only cut at whitespace boundaries.
+ ///
+ /// Note: Function was moved here from `std::str` because this module is the only place that
+ /// uses it, and because it was to specific for a general string function.
+ ///
+ /// #Failure:
+ ///
+ /// Fails during iteration if the string contains a non-whitespace
+ /// sequence longer than the limit.
fn each_split_within<'a>(ss: &'a str,
lim: uint,
it: &fn(&'a str) -> bool) -> bool {
- // Just for fun, let's write this as an state machine:
+ // Just for fun, let's write this as a state machine:
enum SplitWithinState {
A, // leading whitespace, initial state
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "test")));
- assert_eq!(opt_str(m, "test"), ~"20");
+ assert!(m.opt_present("test"));
+ assert_eq!(m.opt_str("test").unwrap(), ~"20");
}
_ => { fail!("test_reqopt_long failed"); }
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "t")));
- assert_eq!(opt_str(m, "t"), ~"20");
+ assert!(m.opt_present("t"));
+ assert_eq!(m.opt_str("t").unwrap(), ~"20");
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "test")));
- assert_eq!(opt_str(m, "test"), ~"20");
+ assert!(m.opt_present("test"));
+ assert_eq!(m.opt_str("test").unwrap(), ~"20");
}
_ => fail!()
}
let opts = ~[optopt("test")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "test")),
+ Ok(ref m) => assert!(!m.opt_present("test")),
_ => fail!()
}
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "t")));
- assert_eq!(opt_str(m, "t"), ~"20");
+ assert!((m.opt_present("t")));
+ assert_eq!(m.opt_str("t").unwrap(), ~"20");
}
_ => fail!()
}
let opts = ~[optopt("t")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "t")),
+ Ok(ref m) => assert!(!m.opt_present("t")),
_ => fail!()
}
}
let opts = ~[optflag("test")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(opt_present(m, "test")),
+ Ok(ref m) => assert!(m.opt_present("test")),
_ => fail!()
}
}
let opts = ~[optflag("test")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "test")),
+ Ok(ref m) => assert!(!m.opt_present("test")),
_ => fail!()
}
}
let rs = getopts(args, opts);
match rs {
Err(f) => {
- error!(fail_str(f.clone()));
+ error!(f.clone().to_err_msg());
check_fail_type(f, UnexpectedArgument_);
}
_ => fail!()
let opts = ~[optflag("t")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(opt_present(m, "t")),
+ Ok(ref m) => assert!(m.opt_present("t")),
_ => fail!()
}
}
let opts = ~[optflag("t")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "t")),
+ Ok(ref m) => assert!(!m.opt_present("t")),
_ => fail!()
}
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert_eq!(opt_count(m, "v"), 1);
+ assert_eq!(m.opt_count("v"), 1);
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert_eq!(opt_count(m, "v"), 2);
+ assert_eq!(m.opt_count("v"), 2);
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert_eq!(opt_count(m, "v"), 2);
+ assert_eq!(m.opt_count("v"), 2);
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert_eq!(opt_count(m, "verbose"), 1);
+ assert_eq!(m.opt_count("verbose"), 1);
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert_eq!(opt_count(m, "verbose"), 2);
+ assert_eq!(m.opt_count("verbose"), 2);
}
_ => fail!()
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "test")));
- assert_eq!(opt_str(m, "test"), ~"20");
+ assert!((m.opt_present("test")));
+ assert_eq!(m.opt_str("test").unwrap(), ~"20");
}
_ => fail!()
}
let opts = ~[optmulti("test")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "test")),
+ Ok(ref m) => assert!(!m.opt_present("test")),
_ => fail!()
}
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!(opt_present(m, "test"));
- assert_eq!(opt_str(m, "test"), ~"20");
- let pair = opt_strs(m, "test");
+ assert!(m.opt_present("test"));
+ assert_eq!(m.opt_str("test").unwrap(), ~"20");
+ let pair = m.opt_strs("test");
assert!(pair[0] == ~"20");
assert!(pair[1] == ~"30");
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "t")));
- assert_eq!(opt_str(m, "t"), ~"20");
+ assert!((m.opt_present("t")));
+ assert_eq!(m.opt_str("t").unwrap(), ~"20");
}
_ => fail!()
}
let opts = ~[optmulti("t")];
let rs = getopts(args, opts);
match rs {
- Ok(ref m) => assert!(!opt_present(m, "t")),
+ Ok(ref m) => assert!(!m.opt_present("t")),
_ => fail!()
}
}
let rs = getopts(args, opts);
match rs {
Ok(ref m) => {
- assert!((opt_present(m, "t")));
- assert_eq!(opt_str(m, "t"), ~"20");
- let pair = opt_strs(m, "t");
+ assert!((m.opt_present("t")));
+ assert_eq!(m.opt_str("t").unwrap(), ~"20");
+ let pair = m.opt_strs("t");
assert!(pair[0] == ~"20");
assert!(pair[1] == ~"30");
}
Ok(ref m) => {
assert!(m.free[0] == ~"prog");
assert!(m.free[1] == ~"free1");
- assert_eq!(opt_str(m, "s"), ~"20");
+ assert_eq!(m.opt_str("s").unwrap(), ~"20");
assert!(m.free[2] == ~"free2");
- assert!((opt_present(m, "flag")));
- assert_eq!(opt_str(m, "long"), ~"30");
- assert!((opt_present(m, "f")));
- let pair = opt_strs(m, "m");
+ assert!((m.opt_present("flag")));
+ assert_eq!(m.opt_str("long").unwrap(), ~"30");
+ assert!((m.opt_present("f")));
+ let pair = m.opt_strs("m");
assert!(pair[0] == ~"40");
assert!(pair[1] == ~"50");
- let pair = opt_strs(m, "n");
+ let pair = m.opt_strs("n");
assert!(pair[0] == ~"-A B");
assert!(pair[1] == ~"-60 70");
- assert!((!opt_present(m, "notpresent")));
+ assert!((!m.opt_present("notpresent")));
}
_ => fail!()
}
result::Ok(m) => m,
result::Err(_) => fail!()
};
- assert!(opts_present(matches_single, [~"e"]));
- assert!(opts_present(matches_single, [~"encrypt", ~"e"]));
- assert!(opts_present(matches_single, [~"e", ~"encrypt"]));
- assert!(!opts_present(matches_single, [~"encrypt"]));
- assert!(!opts_present(matches_single, [~"thing"]));
- assert!(!opts_present(matches_single, []));
+ assert!(matches_single.opts_present([~"e"]));
+ assert!(matches_single.opts_present([~"encrypt", ~"e"]));
+ assert!(matches_single.opts_present([~"e", ~"encrypt"]));
+ assert!(!matches_single.opts_present([~"encrypt"]));
+ assert!(!matches_single.opts_present([~"thing"]));
+ assert!(!matches_single.opts_present([]));
- assert_eq!(opts_str(matches_single, [~"e"]), ~"foo");
- assert_eq!(opts_str(matches_single, [~"e", ~"encrypt"]), ~"foo");
- assert_eq!(opts_str(matches_single, [~"encrypt", ~"e"]), ~"foo");
+ assert_eq!(matches_single.opts_str([~"e"]).unwrap(), ~"foo");
+ assert_eq!(matches_single.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+ assert_eq!(matches_single.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
let args_both = ~[~"-e", ~"foo", ~"--encrypt", ~"foo"];
let matches_both = &match getopts(args_both, opts) {
result::Ok(m) => m,
result::Err(_) => fail!()
};
- assert!(opts_present(matches_both, [~"e"]));
- assert!(opts_present(matches_both, [~"encrypt"]));
- assert!(opts_present(matches_both, [~"encrypt", ~"e"]));
- assert!(opts_present(matches_both, [~"e", ~"encrypt"]));
- assert!(!opts_present(matches_both, [~"f"]));
- assert!(!opts_present(matches_both, [~"thing"]));
- assert!(!opts_present(matches_both, []));
+ assert!(matches_both.opts_present([~"e"]));
+ assert!(matches_both.opts_present([~"encrypt"]));
+ assert!(matches_both.opts_present([~"encrypt", ~"e"]));
+ assert!(matches_both.opts_present([~"e", ~"encrypt"]));
+ assert!(!matches_both.opts_present([~"f"]));
+ assert!(!matches_both.opts_present([~"thing"]));
+ assert!(!matches_both.opts_present([]));
- assert_eq!(opts_str(matches_both, [~"e"]), ~"foo");
- assert_eq!(opts_str(matches_both, [~"encrypt"]), ~"foo");
- assert_eq!(opts_str(matches_both, [~"e", ~"encrypt"]), ~"foo");
- assert_eq!(opts_str(matches_both, [~"encrypt", ~"e"]), ~"foo");
+ assert_eq!(matches_both.opts_str([~"e"]).unwrap(), ~"foo");
+ assert_eq!(matches_both.opts_str([~"encrypt"]).unwrap(), ~"foo");
+ assert_eq!(matches_both.opts_str([~"e", ~"encrypt"]).unwrap(), ~"foo");
+ assert_eq!(matches_both.opts_str([~"encrypt", ~"e"]).unwrap(), ~"foo");
}
#[test]
result::Ok(m) => m,
result::Err(_) => fail!()
};
- assert!(opts_present(matches, [~"L"]));
- assert_eq!(opts_str(matches, [~"L"]), ~"foo");
- assert!(opts_present(matches, [~"M"]));
- assert_eq!(opts_str(matches, [~"M"]), ~".");
+ assert!(matches.opts_present([~"L"]));
+ assert_eq!(matches.opts_str([~"L"]).unwrap(), ~"foo");
+ assert!(matches.opts_present([~"M"]));
+ assert_eq!(matches.opts_str([~"M"]).unwrap(), ~".");
}
short.aliases = ~[reqopt("b")];
let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
- assert_eq!(groups::long_to_short(&verbose), short);
+ assert_eq!(verbose.long_to_short(), short);
}
#[test]
let args = ~[~"-a", ~"--apple", ~"-a"];
let matches = groups::getopts(args, opts).unwrap();
- assert_eq!(3, opt_count(&matches, "a"));
- assert_eq!(3, opt_count(&matches, "apple"));
+ assert_eq!(3, matches.opt_count("a"));
+ assert_eq!(3, matches.opt_count("apple"));
}
#[test]
/**
* A compiled Unix shell style pattern.
*/
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct Pattern {
- priv tokens: ~[PatternToken]
-}
-
-/**
- * A compiled Unix shell style pattern.
- */
-#[cfg(not(stage0))]
#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
pub struct Pattern {
priv tokens: ~[PatternToken]
}
}
-/**
- * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
- */
-#[cfg(stage0)]
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
-pub struct MatchOptions {
-
- /**
- * Whether or not patterns should be matched in a case-sensitive manner. This
- * currently only considers upper/lower case relationships between ASCII characters,
- * but in future this might be extended to work with Unicode.
- */
- case_sensitive: bool,
-
- /**
- * If this is true then path-component separator characters (e.g. `/` on Posix)
- * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
- */
- require_literal_separator: bool,
-
- /**
- * If this is true then paths that contain components that start with a `.` will
- * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
- * will not match. This is useful because such files are conventionally considered
- * hidden on Unix systems and it might be desirable to skip them when listing files.
- */
- require_literal_leading_dot: bool
-}
/**
* Configuration options to modify the behaviour of `Pattern::matches_with(..)`
*/
-#[cfg(not(stage0))]
#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
pub struct MatchOptions {
_id: uint,
cnt: uint,
f: &fn(&mut Encoder)) {
- // enums are encoded as strings or vectors:
+ // enums are encoded as strings or objects
// Bunny => "Bunny"
- // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]]
-
+ // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
if cnt == 0 {
self.wr.write_str(escape_str(name));
} else {
- self.wr.write_char('[');
+ self.wr.write_char('{');
+ self.wr.write_str("\"variant\"");
+ self.wr.write_char(':');
self.wr.write_str(escape_str(name));
self.wr.write_char(',');
+ self.wr.write_str("\"fields\"");
+ self.wr.write_str(":[");
f(self);
- self.wr.write_char(']');
+ self.wr.write_str("]}");
}
}
debug!("read_enum_variant(names=%?)", names);
let name = match self.stack.pop() {
String(s) => s,
- List(list) => {
- for v in list.move_rev_iter() {
- self.stack.push(v);
- }
- match self.stack.pop() {
- String(s) => s,
- value => fail!("invalid variant name: %?", value),
+ Object(o) => {
+ let n = match o.find(&~"variant").expect("invalidly encoded json") {
+ &String(ref s) => s.clone(),
+ _ => fail!("invalidly encoded json"),
+ };
+ match o.find(&~"fields").expect("invalidly encoded json") {
+ &List(ref l) => {
+ for field in l.rev_iter() {
+ self.stack.push(field.clone());
+ }
+ },
+ _ => fail!("invalidly encoded json")
}
+ n
}
ref json => fail!("invalid variant: %?", *json),
};
let mut encoder = Encoder(wr);
animal.encode(&mut encoder);
},
- ~"[\"Frog\",\"Henry\",349]"
+ ~"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
);
assert_eq!(
do io::with_str_writer |wr| {
assert_eq!(value, Dog);
let mut decoder =
- Decoder(from_str("[\"Frog\",\"Henry\",349]").unwrap());
+ Decoder(from_str("{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}").unwrap());
let value: Animal = Decodable::decode(&mut decoder);
assert_eq!(value, Frog(~"Henry", 349));
}
#[test]
fn test_decode_map() {
- let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}";
+ let s = ~"{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\"fields\":[\"Henry\", 349]}}";
let mut decoder = Decoder(from_str(s).unwrap());
let mut map: TreeMap<~str, Animal> = Decodable::decode(&mut decoder);
if s_len > o_len { return Greater; }
for (&self_i, &other_i) in self.data.rev_iter().zip(other.data.rev_iter()) {
- cond!((self_i < other_i) { return Less; }
- (self_i > other_i) { return Greater; })
+ if self_i < other_i { return Less; }
+ if self_i > other_i { return Greater; }
}
return Equal;
}
}
return BigUint::new(shifted);
}
+
+ /// Determines the fewest bits necessary to express the BigUint.
+ pub fn bits(&self) -> uint {
+ if self.is_zero() { return 0; }
+ let zeros = self.data.last().leading_zeros();
+ return self.data.len()*BigDigit::bits - (zeros as uint);
+ }
}
#[cfg(target_word_size = "64")]
/// Generate a random BigInt of the given bit size.
fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
+
+ /// Generate a random BigUint less than the given bound. Fails
+ /// when the bound is zero.
+ fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;
+
+ /// Generate a random BigUint within the given range. The lower
+ /// bound is inclusive; the upper bound is exclusive. Fails when
+ /// the upper bound is not greater than the lower bound.
+ fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
+
+ /// Generate a random BigInt within the given range. The lower
+ /// bound is inclusive; the upper bound is exclusive. Fails when
+ /// the upper bound is not greater than the lower bound.
+ fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
}
impl<R: Rng> RandBigInt for R {
- /// Generate a random BigUint of the given bit size.
fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
let mut data = vec::with_capacity(digits+1);
return BigUint::new(data);
}
- /// Generate a random BigInt of the given bit size.
fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
// Generate a random BigUint...
let biguint = self.gen_biguint(bit_size);
};
return BigInt::from_biguint(sign, biguint);
}
+
+ fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
+ assert!(!bound.is_zero());
+ let bits = bound.bits();
+ loop {
+ let n = self.gen_biguint(bits);
+ if n < *bound { return n; }
+ }
+ }
+
+ fn gen_biguint_range(&mut self,
+ lbound: &BigUint,
+ ubound: &BigUint)
+ -> BigUint {
+ assert!(*lbound < *ubound);
+ return *lbound + self.gen_biguint_below(&(*ubound - *lbound));
+ }
+
+ fn gen_bigint_range(&mut self,
+ lbound: &BigInt,
+ ubound: &BigInt)
+ -> BigInt {
+ assert!(*lbound < *ubound);
+ let delta = (*ubound - *lbound).to_biguint();
+ return *lbound + self.gen_biguint_below(&delta).to_bigint();
+ }
}
impl BigInt {
check(30, "265252859812191058636308480000000");
}
+ #[test]
+ fn test_bits() {
+ assert_eq!(BigUint::new(~[0,0,0,0]).bits(), 0);
+ assert_eq!(BigUint::from_uint(0).bits(), 0);
+ assert_eq!(BigUint::from_uint(1).bits(), 1);
+ assert_eq!(BigUint::from_uint(3).bits(), 2);
+ let n: BigUint = FromStrRadix::from_str_radix("4000000000", 16).unwrap();
+ assert_eq!(n.bits(), 39);
+ let one: BigUint = One::one();
+ assert_eq!((one << 426).bits(), 427);
+ }
+
#[test]
fn test_rand() {
let mut rng = task_rng();
let _n: BigUint = rng.gen_biguint(137);
assert!(rng.gen_biguint(0).is_zero());
}
+
+ #[test]
+ fn test_rand_range() {
+ let mut rng = task_rng();
+
+ do 10.times {
+ assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
+ &BigInt::from_uint(237)),
+ BigInt::from_uint(236));
+ }
+
+ let l = BigUint::from_uint(403469000 + 2352);
+ let u = BigUint::from_uint(403469000 + 3513);
+ do 1000.times {
+ let n: BigUint = rng.gen_biguint_below(&u);
+ assert!(n < u);
+
+ let n: BigUint = rng.gen_biguint_range(&l, &u);
+ assert!(n >= l);
+ assert!(n < u);
+ }
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_zero_rand_range() {
+ task_rng().gen_biguint_range(&BigUint::from_uint(54),
+ &BigUint::from_uint(54));
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_negative_rand_range() {
+ let mut rng = task_rng();
+ let l = BigUint::from_uint(2352);
+ let u = BigUint::from_uint(3513);
+ // Switching u and l should fail:
+ let _n: BigUint = rng.gen_biguint_range(&u, &l);
+ }
}
#[cfg(test)]
let _n: BigInt = rng.gen_bigint(137);
assert!(rng.gen_bigint(0).is_zero());
}
+
+ #[test]
+ fn test_rand_range() {
+ let mut rng = task_rng();
+
+ do 10.times {
+ assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
+ &BigInt::from_uint(237)),
+ BigInt::from_uint(236));
+ }
+
+ fn check(l: BigInt, u: BigInt) {
+ let mut rng = task_rng();
+ do 1000.times {
+ let n: BigInt = rng.gen_bigint_range(&l, &u);
+ assert!(n >= l);
+ assert!(n < u);
+ }
+ }
+ let l = BigInt::from_uint(403469000 + 2352);
+ let u = BigInt::from_uint(403469000 + 3513);
+ check( l.clone(), u.clone());
+ check(-l.clone(), u.clone());
+ check(-u.clone(), -l.clone());
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_zero_rand_range() {
+ task_rng().gen_bigint_range(&IntConvertible::from_int(54),
+ &IntConvertible::from_int(54));
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_negative_rand_range() {
+ let mut rng = task_rng();
+ let l = BigInt::from_uint(2352);
+ let u = BigInt::from_uint(3513);
+ // Switching u and l should fail:
+ let _n: BigInt = rng.gen_bigint_range(&u, &l);
+ }
}
#[cfg(test)]
#[unsafe_destructor]
impl<T> Drop for Rc<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
if self.ptr.is_not_null() {
(*self.ptr).count -= 1;
#[unsafe_destructor]
impl<T> Drop for RcMut<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
if self.ptr.is_not_null() {
(*self.ptr).count -= 1;
use std::{local_data, str, rt};
use std::unstable::finally::Finally;
-#[cfg(stage0)]
-pub mod rustrt {
- use std::libc::{c_char, c_int};
-
- extern {
- fn linenoise(prompt: *c_char) -> *c_char;
- fn linenoiseHistoryAdd(line: *c_char) -> c_int;
- fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
- fn linenoiseHistorySave(file: *c_char) -> c_int;
- fn linenoiseHistoryLoad(file: *c_char) -> c_int;
- fn linenoiseSetCompletionCallback(callback: *u8);
- fn linenoiseAddCompletion(completions: *(), line: *c_char);
-
- fn rust_take_linenoise_lock();
- fn rust_drop_linenoise_lock();
- }
-}
-
-#[cfg(not(stage0))]
pub mod rustrt {
use std::libc::{c_char, c_int};
pub type CompletionCb = @fn(~str, @fn(~str));
-static complete_key: local_data::Key<CompletionCb> = &local_data::Key;
+local_data_key!(complete_key: CompletionCb)
/// Bind to the main completion callback in the current task.
///
#[unsafe_destructor]
impl<T> Drop for TaskPool<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
for channel in self.channels.iter() {
channel.send(Quit);
}
let matches =
match groups::getopts(args_, optgroups()) {
Ok(m) => m,
- Err(f) => return Err(getopts::fail_str(f))
+ Err(f) => return Err(f.to_err_msg())
};
- if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
- if getopts::opt_present(&matches, "help") { usage(args[0], "help"); }
+ if matches.opt_present("h") { usage(args[0], "h"); }
+ if matches.opt_present("help") { usage(args[0], "help"); }
let filter =
if matches.free.len() > 0 {
None
};
- let run_ignored = getopts::opt_present(&matches, "ignored");
+ let run_ignored = matches.opt_present("ignored");
- let logfile = getopts::opt_maybe_str(&matches, "logfile");
+ let logfile = matches.opt_str("logfile");
let logfile = logfile.map_move(|s| Path(s));
- let run_benchmarks = getopts::opt_present(&matches, "bench");
+ let run_benchmarks = matches.opt_present("bench");
let run_tests = ! run_benchmarks ||
- getopts::opt_present(&matches, "test");
+ matches.opt_present("test");
- let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics");
+ let ratchet_metrics = matches.opt_str("ratchet-metrics");
let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
- let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
+ let ratchet_noise_percent = matches.opt_str("ratchet-noise-percent");
let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| from_str::<f64>(s).unwrap());
- let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
+ let save_metrics = matches.opt_str("save-metrics");
let save_metrics = save_metrics.map_move(|s| Path(s));
- let test_shard = getopts::opt_maybe_str(&matches, "test-shard");
+ let test_shard = matches.opt_str("test-shard");
let test_shard = opt_shard(test_shard);
let test_opts = TestOpts {
}
}
-// FIXME #4330: use &mut self here
#[unsafe_destructor]
impl Drop for Database {
- fn drop(&self) {
+ fn drop(&mut self) {
if self.db_dirty {
self.save();
}
impl Engine for LLVMJITData {}
impl Drop for LLVMJITData {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeExecutionEngine(self.ee);
llvm::LLVMContextDispose(self.llcx);
// The stage1 compiler won't work, but that doesn't really matter. TLS
// changed only very recently to allow storage of owned values.
- static engine_key: local_data::Key<~Engine> = &local_data::Key;
+ local_data_key!(engine_key: ~Engine)
fn set_engine(engine: ~Engine) {
local_data::set(engine_key, engine)
use std::os;
use std::vec;
use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
-use extra::getopts::{opt_present};
use extra::getopts;
use syntax::ast;
use syntax::abi;
matches: &getopts::Matches,
demitter: diagnostic::Emitter)
-> @session::options {
- let crate_type = if opt_present(matches, "lib") {
+ let crate_type = if matches.opt_present("lib") {
session::lib_crate
- } else if opt_present(matches, "bin") {
+ } else if matches.opt_present("bin") {
session::bin_crate
} else {
session::unknown_crate
};
- let parse_only = opt_present(matches, "parse-only");
- let no_trans = opt_present(matches, "no-trans");
+ let parse_only = matches.opt_present("parse-only");
+ let no_trans = matches.opt_present("no-trans");
let lint_levels = [lint::allow, lint::warn,
lint::deny, lint::forbid];
// to_ascii_move and to_str_move to not do a unnecessary copy.
let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().to_str_ascii();
- let flags = vec::append(getopts::opt_strs(matches, level_short),
- getopts::opt_strs(matches, level_name));
+ let flags = vec::append(matches.opt_strs(level_short),
+ matches.opt_strs(level_name));
for lint_name in flags.iter() {
let lint_name = lint_name.replace("-", "_");
match lint_dict.find_equiv(&lint_name) {
}
let mut debugging_opts = 0u;
- let debug_flags = getopts::opt_strs(matches, "Z");
+ let debug_flags = matches.opt_strs("Z");
let debug_map = session::debugging_opts_map();
for debug_flag in debug_flags.iter() {
let mut this_bit = 0u;
let output_type =
if parse_only || no_trans {
link::output_type_none
- } else if opt_present(matches, "S") &&
- opt_present(matches, "emit-llvm") {
+ } else if matches.opt_present("S") &&
+ matches.opt_present("emit-llvm") {
link::output_type_llvm_assembly
- } else if opt_present(matches, "S") {
+ } else if matches.opt_present("S") {
link::output_type_assembly
- } else if opt_present(matches, "c") {
+ } else if matches.opt_present("c") {
link::output_type_object
- } else if opt_present(matches, "emit-llvm") {
+ } else if matches.opt_present("emit-llvm") {
link::output_type_bitcode
} else { link::output_type_exe };
- let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
- let target = getopts::opt_maybe_str(matches, "target").unwrap_or(host_triple());
- let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or(~"generic");
- let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or(~"");
- let save_temps = getopts::opt_present(matches, "save-temps");
+ let sysroot_opt = matches.opt_str("sysroot").map_move(|m| @Path(m));
+ let target = matches.opt_str("target").unwrap_or(host_triple());
+ let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic");
+ let target_feature = matches.opt_str("target-feature").unwrap_or(~"");
+ let save_temps = matches.opt_present("save-temps");
let opt_level = {
if (debugging_opts & session::no_opt) != 0 {
No
- } else if opt_present(matches, "O") {
- if opt_present(matches, "opt-level") {
+ } else if matches.opt_present("O") {
+ if matches.opt_present("opt-level") {
early_error(demitter, ~"-O and --opt-level both provided");
}
Default
- } else if opt_present(matches, "opt-level") {
- match getopts::opt_str(matches, "opt-level") {
+ } else if matches.opt_present("opt-level") {
+ match matches.opt_str("opt-level").unwrap() {
~"0" => No,
~"1" => Less,
~"2" => Default,
let statik = debugging_opts & session::statik != 0;
- let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
- let linker = getopts::opt_maybe_str(matches, "linker");
- let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
+ let addl_lib_search_paths = matches.opt_strs("L").map(|s| Path(*s));
+ let linker = matches.opt_str("linker");
+ let linker_args = matches.opt_strs("link-args").flat_map( |a| {
a.split_iter(' ').map(|arg| arg.to_owned()).collect()
});
- let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
- let test = opt_present(matches, "test");
- let android_cross_path = getopts::opt_maybe_str(
- matches, "android-cross-path");
+ let cfg = parse_cfgspecs(matches.opt_strs("cfg"), demitter);
+ let test = matches.opt_present("test");
+ let android_cross_path = matches.opt_str("android-cross-path");
- let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
+ let custom_passes = match matches.opt_str("passes") {
None => ~[],
Some(s) => {
s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
}).collect()
}
};
- let llvm_args = match getopts::opt_maybe_str(matches, "llvm-args") {
+ let llvm_args = match matches.opt_str("llvm-args") {
None => ~[],
Some(s) => {
s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
use driver::driver::{build_session_options, optgroups};
use extra::getopts::groups::getopts;
- use extra::getopts;
use syntax::attr;
use syntax::diagnostic;
let matches =
&match getopts([~"--test"], optgroups()) {
Ok(m) => m,
- Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
+ Err(f) => fail!("test_switch_implies_cfg_test: %s", f.to_err_msg())
};
let sessopts = build_session_options(
@"rustc", matches, diagnostic::emit);
&match getopts([~"--test", ~"--cfg=test"], optgroups()) {
Ok(m) => m,
Err(f) => {
- fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
+ fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", f.to_err_msg());
}
};
let sessopts = build_session_options(
}
}
-#[cfg(stage0)]
-fn mk_test_module(cx: &TestCtxt) -> @ast::item {
-
- // Link to extra
- let view_items = ~[mk_std(cx)];
-
- // A constant vector of test descriptors.
- let tests = mk_tests(cx);
-
- // The synthesized main function which will call the console test runner
- // with our list of tests
- let ext_cx = cx.ext_cx;
- let mainfn = (quote_item!(
- pub fn main() {
- #[main];
- extra::test::test_main_static(::std::os::args(), TESTS);
- }
- )).unwrap();
-
- let testmod = ast::_mod {
- view_items: view_items,
- items: ~[mainfn, tests],
- };
- let item_ = ast::item_mod(testmod);
-
- // This attribute tells resolve to let us call unexported functions
- let resolve_unexported_attr =
- attr::mk_attr(attr::mk_word_item(@"!resolve_unexported"));
-
- let item = ast::item {
- ident: cx.sess.ident_of("__test"),
- attrs: ~[resolve_unexported_attr],
- id: ast::DUMMY_NODE_ID,
- node: item_,
- vis: ast::public,
- span: dummy_sp(),
- };
-
- debug!("Synthetic test module:\n%s\n",
- pprust::item_to_str(@item.clone(), cx.sess.intr()));
-
- return @item;
-}
-#[cfg(not(stage0))]
fn mk_test_module(cx: &TestCtxt) -> @ast::item {
// Link to extra
}
}
-#[cfg(stage0)]
-fn mk_tests(cx: &TestCtxt) -> @ast::item {
-
- let ext_cx = cx.ext_cx;
-
- // The vector of test_descs for this crate
- let test_descs = mk_test_descs(cx);
-
- (quote_item!(
- pub static TESTS : &'static [self::extra::test::TestDescAndFn] =
- $test_descs
- ;
- )).unwrap()
-}
-#[cfg(not(stage0))]
fn mk_tests(cx: &TestCtxt) -> @ast::item {
// The vector of test_descs for this crate
let test_descs = mk_test_descs(cx);
}
}
-#[cfg(stage0)]
-fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
- let span = test.span;
- let path = test.path.clone();
-
- let ext_cx = cx.ext_cx;
-
- debug!("encoding %s", ast_util::path_name_i(path));
-
- let name_lit: ast::lit =
- nospan(ast::lit_str(ast_util::path_name_i(path).to_managed()));
-
- let name_expr = @ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprLit(@name_lit),
- span: span
- };
-
- let fn_path = path_node_global(path);
-
- let fn_expr = @ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprPath(fn_path),
- span: span,
- };
-
- let t_expr = if test.bench {
- quote_expr!( self::extra::test::StaticBenchFn($fn_expr) )
- } else {
- quote_expr!( self::extra::test::StaticTestFn($fn_expr) )
- };
-
- let ignore_expr = if test.ignore {
- quote_expr!( true )
- } else {
- quote_expr!( false )
- };
-
- let fail_expr = if test.should_fail {
- quote_expr!( true )
- } else {
- quote_expr!( false )
- };
-
- let e = quote_expr!(
- self::extra::test::TestDescAndFn {
- desc: self::extra::test::TestDesc {
- name: self::extra::test::StaticTestName($name_expr),
- ignore: $ignore_expr,
- should_fail: $fail_expr
- },
- testfn: $t_expr,
- }
- );
- e
-}
-#[cfg(not(stage0))]
fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::Expr {
let span = test.span;
let path = test.path.clone();
}
impl Drop for target_data_res {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeTargetData(self.TD);
}
}
impl Drop for pass_manager_res {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposePassManager(self.PM);
}
}
impl Drop for object_file_res {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeObjectFile(self.ObjectFile);
}
}
impl Drop for section_iter_res {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeSectionIterator(self.SI);
}
reexports2: middle::resolve::ExportMap2,
item_symbols: &'self HashMap<ast::NodeId, ~str>,
discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+ non_inlineable_statics: &'self HashSet<ast::NodeId>,
link_meta: &'self LinkMeta,
cstore: @mut cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>,
reexports2: middle::resolve::ExportMap2,
item_symbols: &'self HashMap<ast::NodeId, ~str>,
discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+ non_inlineable_statics: &'self HashSet<ast::NodeId>,
link_meta: &'self LinkMeta,
cstore: &'self cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>,
encode_name(ecx, ebml_w, item.ident);
let elt = ast_map::path_pretty_name(item.ident, item.id as u64);
encode_path(ecx, ebml_w, path, elt);
- (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+ if !ecx.non_inlineable_statics.contains(&item.id) {
+ (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+ }
ebml_w.end_tag();
}
item_fn(_, purity, _, ref generics, _) => {
encode_inlined_item,
link_meta,
reachable,
+ non_inlineable_statics,
_
} = parms;
let type_abbrevs = @mut HashMap::new();
reexports2: reexports2,
item_symbols: item_symbols,
discrim_symbols: discrim_symbols,
+ non_inlineable_statics: non_inlineable_statics,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: encode_inlined_item,
use syntax::visit::Visitor;
use syntax::ast::*;
-use std::float;
use std::hashmap::{HashMap, HashSet};
//
lit_int(n, _) => const_int(n),
lit_uint(n, _) => const_uint(n),
lit_int_unsuffixed(n) => const_int(n),
- lit_float(n, _) => const_float(float::from_str(n).unwrap() as f64),
+ lit_float(n, _) => const_float(from_str::<float>(n).unwrap() as f64),
lit_float_unsuffixed(n) =>
- const_float(float::from_str(n).unwrap() as f64),
+ const_float(from_str::<float>(n).unwrap() as f64),
lit_nil => const_int(0i64),
lit_bool(b) => const_bool(b)
}
return single_result(datumblock.to_result(bcx));
}
lit(ConstLit(lit_id)) => {
- let llval = consts::get_const_val(bcx.ccx(), lit_id);
+ let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
return single_result(rslt(bcx, llval));
}
var(disr_val, repr) => {
return adt::trans_case(bcx, repr, disr_val);
}
range(l1, l2) => {
- return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
- rslt(bcx, consts::const_expr(ccx, l2)));
+ let (l1, _) = consts::const_expr(ccx, l1);
+ let (l2, _) = consts::const_expr(ccx, l2);
+ return range_result(rslt(bcx, l1), rslt(bcx, l2));
}
vec_len(n, vec_len_eq, _) => {
return single_result(rslt(bcx, C_int(ccx, n as int)));
pub use middle::trans::context::task_llcx;
-static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
+local_data_key!(task_local_insn_key: @~[&'static str])
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k));
#[unsafe_destructor]
impl Drop for _InsnCtxt {
- fn drop(&self) {
+ fn drop(&mut self) {
do local_data::modify(task_local_insn_key) |c| {
do c.map_move |ctx| {
let mut ctx = (*ctx).clone();
#[unsafe_destructor]
impl<'self> Drop for StatRecorder<'self> {
- fn drop(&self) {
+ fn drop(&mut self) {
if self.ccx.sess.trans_stats() {
let end = time::precise_time_ns();
let elapsed = ((end - self.start) / 1_000_000) as uint;
}
}
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
let llfn: ValueRef = do name.with_c_str |buf| {
unsafe {
return llfn;
}
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
}
-// Only use this if you are going to actually define the function. It's
-// not valid to simply declare a function as internal.
-pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
- let llfn = decl_cdecl_fn(llmod, name, ty);
- lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
- return llfn;
-}
-
+// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
match externs.find_equiv(&name) {
}
let f = decl_fn(llmod, name, cc, ty);
externs.insert(name.to_owned(), f);
- return f;
+ f
+}
+
+pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ match ccx.externs.find_equiv(&name) {
+ Some(n) => return *n,
+ None => ()
+ }
+ let f = decl_rust_fn(ccx, inputs, output, name);
+ ccx.externs.insert(name.to_owned(), f);
+ f
+}
+
+pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfty = type_of_rust_fn(ccx, inputs, output);
+ let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
+
+ match ty::get(output).sty {
+ // `~` pointer return values never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) => {
+ unsafe {
+ llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+ _ => ()
+ }
+
+ let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
+ let offset = if uses_outptr { 2 } else { 1 };
+
+ for (i, &arg_ty) in inputs.iter().enumerate() {
+ let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
+ match ty::get(arg_ty).sty {
+ // `~` pointer parameters never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+ unsafe {
+ llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+ _ => ()
+ }
+ }
+
+ // The out pointer will never alias with any other pointers, as the object only exists at a
+ // language level after the call. It can also be tagged with SRet to indicate that it is
+ // guaranteed to point to a usable block of memory for the type.
+ if uses_outptr {
+ unsafe {
+ let outptr = llvm::LLVMGetParam(llfn, 0);
+ llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
+ llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
+ }
+ }
+
+ llfn
+}
+
+pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+ name: &str) -> ValueRef {
+ let llfn = decl_rust_fn(ccx, inputs, output, name);
+ lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
+ llfn
}
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
C_null(Type::opaque_box(ccx).ptr_to())
}
-pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
- -> ValueRef {
+pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
let name = csearch::get_symbol(ccx.sess.cstore, did);
match ty::get(t).sty {
ty::ty_bare_fn(ref fn_ty) => {
- // Currently llvm_calling_convention triggers unimpl/bug on
- // Rust/RustIntrinsic, so those two are handled specially here.
- let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
- Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
+ match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+ Some(Rust) | Some(RustIntrinsic) => {
+ get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
+ }
Some(*) | None => {
let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
- c.unwrap_or(lib::llvm::CCallConv)
+ let cconv = c.unwrap_or(lib::llvm::CCallConv);
+ let llty = type_of_fn_from_ty(ccx, t);
+ get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
}
- };
- let llty = type_of_fn_from_ty(ccx, t);
- return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
+ }
}
- ty::ty_closure(_) => {
- let llty = type_of_fn_from_ty(ccx, t);
- return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
- lib::llvm::CCallConv, llty);
+ ty::ty_closure(ref f) => {
+ get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
}
_ => {
let llty = type_of(ccx, t);
- return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
+ get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
}
- };
+ }
}
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
llfn,
llargs,
normal_bcx.llbb,
- get_landing_pad(bcx));
+ get_landing_pad(bcx),
+ attributes);
return (llresult, normal_bcx);
} else {
unsafe {
// field of the fn_ctxt with
pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
self_arg: self_arg,
- args: &[ast::arg],
- arg_tys: &[ty::t])
+ args: &[ast::arg])
-> ~[ValueRef] {
let _icx = push_ctxt("create_llargs_for_fn_args");
// Return an array containing the ValueRefs that we get from
// llvm::LLVMGetParam for each argument.
do vec::from_fn(args.len()) |i| {
- let arg_n = cx.arg_pos(i);
- let arg_ty = arg_tys[i];
- let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
-
- match ty::get(arg_ty).sty {
- // `~` pointer parameters never alias because ownership is transferred
- ty::ty_uniq(*) |
- ty::ty_evec(_, ty::vstore_uniq) |
- ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
- unsafe {
- llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
- }
- }
- _ => ()
- }
-
- llarg
+ unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
}
}
// Set up arguments to the function.
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
- let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
- decl.inputs, arg_tys);
+ let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
// Set the fixed stack segment flag if necessary.
if attr::contains_name(attributes, "fixed_stack_segment") {
param_substs.repr(ccx.tcx));
let _icx = push_ctxt("trans_fn");
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
-
- match ty::get(output_type).sty {
- // `~` pointer return values never alias because ownership is transferred
- ty::ty_uniq(*) |
- ty::ty_evec(_, ty::vstore_uniq) => {
- unsafe {
- llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
- }
- }
- _ => ()
- }
-
trans_closure(ccx,
path.clone(),
decl,
let arg_tys = ty::ty_fn_args(ctor_ty);
- let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
+ let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = fcx.entry_bcx.unwrap();
node_id: ast::NodeId,
node_type: ty::t)
-> ValueRef {
- let llfty = type_of_fn_from_ty(ccx, node_type);
- register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+ let f = match ty::get(node_type).sty {
+ ty::ty_bare_fn(ref f) => {
+ assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+ f
+ }
+ _ => fail!("expected bare rust fn or an intrinsic")
+ };
+
+ let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
+ ccx.item_symbols.insert(node_id, sym);
+
+ // FIXME #4404 android JNI hacks
+ let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
+ (*ccx.sess.building_library &&
+ ccx.sess.targ_cfg.os == session::OsAndroid));
+ if is_entry {
+ create_entry_wrapper(ccx, sp, llfn);
+ }
+ llfn
}
+// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: @mut CrateContext,
sp: Span,
sym: ~str,
let et = ccx.sess.entry_type.unwrap();
match et {
session::EntryMain => {
- let llfn = create_main(ccx, main_llfn);
- create_entry_fn(ccx, llfn, true);
+ create_entry_fn(ccx, main_llfn, true);
}
session::EntryStart => create_entry_fn(ccx, main_llfn, false),
session::EntryNone => {} // Do nothing.
}
- fn create_main(ccx: @mut CrateContext, main_llfn: ValueRef) -> ValueRef {
- let nt = ty::mk_nil();
- let llfty = type_of_rust_fn(ccx, [], nt);
- let llfdecl = decl_fn(ccx.llmod, "_rust_main",
- lib::llvm::CCallConv, llfty);
-
- let fcx = new_fn_ctxt(ccx, ~[], llfdecl, nt, None);
-
- // the args vector built in create_entry_fn will need
- // be updated if this assertion starts to fail.
- assert!(!fcx.caller_expects_out_pointer);
-
- let bcx = fcx.entry_bcx.unwrap();
- // Call main.
- let llenvarg = unsafe {
- let env_arg = fcx.env_arg_pos();
- llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
- };
- let args = ~[llenvarg];
- Call(bcx, main_llfn, args, []);
-
- finish_fn(fcx, bcx);
- return llfdecl;
- }
-
fn create_entry_fn(ccx: @mut CrateContext,
rust_main: ValueRef,
use_start_lang_item: bool) {
let sym = exported_name(ccx, my_path, ty, i.attrs);
let v = match i.node {
- ast::item_static(_, m, expr) => {
+ ast::item_static(_, _, expr) => {
+ // If this static came from an external crate, then
+ // we need to get the symbol from csearch instead of
+ // using the current crate's name/version
+ // information in the hash of the symbol
+ debug!("making %s", sym);
+ let sym = match ccx.external_srcs.find(&i.id) {
+ Some(&did) => {
+ debug!("but found in other crate...");
+ csearch::get_symbol(ccx.sess.cstore, did)
+ }
+ None => sym
+ };
+
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
- let v = consts::const_expr(ccx, expr);
+ let (v, inlineable) = consts::const_expr(ccx, expr);
ccx.const_values.insert(id, v);
- exprt = (m == ast::MutMutable || i.vis == ast::public);
+ let mut inlineable = inlineable;
+ exprt = true;
unsafe {
let llty = llvm::LLVMTypeOf(v);
lib::llvm::SetUnnamedAddr(g, true);
lib::llvm::SetLinkage(g,
lib::llvm::InternalLinkage);
+
+ // This is a curious case where we must make
+ // all of these statics inlineable. If a
+ // global is tagged as
+ // address_insignificant, then LLVM won't
+ // coalesce globals unless they have an
+ // internal linkage type. This means that
+ // external crates cannot use this global.
+ // This is a problem for things like inner
+ // statics in generic functions, because the
+ // function will be inlined into another
+ // crate and then attempt to link to the
+ // static in the original crate, only to
+ // find that it's not there. On the other
+ // side of inlininig, the crates knows to
+ // not declare this static as
+ // available_externally (because it isn't)
+ inlineable = true;
}
+ if !inlineable {
+ debug!("%s not inlined", sym);
+ ccx.non_inlineable_statics.insert(id);
+ }
ccx.item_symbols.insert(i.id, sym);
g
}
foreign::register_foreign_item_fn(ccx, abis, &path, ni)
}
ast::foreign_item_static(*) => {
- let ident = token::ident_to_str(&ni.ident);
+ let ident = foreign::link_name(ccx, ni);
let g = do ident.with_c_str |buf| {
unsafe {
let ty = type_of(ccx, ty);
reexports2: cx.exp_map2,
item_symbols: item_symbols,
discrim_symbols: discrim_symbols,
+ non_inlineable_statics: &cx.non_inlineable_statics,
link_meta: link_meta,
cstore: cx.sess.cstore,
encode_inlined_item: ie,
Fn: ValueRef,
Args: &[ValueRef],
Then: BasicBlockRef,
- Catch: BasicBlockRef)
+ Catch: BasicBlockRef,
+ attributes: &[(uint, lib::llvm::Attribute)])
-> ValueRef {
if cx.unreachable {
return C_null(Type::i8());
debug!("Invoke(%s with arguments (%s))",
cx.val_to_str(Fn),
Args.map(|a| cx.val_to_str(*a)).connect(", "));
- B(cx).invoke(Fn, Args, Then, Catch)
-}
-
-pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
- Then: BasicBlockRef, Catch: BasicBlockRef) {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "FastInvoke");
- B(cx).fast_invoke(Fn, Args, Then, Catch);
+ B(cx).invoke(Fn, Args, Then, Catch, attributes)
}
pub fn Unreachable(cx: @mut Block) {
llfn: ValueRef,
args: &[ValueRef],
then: BasicBlockRef,
- catch: BasicBlockRef)
+ catch: BasicBlockRef,
+ attributes: &[(uint, lib::llvm::Attribute)])
-> ValueRef {
self.count_insn("invoke");
unsafe {
- llvm::LLVMBuildInvoke(self.llbuilder,
- llfn,
- vec::raw::to_ptr(args),
- args.len() as c_uint,
- then,
- catch,
- noname())
+ let v = llvm::LLVMBuildInvoke(self.llbuilder,
+ llfn,
+ vec::raw::to_ptr(args),
+ args.len() as c_uint,
+ then,
+ catch,
+ noname());
+ for &(idx, attr) in attributes.iter() {
+ llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+ }
+ v
}
}
- pub fn fast_invoke(&self,
- llfn: ValueRef,
- args: &[ValueRef],
- then: BasicBlockRef,
- catch: BasicBlockRef) {
- self.count_insn("fastinvoke");
- let v = self.invoke(llfn, args, then, catch);
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- }
-
pub fn unreachable(&self) {
self.count_insn("unreachable");
unsafe {
use back::abi;
use driver::session;
-use lib::llvm::ValueRef;
+use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
use lib::llvm::llvm;
use metadata::csearch;
use middle::trans::base;
_ => {}
}
+ // A function pointer is called without the declaration available, so we have to apply
+ // any attributes with ABI implications directly to the call instruction. Right now, the
+ // only attribute we need to worry about is `sret`.
+ let mut attrs = ~[];
+ if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+ attrs.push((1, StructRetAttribute));
+ }
+
+ // The `noalias` attribute on the return value is useful to a function ptr caller.
+ match ty::get(ret_ty).sty {
+ // `~` pointer return values never alias because ownership is transferred
+ ty::ty_uniq(*) |
+ ty::ty_evec(_, ty::vstore_uniq) => {
+ attrs.push((0, NoAliasAttribute));
+ }
+ _ => ()
+ }
+
// Invoke the actual rust fn and update bcx/llresult.
- let (llret, b) = base::invoke(bcx, llfn, llargs, []);
+ let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
bcx = b;
llresult = llret;
let ccx = bcx.ccx();
let fty = node_id_type(bcx, outer_id);
-
- let llfnty = type_of_fn_from_ty(ccx, fty);
+ let f = match ty::get(fty).sty {
+ ty::ty_closure(ref f) => f,
+ _ => fail!("expected closure")
+ };
let sub_path = vec::append_one(bcx.fcx.path.clone(),
path_name(special_idents::anon));
let s = mangle_internal_name_by_path_and_seq(ccx,
sub_path.clone(),
"expr_fn");
- let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
+ let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
// set an inline hint for all closures
set_inline_hint(llfn);
}
impl Drop for BuilderRef_res {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
llvm::LLVMDisposeBuilder(self.B);
}
}
pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr])
- -> (ValueRef, ValueRef, Type) {
+ -> (ValueRef, ValueRef, Type, bool) {
unsafe {
let vec_ty = ty::expr_ty(cx.tcx, e);
let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
let llunitty = type_of::type_of(cx, unit_ty);
let unit_sz = machine::llsize_of(cx, llunitty);
let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
- let vs = es.map(|e| const_expr(cx, *e));
+ let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
// If the vector contains enums, an LLVM array won't work.
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs)
} else {
C_array(llunitty, vs)
};
- return (v, sz, llunitty);
+ return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b));
}
}
}
}
-pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef {
+pub fn get_const_val(cx: @mut CrateContext,
+ mut def_id: ast::DefId) -> (ValueRef, bool) {
let contains_key = cx.const_values.contains_key(&def_id.node);
if !ast_util::is_local(def_id) || !contains_key {
if !ast_util::is_local(def_id) {
_ => cx.tcx.sess.bug("expected a const to be an item")
}
}
- cx.const_values.get_copy(&def_id.node)
+ (cx.const_values.get_copy(&def_id.node),
+ !cx.non_inlineable_statics.contains(&def_id.node))
}
-pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
- let mut llconst = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> (ValueRef, bool) {
+ let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+ let mut llconst = llconst;
+ let mut inlineable = inlineable;
let ety = ty::expr_ty(cx.tcx, e);
let adjustment = cx.tcx.adjustments.find_copy(&e.id);
match adjustment {
// Don't copy data to do a deref+ref.
let llptr = match maybe_ptr {
Some(ptr) => ptr,
- None => const_addr_of(cx, llconst)
+ None => {
+ inlineable = false;
+ const_addr_of(cx, llconst)
+ }
};
match *autoref {
ty::AutoUnsafe(m) |
e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
csize, tsize));
}
- llconst
+ (llconst, inlineable)
}
-fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
+// the bool returned is whether this expression can be inlined into other crates
+// if it's assigned to a static.
+fn const_expr_unadjusted(cx: @mut CrateContext,
+ e: &ast::Expr) -> (ValueRef, bool) {
+ fn map_list(cx: @mut CrateContext,
+ exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
+ exprs.iter().map(|&e| const_expr(cx, e))
+ .fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
+ (vec::append_one(L, val), all_inlineable && inlineable)
+ })
+ }
unsafe {
let _icx = push_ctxt("const_expr");
return match e.node {
- ast::ExprLit(lit) => consts::const_lit(cx, e, *lit),
+ ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
ast::ExprBinary(_, b, e1, e2) => {
- let te1 = const_expr(cx, e1);
- let te2 = const_expr(cx, e2);
+ let (te1, _) = const_expr(cx, e1);
+ let (te2, _) = const_expr(cx, e2);
let te2 = base::cast_shift_const_rhs(b, te1, te2);
let ty = ty::expr_ty(cx.tcx, e1);
let is_float = ty::type_is_fp(ty);
let signed = ty::type_is_signed(ty);
- return match b {
+ return (match b {
ast::BiAdd => {
if is_float { llvm::LLVMConstFAdd(te1, te2) }
else { llvm::LLVMConstAdd(te1, te2) }
else { ConstICmp(IntUGT, te1, te2) }
}
},
- };
+ }, true)
},
ast::ExprUnary(_, u, e) => {
- let te = const_expr(cx, e);
+ let (te, _) = const_expr(cx, e);
let ty = ty::expr_ty(cx.tcx, e);
let is_float = ty::type_is_fp(ty);
- return match u {
+ return (match u {
ast::UnBox(_) |
ast::UnUniq |
ast::UnDeref => {
if is_float { llvm::LLVMConstFNeg(te) }
else { llvm::LLVMConstNeg(te) }
}
- }
+ }, true)
}
ast::ExprField(base, field, _) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
let brepr = adt::represent_type(cx, bt);
- let bv = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base);
do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
- adt::const_get_field(cx, brepr, bv, discr, ix)
+ (adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
}
}
ast::ExprIndex(_, base, index) => {
let bt = ty::expr_ty_adjusted(cx.tcx, base);
- let bv = const_expr(cx, base);
+ let (bv, inlineable) = const_expr(cx, base);
let iv = match const_eval::eval_const_expr(cx.tcx, index) {
const_eval::const_int(i) => i as u64,
const_eval::const_uint(u) => u,
cx.sess.span_err(e.span,
"const index-expr is out of bounds");
}
- const_get_elt(cx, arr, [iv as c_uint])
+ (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
}
ast::ExprCast(base, _) => {
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
let basety = ty::expr_ty(cx.tcx, base);
- let v = const_expr(cx, base);
- match (expr::cast_type_kind(basety),
- expr::cast_type_kind(ety)) {
+ let (v, inlineable) = const_expr(cx, base);
+ return (match (expr::cast_type_kind(basety),
+ expr::cast_type_kind(ety)) {
(expr::cast_integral, expr::cast_integral) => {
let s = ty::type_is_signed(basety) as Bool;
cx.sess.impossible_case(e.span,
"bad combination of types for cast")
}
- }
+ }, inlineable)
}
ast::ExprAddrOf(ast::MutImmutable, sub) => {
- let e = const_expr(cx, sub);
- const_addr_of(cx, e)
+ let (e, _) = const_expr(cx, sub);
+ (const_addr_of(cx, e), false)
}
ast::ExprTup(ref es) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let vals = es.map(|&e| const_expr(cx, e));
- adt::trans_const(cx, repr, 0, vals)
+ let (vals, inlineable) = map_list(cx, *es);
+ (adt::trans_const(cx, repr, 0, vals), inlineable)
}
ast::ExprStruct(_, ref fs, ref base_opt) => {
let ety = ty::expr_ty(cx.tcx, e);
do expr::with_field_tys(tcx, ety, Some(e.id))
|discr, field_tys| {
- let cs: ~[ValueRef] = field_tys.iter().enumerate()
+ let cs = field_tys.iter().enumerate()
.map(|(ix, &field_ty)| {
match fs.iter().find(|f| field_ty.ident.name == f.ident.name) {
Some(f) => const_expr(cx, (*f).expr),
None => {
match base_val {
- Some(bv) => adt::const_get_field(cx, repr, bv, discr, ix),
+ Some((bv, inlineable)) => {
+ (adt::const_get_field(cx, repr, bv, discr, ix),
+ inlineable)
+ }
None => cx.tcx.sess.span_bug(e.span, "missing struct field")
}
}
}
- }).collect();
- adt::trans_const(cx, repr, discr, cs)
+ }).to_owned_vec();
+ let (cs, inlineable) = vec::unzip(cs.move_iter());
+ (adt::trans_const(cx, repr, discr, cs),
+ inlineable.iter().fold(true, |a, &b| a && b))
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (v, _, _) = const_vec(cx, e, *es);
- v
+ let (v, _, _, inlineable) = const_vec(cx, e, *es);
+ (v, inlineable)
}
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
match sub.node {
}
}
ast::ExprVec(ref es, ast::MutImmutable) => {
- let (cv, sz, llunitty) = const_vec(cx, e, *es);
+ let (cv, sz, llunitty, _) = const_vec(cx, e, *es);
let llty = val_ty(cv);
let gv = do "const".with_c_str |name| {
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
llvm::LLVMSetGlobalConstant(gv, True);
SetLinkage(gv, PrivateLinkage);
let p = const_ptrcast(cx, gv, llunitty);
- C_struct([p, sz])
+ (C_struct([p, sz]), false)
}
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
}
const_eval::const_uint(i) => i as uint,
_ => cx.sess.span_bug(count.span, "count must be integral const expression.")
};
- let vs = vec::from_elem(n, const_expr(cx, elem));
+ let vs = vec::from_elem(n, const_expr(cx, elem).first());
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(vs)
} else {
C_array(llunitty, vs)
};
- v
+ (v, true)
}
ast::ExprPath(ref pth) => {
// Assert that there are no type parameters in this path.
Some(&ast::DefFn(def_id, _purity)) => {
if !ast_util::is_local(def_id) {
let ty = csearch::get_type(cx.tcx, def_id).ty;
- base::trans_external_path(cx, def_id, ty)
+ (base::trans_external_path(cx, def_id, ty), true)
} else {
assert!(ast_util::is_local(def_id));
- base::get_item_val(cx, def_id.node)
+ (base::get_item_val(cx, def_id.node), true)
}
}
Some(&ast::DefStatic(def_id, false)) => {
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- adt::trans_const(cx, repr, vinfo.disr_val, [])
+ (adt::trans_const(cx, repr, vinfo.disr_val, []), true)
}
Some(&ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let llty = type_of::type_of(cx, ety);
- C_null(llty)
+ (C_null(llty), true)
}
_ => {
cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
Some(&ast::DefStruct(_)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
- let arg_vals = args.map(|a| const_expr(cx, *a));
- adt::trans_const(cx, repr, 0, arg_vals)
+ let (arg_vals, inlineable) = map_list(cx, *args);
+ (adt::trans_const(cx, repr, 0, arg_vals), inlineable)
}
Some(&ast::DefVariant(enum_did, variant_did, _)) => {
let ety = ty::expr_ty(cx.tcx, e);
let vinfo = ty::enum_variant_with_id(cx.tcx,
enum_did,
variant_did);
- let arg_vals = args.map(|a| const_expr(cx, *a));
- adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
+ let (arg_vals, inlineable) = map_list(cx, *args);
+ (adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
+ inlineable)
}
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
}
}
- ast::ExprParen(e) => { return const_expr(cx, e); }
+ ast::ExprParen(e) => { const_expr(cx, e) }
_ => cx.sess.span_bug(e.span,
"bad constant expression type in consts::const_expr")
};
finished_tydescs: bool,
// Track mapping of external ids to local items imported for inlining
external: HashMap<ast::DefId, Option<ast::NodeId>>,
+ // Backwards version of the `external` map (inlined items to where they
+ // came from)
+ external_srcs: HashMap<ast::NodeId, ast::DefId>,
+ // A set of static items which cannot be inlined into other crates. This
+ // will pevent in ii_item() structures from being encoded into the metadata
+ // that is generated
+ non_inlineable_statics: HashSet<ast::NodeId>,
// Cache instances of monomorphized functions
monomorphized: HashMap<mono_id, ValueRef>,
monomorphizing: HashMap<ast::DefId, uint>,
tydescs: HashMap::new(),
finished_tydescs: false,
external: HashMap::new(),
+ external_srcs: HashMap::new(),
+ non_inlineable_statics: HashSet::new(),
monomorphized: HashMap::new(),
monomorphizing: HashMap::new(),
type_use_cache: HashMap::new(),
#[unsafe_destructor]
impl Drop for CrateContext {
- fn drop(&self) {
+ fn drop(&mut self) {
unset_task_llcx();
}
}
-static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
+local_data_key!(task_local_llcx_key: @ContextRef)
pub fn task_llcx() -> ContextRef {
let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
use back::abi;
use back::link;
-use lib::llvm::{ValueRef, llvm, SetLinkage, ExternalLinkage, False};
+use lib::llvm::{ValueRef, llvm, SetLinkage, False};
use lib;
use metadata::csearch;
use middle::trans::_match;
use middle::trans::debuginfo;
use middle::trans::machine;
use middle::trans::meth;
+use middle::trans::inline;
use middle::trans::tvec;
use middle::trans::type_of;
use middle::ty::struct_fields;
ast::DefStatic(did, _) => {
let const_ty = expr_ty(bcx, ref_expr);
+ fn get_did(ccx: @mut CrateContext, did: ast::DefId)
+ -> ast::DefId {
+ if did.crate != ast::LOCAL_CRATE {
+ inline::maybe_instantiate_inline(ccx, did)
+ } else {
+ did
+ }
+ }
+
fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
-> ValueRef {
// For external constants, we don't inline.
llty.to_ref(),
buf)
};
- SetLinkage(llval, ExternalLinkage);
let extern_const_values = &mut bcx.ccx().extern_const_values;
extern_const_values.insert(did, llval);
llval
}
}
+ let did = get_did(bcx.ccx(), did);
let val = get_val(bcx, did, const_ty);
DatumBlock {
bcx: bcx,
use middle::trans::build::*;
use middle::trans::builder::noname;
use middle::trans::common::*;
-use middle::trans::llrepr::LlvmRepr;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::ty;
}
};
+ // A function pointer is called without the declaration available, so we have to apply
+ // any attributes with ABI implications directly to the call instruction. Right now, the
+ // only attribute we need to worry about is `sret`.
let attrs;
if fn_type.sret {
attrs = &[(1, StructRetAttribute)];
special_idents::clownshoe_abi
)));
- // Compute the LLVM type that the function would have if it
- // were just a normal Rust function. This will be the type of
- // the wrappee fn.
- let llty = match ty::get(t).sty {
+ // Compute the type that the function would have if it were just a
+ // normal Rust function. This will be the type of the wrappee fn.
+ let f = match ty::get(t).sty {
ty::ty_bare_fn(ref f) => {
assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
- type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
+ f
}
_ => {
ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
}
};
- debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
+ debug!("build_rust_fn: path=%s id=%? t=%s",
path.repr(tcx),
id,
- t.repr(tcx),
- llty.llrepr(ccx));
+ t.repr(tcx));
- let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+ let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
base::trans_fn(ccx,
(*path).clone(),
decl,
// Rust expects to use an outpointer. If the foreign fn
// also uses an outpointer, we can reuse it, but the types
// may vary, so cast first to the Rust type. If the
- // foriegn fn does NOT use an outpointer, we will have to
+ // foreign fn does NOT use an outpointer, we will have to
// alloca some scratch space on the stack.
match foreign_outptr {
Some(llforeign_outptr) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+use lib::llvm::{AvailableExternallyLinkage, SetLinkage};
use metadata::csearch;
use middle::astencode;
use middle::trans::base::{push_ctxt, impl_self, no_self};
use syntax::ast;
use syntax::ast_map::path_name;
use syntax::ast_util::local_def;
+use syntax::attr;
pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
-> ast::DefId {
}
csearch::found(ast::ii_item(item)) => {
ccx.external.insert(fn_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, fn_id);
ccx.stats.n_inlines += 1;
trans_item(ccx, item);
+
+ // We're bringing an external global into this crate, but we don't
+ // want to create two copies of the global. If we do this, then if
+ // you take the address of the global in two separate crates you get
+ // two different addresses. This is bad for things like conditions,
+ // but it could possibly have other adverse side effects. We still
+ // want to achieve the optimizations related to this global,
+ // however, so we use the available_externally linkage which llvm
+ // provides
+ match item.node {
+ ast::item_static(*) => {
+ let g = get_item_val(ccx, item.id);
+ // see the comment in get_item_val() as to why this check is
+ // performed here.
+ if !attr::contains_name(item.attrs,
+ "address_insignificant") {
+ SetLinkage(g, AvailableExternallyLinkage);
+ }
+ }
+ _ => {}
+ }
+
local_def(item.id)
}
csearch::found(ast::ii_foreign(item)) => {
ccx.external.insert(fn_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, fn_id);
local_def(item.id)
}
csearch::found_parent(parent_id, ast::ii_item(item)) => {
ccx.external.insert(parent_id, Some(item.id));
+ ccx.external_srcs.insert(item.id, parent_id);
let mut my_id = 0;
match item.node {
ast::item_enum(_, _) => {
csearch::found(ast::ii_method(impl_did, is_provided, mth)) => {
ccx.stats.n_inlines += 1;
ccx.external.insert(fn_id, Some(mth.id));
+ ccx.external_srcs.insert(mth.id, fn_id);
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so don't.
if is_provided { return local_def(mth.id); }
use lib::llvm::ValueRef;
use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
use middle::trans::base::{trans_enum_variant,push_ctxt};
-use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
+use middle::trans::base::{trans_fn, decl_internal_rust_fn};
use middle::trans::base::{get_item_val, no_self};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
use middle::trans::machine;
use middle::trans::meth;
-use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
use middle::trans::intrinsic;
ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
}
};
- let llfty = type_of_fn_from_ty(ccx, mono_ty);
+
+ let f = match ty::get(mono_ty).sty {
+ ty::ty_bare_fn(ref f) => {
+ assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+ f
+ }
+ _ => fail!("expected bare rust fn or an intrinsic")
+ };
ccx.stats.n_monos += 1;
debug!("monomorphize_fn mangled to %s", s);
let mk_lldecl = || {
- let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
+ let lldecl = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
ccx.monomorphized.insert(hash_id, lldecl);
lldecl
};
sub_path,
"get_disr");
- let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
- let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
+ let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
let fcx = new_fn_ctxt(ccx,
~[],
llfdecl,
use std::str;
use std::task;
use std::vec;
-use extra::getopts::{groups, opt_present};
+use extra::getopts::groups;
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic;
pub fn usage(argv0: &str) {
let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
- printfln!("%s\
+ printfln!("%s\n\
Additional help:
-W help Print 'lint' options and default settings
-Z help Print internal options for debugging rustc\n",
&match getopts::groups::getopts(args, optgroups()) {
Ok(m) => m,
Err(f) => {
- early_error(demitter, getopts::fail_str(f));
+ early_error(demitter, f.to_err_msg());
}
};
- if opt_present(matches, "h") || opt_present(matches, "help") {
+ if matches.opt_present("h") || matches.opt_present("help") {
usage(binary);
return;
}
// Display the available lint options if "-W help" or only "-W" is given.
- let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
- getopts::opt_strs(matches, "warn"));
+ let lint_flags = vec::append(matches.opt_strs("W"),
+ matches.opt_strs("warn"));
let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
- (opt_present(matches, "W") && lint_flags.is_empty());
+ (matches.opt_present("W") && lint_flags.is_empty());
if show_lint_options {
describe_warnings();
return;
}
- let r = getopts::opt_strs(matches, "Z");
+ let r = matches.opt_strs("Z");
if r.iter().any(|x| x == &~"help") {
describe_debug_flags();
return;
}
- if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
+ if matches.opt_str("passes") == Some(~"list") {
unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
return;
}
- if opt_present(matches, "v") || opt_present(matches, "version") {
+ if matches.opt_present("v") || matches.opt_present("version") {
version(binary);
return;
}
let sopts = build_session_options(binary, matches, demitter);
let sess = build_session(sopts, demitter);
- let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
- let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
+ let odir = matches.opt_str("out-dir").map_move(|o| Path(o));
+ let ofile = matches.opt_str("o").map_move(|o| Path(o));
let cfg = build_configuration(sess);
- let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
+ let pretty = do matches.opt_default("pretty", "normal").map_move |a| {
parse_pretty(sess, a)
};
match pretty {
}
None::<PpMode> => {/* continue */ }
}
- let ls = opt_present(matches, "ls");
+ let ls = matches.opt_present("ls");
if ls {
match input {
file_input(ref ifile) => {
}
impl Drop for finally {
- fn drop(&self) { self.ch.send(done); }
+ fn drop(&mut self) { self.ch.send(done); }
}
let _finally = finally { ch: ch };
}
impl Drop for _indenter {
- fn drop(&self) { debug!("<<"); }
+ fn drop(&mut self) { debug!("<<"); }
}
pub fn _indenter(_i: ()) -> _indenter {
}
}
Err(f) => {
- Err(getopts::fail_str(f))
+ Err(f.to_err_msg())
}
}
}
let config = default_config(input_crate);
let result = result::Ok(config);
let result = do result.and_then |config| {
- let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
+ let output_dir = matches.opt_str(opt_output_dir());
let output_dir = output_dir.map_move(|s| Path(s));
result::Ok(Config {
output_dir: output_dir.unwrap_or(config.output_dir.clone()),
})
};
let result = do result.and_then |config| {
- let output_format = getopts::opt_maybe_str(matches, opt_output_format());
+ let output_format = matches.opt_str(opt_output_format());
do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
do parse_output_format(output_format).and_then |output_format| {
result::Ok(Config {
};
let result = do result.and_then |config| {
let output_style =
- getopts::opt_maybe_str(matches, opt_output_style());
+ matches.opt_str(opt_output_style());
do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
do parse_output_style(output_style).and_then |output_style| {
result::Ok(Config {
};
let process_output = Cell::new(process_output);
let result = do result.and_then |config| {
- let pandoc_cmd = getopts::opt_maybe_str(matches, opt_pandoc_cmd());
+ let pandoc_cmd = matches.opt_str(opt_pandoc_cmd());
let pandoc_cmd = maybe_find_pandoc(
&config, pandoc_cmd, process_output.take());
do pandoc_cmd.and_then |pandoc_cmd| {
}
impl Drop for Bored {
- fn drop(&self) { }
+ fn drop(&mut self) { }
}
/**
}
type LocalCache = @mut HashMap<~str, @~[u8]>;
-static tls_key: local_data::Key<LocalCache> = &local_data::Key;
+local_data_key!(tls_key: LocalCache)
impl Program {
pub fn new() -> Program {
use crate::*;
use package_id::*;
use package_source::*;
+use target::*;
use version::Version;
use workcache_support::*;
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
lib: Path) {
let cx = default_context(sysroot);
- let subroot = root.clone();
- let subversion = version.clone();
- let sublib = lib.clone();
- do cx.workcache_context.with_prep(name) |prep| {
- let pkg_src = PkgSrc {
- workspace: subroot.clone(),
- start_dir: subroot.push("src").push(name),
- id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
- libs: ~[mk_crate(sublib.clone())],
+ let pkg_src = PkgSrc {
+ workspace: root.clone(),
+ start_dir: root.push("src").push(name),
+ id: PkgId{ version: version, ..PkgId::new(name)},
+ // n.b. This assumes the package only has one crate
+ libs: ~[mk_crate(lib)],
mains: ~[],
tests: ~[],
benchs: ~[]
};
- pkg_src.declare_inputs(prep);
- let subcx = cx.clone();
- let subsrc = pkg_src.clone();
- do prep.exec |exec| {
- subsrc.build(exec, &subcx.clone(), ~[]);
- }
- };
+ pkg_src.build(&cx, ~[]);
}
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
main: Path) {
let cx = default_context(sysroot);
- let subroot = root.clone();
- let submain = main.clone();
- do cx.workcache_context.with_prep(name) |prep| {
- let pkg_src = PkgSrc {
- workspace: subroot.clone(),
- start_dir: subroot.push("src").push(name),
- id: PkgId{ version: version.clone(), ..PkgId::new(name)},
- libs: ~[],
- mains: ~[mk_crate(submain.clone())],
- tests: ~[],
- benchs: ~[]
- };
- pkg_src.declare_inputs(prep);
- let subsrc = pkg_src.clone();
- let subcx = cx.clone();
- do prep.exec |exec| {
- subsrc.clone().build(exec, &subcx.clone(), ~[]);
- }
- }
+ let pkg_src = PkgSrc {
+ workspace: root.clone(),
+ start_dir: root.push("src").push(name),
+ id: PkgId{ version: version, ..PkgId::new(name)},
+ libs: ~[],
+ // n.b. This assumes the package only has one crate
+ mains: ~[mk_crate(main)],
+ tests: ~[],
+ benchs: ~[]
+ };
+
+ pkg_src.build(&cx, ~[]);
}
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
let cx = default_context(sysroot);
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
- cx.install(PkgSrc::new(workspace, false, pkgid));
+ cx.install(PkgSrc::new(workspace, false, pkgid), &Everything);
}
fn mk_crate(p: Path) -> Crate {
--- /dev/null
+// 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.
+
+pub static copy_failed_code: int = 65;
}
}
+ // This is the workcache function name for the *installed*
+ // binaries for this package (as opposed to the built ones,
+ // which are per-crate).
+ pub fn install_tag(&self) -> ~str {
+ fmt!("install(%s)", self.to_str())
+ }
}
struct Prefixes {
use util::compile_crate;
use workspace::is_workspace;
use workcache_support;
+use workcache_support::crate_tag;
use extra::workcache;
// An enumeration of the unpacked source of a package workspace.
p.filestem().map_default(false, |p| { p == &self.id.short_name.as_slice() })
}
- fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
+ pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
assert!(p.components.len() > prefix);
let mut sub = Path("");
for c in p.components.slice(prefix, p.components.len()).iter() {
fn build_crates(&self,
ctx: &BuildContext,
- exec: &mut workcache::Exec,
destination_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
let path_str = path.to_str();
let cfgs = crate.cfgs + cfgs;
- let result =
- // compile_crate should return the path of the output artifact
- compile_crate(ctx,
- exec,
- &self.id,
- &path,
- destination_dir,
- crate.flags,
- cfgs,
- false,
- what).to_str();
- debug!("Result of compiling %s was %s", path_str, result);
+ do ctx.workcache_context.with_prep(crate_tag(&path)) |prep| {
+ debug!("Building crate %s, declaring it as an input", path.to_str());
+ prep.declare_input("file", path.to_str(),
+ workcache_support::digest_file_with_date(&path));
+ let subpath = path.clone();
+ let subcfgs = cfgs.clone();
+ let subpath_str = path_str.clone();
+ let subcx = ctx.clone();
+ let id = self.id.clone();
+ let sub_dir = destination_dir.clone();
+ let sub_flags = crate.flags.clone();
+ do prep.exec |exec| {
+ let result = compile_crate(&subcx,
+ exec,
+ &id,
+ &subpath,
+ &sub_dir,
+ sub_flags,
+ subcfgs,
+ false,
+ what).to_str();
+ debug!("Result of compiling %s was %s", subpath_str, result);
+ result
+ }
+ };
}
}
/// Declare all the crate files in the package source as inputs
+ /// (to the package)
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
let to_do = ~[self.libs.clone(), self.mains.clone(),
self.tests.clone(), self.benchs.clone()];
+ debug!("In declare inputs, self = %s", self.to_str());
for cs in to_do.iter() {
for c in cs.iter() {
let path = self.start_dir.push_rel(&c.file).normalize();
// It would be better if build returned a Path, but then Path would have to derive
// Encodable.
pub fn build(&self,
- exec: &mut workcache::Exec,
build_context: &BuildContext,
cfgs: ~[~str]) -> ~str {
use conditions::not_a_workspace::cond;
let benchs = self.benchs.clone();
debug!("Building libs in %s, destination = %s",
destination_workspace.to_str(), destination_workspace.to_str());
- self.build_crates(build_context, exec, &destination_workspace, libs, cfgs, Lib);
+ self.build_crates(build_context, &destination_workspace, libs, cfgs, Lib);
debug!("Building mains");
- self.build_crates(build_context, exec, &destination_workspace, mains, cfgs, Main);
+ self.build_crates(build_context, &destination_workspace, mains, cfgs, Main);
debug!("Building tests");
- self.build_crates(build_context, exec, &destination_workspace, tests, cfgs, Test);
+ self.build_crates(build_context, &destination_workspace, tests, cfgs, Test);
debug!("Building benches");
- self.build_crates(build_context, exec, &destination_workspace, benchs, cfgs, Bench);
+ self.build_crates(build_context, &destination_workspace, benchs, cfgs, Bench);
destination_workspace.to_str()
}
+
+ /// Debugging
+ pub fn dump_crates(&self) {
+ let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
+ for crate_set in crate_sets.iter() {
+ for c in crate_set.iter() {
+ debug!("Built crate: %s", c.file.to_str())
+ }
+ }
+ }
}
extern mod rustc;
extern mod syntax;
-use std::{io, os, result, run, str};
+use std::{io, os, result, run, str, task};
pub use std::path::Path;
use extra::workcache;
-use extra::arc::RWArc;
use rustc::driver::{driver, session};
use rustc::metadata::filesearch;
use rustc::metadata::filesearch::rust_path;
LLVMAssemble, LLVMCompileBitcode};
use package_id::PkgId;
use package_source::PkgSrc;
-use workcache_support::{discover_outputs, digest_only_date};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+// use workcache_support::{discover_outputs, digest_only_date};
+use workcache_support::digest_only_date;
+use exit_codes::copy_failed_code;
pub mod api;
mod conditions;
mod context;
mod crate;
+mod exit_codes;
mod installed_packages;
mod messages;
mod package_id;
pub trait CtxMethods {
fn run(&self, cmd: &str, args: ~[~str]);
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
- fn build_from_src(&self, pkg_src: PkgSrc);
/// Returns the destination workspace
- fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
+ fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
fn clean(&self, workspace: &Path, id: &PkgId);
fn info(&self);
/// Returns a pair. First component is a list of installed paths,
/// second is a list of declared and discovered inputs
- fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
+ fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
/// Returns a list of installed files
fn install_no_build(&self,
source_workspace: &Path,
target_workspace: &Path,
- id: &PkgId) -> ~[Path];
+ id: &PkgId) -> ~[~str];
fn prefer(&self, _id: &str, _vers: Option<~str>);
fn test(&self);
fn uninstall(&self, _id: &str, _vers: Option<~str>);
fn unprefer(&self, _id: &str, _vers: Option<~str>);
+ fn init(&self);
}
impl CtxMethods for BuildContext {
- fn build_from_src(&self, pkg_src: PkgSrc) {
- let tag = pkg_src.id.to_str();
- debug!("package source = %s", pkg_src.to_str());
- do self.workcache_context.with_prep(tag) |prep| {
- let subsrc = pkg_src.clone();
- let subself = self.clone();
- declare_package_script_dependency(prep, &subsrc);
- pkg_src.declare_inputs(prep);
- do prep.exec |exec| {
- subself.build(exec, subsrc.clone());
- }
- }
- }
-
fn run(&self, cmd: &str, args: ~[~str]) {
match cmd {
"build" => {
None if self.context.use_rust_path_hack => {
let cwd = os::getcwd();
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
- self.build_from_src(PkgSrc::new(cwd, true, pkgid));
+ let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+ self.build(&mut pkg_src, &Everything);
}
None => { usage::build(); return; }
Some((ws, pkgid)) => {
- self.build_from_src(PkgSrc::new(ws, false, pkgid));
+ let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+ self.build(&mut pkg_src, &Everything);
}
}
}
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
debug!("found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());
- let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
- self.build_from_src(pkg_src);
+ let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+ self.build(&mut pkg_src, &Everything);
true
};
}
let cwd = os::getcwd();
let inferred_pkgid =
PkgId::new(cwd.components[cwd.components.len() - 1]);
- self.install(PkgSrc::new(cwd, true, inferred_pkgid));
+ self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
}
None => { usage::install(); return; }
Some((ws, pkgid)) => {
let pkg_src = PkgSrc::new(ws, false, pkgid);
- self.install(pkg_src);
+ self.install(pkg_src, &Everything);
}
}
}
let rp = rust_path();
assert!(!rp.is_empty());
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
- self.install(src);
+ self.install(src, &Everything);
}
else {
for workspace in workspaces.iter() {
let src = PkgSrc::new(workspace.clone(),
self.context.use_rust_path_hack,
pkgid.clone());
- self.install(src);
+ self.install(src, &Everything);
};
}
}
"test" => {
self.test();
}
+ "init" => {
+ if args.len() != 0 {
+ return usage::init();
+ } else {
+ self.init();
+ }
+ }
"uninstall" => {
if args.len() < 1 {
return usage::uninstall();
/// Returns the destination workspace
/// In the case of a custom build, we don't know, so we just return the source workspace
- fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
+ /// what_to_build says: "Just build the lib.rs file in one subdirectory,
+ /// don't walk anything recursively." Or else, everything.
+ fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
let workspace = pkg_src.workspace.clone();
let pkgid = pkg_src.id.clone();
let default_ws = default_workspace();
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
pkgid.to_str());
- return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
+ return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
}
// Is there custom build logic? If so, use it
let cfgs = match pkg_src.package_script_option() {
Some(package_script_path) => {
let sysroot = self.sysroot_to_use();
- let (cfgs, hook_result) = {
- let pscript = PkgScript::parse(@sysroot.clone(),
- package_script_path.clone(),
- &workspace.clone(),
- &pkgid);
- pscript.run_custom(exec, &sysroot)
+ let (cfgs, hook_result) =
+ do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
+ let sub_sysroot = sysroot.clone();
+ let package_script_path_clone = package_script_path.clone();
+ let sub_ws = workspace.clone();
+ let sub_id = pkgid.clone();
+ declare_package_script_dependency(prep, &*pkg_src);
+ do prep.exec |exec| {
+ let pscript = PkgScript::parse(@sub_sysroot.clone(),
+ package_script_path_clone.clone(),
+ &sub_ws,
+ &sub_id);
+
+ pscript.run_custom(exec, &sub_sysroot)
+ }
};
debug!("Command return code = %?", hook_result);
if hook_result != 0 {
// If there was a package script, it should have finished
// the build already. Otherwise...
if !custom {
- // Find crates inside the workspace
- pkg_src.find_crates();
+ match what_to_build {
+ // Find crates inside the workspace
+ &Everything => pkg_src.find_crates(),
+ // Don't infer any crates -- just build the one that was requested
+ &JustOne(ref p) => {
+ // We expect that p is relative to the package source's start directory,
+ // so check that assumption
+ debug!("JustOne: p = %s", p.to_str());
+ assert!(os::path_exists(&pkg_src.start_dir.push_rel(p)));
+ if is_lib(p) {
+ PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
+ } else if is_main(p) {
+ PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
+ } else if is_test(p) {
+ PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
+ } else if is_bench(p) {
+ PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
+ } else {
+ warn(fmt!("Not building any crates for dependency %s", p.to_str()));
+ return workspace.clone();
+ }
+ }
+ }
// Build it!
- let rs_path = pkg_src.build(exec, self, cfgs);
+ let rs_path = pkg_src.build(self, cfgs);
Path(rs_path)
}
else {
fail!("info not yet implemented");
}
- fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
-
- let id = &pkg_src.id;
-
- let installed_files = RWArc::new(~[]);
- let inputs = RWArc::new(~[]);
- // FIXME #7402: Use RUST_PATH to determine target dir
- self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
- do self.workcache_context.with_prep(id.to_str()) |prep| {
- let sub_inputs = inputs.clone();
- let sub_files = installed_files.clone();
- let subsrc = pkg_src.clone();
- let subself = self.clone();
- let id_str = id.to_str();
- let sub_id = id.clone();
- sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
- { (~"file", (*v).clone()) }));
- do prep.exec |exec| {
- let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
- // See #7402: This still isn't quite right yet; we want to
- // install to the first workspace in the RUST_PATH if there's
- // a non-default RUST_PATH. This code installs to the same
- // workspace the package was built in.
- let actual_workspace = if path_util::user_set_rust_path() {
- default_workspace()
- }
- else {
- Path(destination_workspace)
- };
- debug!("install: destination workspace = %s, id = %s, installing to %s",
- destination_workspace, id_str, actual_workspace.to_str());
- let result = subself.install_no_build(&Path(destination_workspace),
- &actual_workspace,
- &sub_id);
- debug!("install: id = %s, about to call discover_outputs, %?",
- id_str, result.to_str());
-
- discover_outputs(exec, result.clone());
- sub_files.write(|r| { *r = result.clone(); });
- sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
- note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
+ fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
+
+ let id = pkg_src.id.clone();
+
+ let mut installed_files = ~[];
+ let inputs = ~[];
+
+ // workcache only knows about *crates*. Building a package
+ // just means inferring all the crates in it, then building each one.
+ let destination_workspace = self.build(&mut pkg_src, what).to_str();
+
+ let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
+ pkg_src.tests.clone(), pkg_src.benchs.clone()];
+ debug!("In declare inputs for %s", id.to_str());
+ for cs in to_do.iter() {
+ for c in cs.iter() {
+ let path = pkg_src.start_dir.push_rel(&c.file).normalize();
+ debug!("Recording input: %s", path.to_str());
+ installed_files.push(path);
}
+ }
+ // See #7402: This still isn't quite right yet; we want to
+ // install to the first workspace in the RUST_PATH if there's
+ // a non-default RUST_PATH. This code installs to the same
+ // workspace the package was built in.
+ let actual_workspace = if path_util::user_set_rust_path() {
+ default_workspace()
+ }
+ else {
+ Path(destination_workspace)
};
- (installed_files.unwrap(), inputs.unwrap())
+ debug!("install: destination workspace = %s, id = %s, installing to %s",
+ destination_workspace, id.to_str(), actual_workspace.to_str());
+ let result = self.install_no_build(&Path(destination_workspace),
+ &actual_workspace,
+ &id).map(|s| Path(*s));
+ debug!("install: id = %s, about to call discover_outputs, %?",
+ id.to_str(), result.to_str());
+ installed_files = installed_files + result;
+ note(fmt!("Installed package %s to %s", id.to_str(), actual_workspace.to_str()));
+ (installed_files, inputs)
}
+ // again, working around lack of Encodable for Path
fn install_no_build(&self,
source_workspace: &Path,
target_workspace: &Path,
- id: &PkgId) -> ~[Path] {
+ id: &PkgId) -> ~[~str] {
use conditions::copy_failed::cond;
// Now copy stuff into the install dirs
let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
debug!("target_exec = %s target_lib = %? \
- maybe_executable = %? maybe_library = %?",
+ maybe_executable = %? maybe_library = %?",
target_exec.to_str(), target_lib,
maybe_executable, maybe_library);
- let mut outputs = ~[];
-
- for exec in maybe_executable.iter() {
- debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
- if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
- os::copy_file(exec, &target_exec)) {
- cond.raise(((*exec).clone(), target_exec.clone()));
+ do self.workcache_context.with_prep(id.install_tag()) |prep| {
+ for ee in maybe_executable.iter() {
+ prep.declare_input("binary",
+ ee.to_str(),
+ workcache_support::digest_only_date(ee));
}
- outputs.push(target_exec.clone());
- }
- for lib in maybe_library.iter() {
- let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
- didn't install it!", lib.to_str()));
- let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib"));
- debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
- if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
- os::copy_file(lib, &target_lib)) {
- cond.raise(((*lib).clone(), target_lib.clone()));
+ for ll in maybe_library.iter() {
+ prep.declare_input("binary",
+ ll.to_str(),
+ workcache_support::digest_only_date(ll));
+ }
+ let subex = maybe_executable.clone();
+ let sublib = maybe_library.clone();
+ let sub_target_ex = target_exec.clone();
+ let sub_target_lib = target_lib.clone();
+
+ do prep.exec |exe_thing| {
+ let mut outputs = ~[];
+
+ for exec in subex.iter() {
+ debug!("Copying: %s -> %s", exec.to_str(), sub_target_ex.to_str());
+ if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) &&
+ os::copy_file(exec, &sub_target_ex)) {
+ cond.raise(((*exec).clone(), sub_target_ex.clone()));
+ }
+ exe_thing.discover_output("binary",
+ sub_target_ex.to_str(),
+ workcache_support::digest_only_date(&sub_target_ex));
+ outputs.push(sub_target_ex.to_str());
+ }
+ for lib in sublib.iter() {
+ let target_lib = sub_target_lib
+ .clone().expect(fmt!("I built %s but apparently \
+ didn't install it!", lib.to_str()));
+ let target_lib = target_lib
+ .pop().push(lib.filename().expect("weird target lib"));
+ debug!("Copying: %s -> %s", lib.to_str(), sub_target_lib.to_str());
+ if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
+ os::copy_file(lib, &target_lib)) {
+ cond.raise(((*lib).clone(), target_lib.clone()));
+ }
+ exe_thing.discover_output("binary",
+ target_lib.to_str(),
+ workcache_support::digest_only_date(&target_lib));
+ outputs.push(target_lib.to_str());
+ }
+ outputs
}
- outputs.push(target_lib.clone());
}
- outputs
}
fn prefer(&self, _id: &str, _vers: Option<~str>) {
fail!("test not yet implemented");
}
+ fn init(&self) {
+ os::mkdir_recursive(&Path("src"), U_RWX);
+ os::mkdir_recursive(&Path("lib"), U_RWX);
+ os::mkdir_recursive(&Path("bin"), U_RWX);
+ os::mkdir_recursive(&Path("build"), U_RWX);
+ }
+
fn uninstall(&self, _id: &str, _vers: Option<~str>) {
fail!("uninstall not yet implemented");
}
let matches = &match getopts::getopts(args, opts) {
result::Ok(m) => m,
result::Err(f) => {
- error(fmt!("%s", getopts::fail_str(f)));
+ error(fmt!("%s", f.to_err_msg()));
return;
}
};
- let mut help = getopts::opt_present(matches, "h") ||
- getopts::opt_present(matches, "help");
- let no_link = getopts::opt_present(matches, "no-link");
- let no_trans = getopts::opt_present(matches, "no-trans");
- let supplied_sysroot = getopts::opt_val(matches, "sysroot");
- let generate_asm = getopts::opt_present(matches, "S") ||
- getopts::opt_present(matches, "assembly");
- let parse_only = getopts::opt_present(matches, "parse-only");
- let pretty = getopts::opt_present(matches, "pretty");
- let emit_llvm = getopts::opt_present(matches, "emit-llvm");
-
- if getopts::opt_present(matches, "v") ||
- getopts::opt_present(matches, "version") {
+ let mut help = matches.opt_present("h") ||
+ matches.opt_present("help");
+ let no_link = matches.opt_present("no-link");
+ let no_trans = matches.opt_present("no-trans");
+ let supplied_sysroot = matches.opt_val("sysroot");
+ let generate_asm = matches.opt_present("S") ||
+ matches.opt_present("assembly");
+ let parse_only = matches.opt_present("parse-only");
+ let pretty = matches.opt_present("pretty");
+ let emit_llvm = matches.opt_present("emit-llvm");
+
+ if matches.opt_present("v") ||
+ matches.opt_present("version") {
rustc::version(args[0]);
return;
}
- let use_rust_path_hack = getopts::opt_present(matches, "r") ||
- getopts::opt_present(matches, "rust-path-hack");
+ let use_rust_path_hack = matches.opt_present("r") ||
+ matches.opt_present("rust-path-hack");
- let linker = getopts::opt_maybe_str(matches, "linker");
- let link_args = getopts::opt_maybe_str(matches, "link-args");
- let cfgs = getopts::opt_strs(matches, "cfg") + getopts::opt_strs(matches, "c");
+ let linker = matches.opt_str("linker");
+ let link_args = matches.opt_str("link-args");
+ let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c");
let mut user_supplied_opt_level = true;
- let opt_level = match getopts::opt_maybe_str(matches, "opt-level") {
+ let opt_level = match matches.opt_str("opt-level") {
Some(~"0") => session::No,
Some(~"1") => session::Less,
Some(~"2") => session::Default,
Some(~"3") => session::Aggressive,
- _ if getopts::opt_present(matches, "O") => session::Default,
+ _ if matches.opt_present("O") => session::Default,
_ => {
user_supplied_opt_level = false;
session::No
}
};
- let save_temps = getopts::opt_present(matches, "save-temps");
- let target = getopts::opt_maybe_str(matches, "target");
- let target_cpu = getopts::opt_maybe_str(matches, "target-cpu");
+ let save_temps = matches.opt_present("save-temps");
+ let target = matches.opt_str("target");
+ let target_cpu = matches.opt_str("target-cpu");
let experimental_features = {
- let strs = getopts::opt_strs(matches, "Z");
- if getopts::opt_present(matches, "Z") {
+ let strs = matches.opt_strs("Z");
+ if matches.opt_present("Z") {
Some(strs)
}
else {
~"list" => usage::list(),
~"prefer" => usage::prefer(),
~"test" => usage::test(),
+ ~"init" => usage::init(),
~"uninstall" => usage::uninstall(),
~"unprefer" => usage::unprefer(),
_ => usage::general()
debug!("Using sysroot: %s", sroot.to_str());
debug!("Will store workcache in %s", default_workspace().to_str());
- BuildContext {
- context: Context {
- cfgs: cfgs,
- rustc_flags: rustc_flags,
- use_rust_path_hack: use_rust_path_hack,
- sysroot: sroot, // Currently, only tests override this
- },
- workcache_context: api::default_context(default_workspace()).workcache_context
- }.run(*cmd, remaining_args)
+
+ let rm_args = remaining_args.clone();
+ let sub_cmd = cmd.clone();
+ // Wrap the rest in task::try in case of a condition failure in a task
+ let result = do task::try {
+ BuildContext {
+ context: Context {
+ cfgs: cfgs.clone(),
+ rustc_flags: rustc_flags.clone(),
+ use_rust_path_hack: use_rust_path_hack,
+ sysroot: sroot.clone(), // Currently, only tests override this
+ },
+ workcache_context: api::default_context(default_workspace()).workcache_context
+ }.run(sub_cmd, rm_args.clone())
+ };
+ // FIXME #9262: This is using the same error code for all errors,
+ // and at least one test case succeeds if rustpkg returns copy_failed_code,
+ // when actually, it might set the exit code for that even if a different
+ // unhandled condition got raised.
+ if result.is_err() { os::set_exit_status(copy_failed_code); }
+
}
/**
#[deriving(Eq)]
pub enum Target {
- // In-place build
+ /// In-place build
Build,
- // Install to bin/ or lib/ dir
+ /// Install to bin/ or lib/ dir
Install
}
+
+#[deriving(Eq, Clone)]
+pub enum WhatToBuild {
+ /// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
+ JustOne(Path),
+ /// Build everything
+ Everything
+}
+
+pub fn is_lib(p: &Path) -> bool {
+ file_is(p, "lib")
+}
+
+pub fn is_main(p: &Path) -> bool {
+ file_is(p, "main")
+}
+
+pub fn is_test(p: &Path) -> bool {
+ file_is(p, "test")
+}
+
+pub fn is_bench(p: &Path) -> bool {
+ file_is(p, "bench")
+}
+
+fn file_is(p: &Path, stem: &str) -> bool {
+ match p.filestem() {
+ Some(s) if s == stem => true,
+ _ => false
+ }
+}
+
+pub fn lib_name_of(p: &Path) -> Path {
+ p.push("lib.rs")
+}
+
+pub static lib_crate_filename: &'static str = "lib.rs";
use syntax::diagnostic;
use target::*;
use package_source::PkgSrc;
-
-/// Returns the last-modified date as an Option
-fn datestamp(p: &Path) -> Option<libc::time_t> {
- p.stat().map(|stat| stat.st_mtime)
-}
+use util::datestamp;
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
let context = workcache::Context::new(
}
fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
- command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+ match command_line_test_with_env(args, cwd, None) {
+ Success(r) => r,
+ _ => fail!("Command line test failed")
+ }
}
-fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> ProcessResult {
command_line_test_with_env(args, cwd, None)
}
+enum ProcessResult {
+ Success(ProcessOutput),
+ Fail(int) // exit code
+}
+
/// Runs `rustpkg` (based on the directory that this executable was
/// invoked from) with the given arguments, in the given working directory.
/// Returns the process's output.
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
- -> Option<ProcessOutput> {
+ -> ProcessResult {
let cmd = rustpkg_exec().to_str();
let env_str = match env {
Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
cmd, args, output.status,
str::from_utf8(output.output) + str::from_utf8(output.error));
- None
+ Fail(output.status)
}
else {
- Some(output)
+ Success(output)
}
}
fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
let mut result = ~[];
- let p_output = command_line_test_with_env(args,
- &os::getcwd(), Some(env)).expect("Command-line test failed");
+ let p_output = match command_line_test_with_env(args,
+ &os::getcwd(), Some(env)) {
+ Fail(_) => fail!("Command-line test failed"),
+ Success(r) => r
+ };
let test_output = str::from_utf8(p_output.output);
for s in test_output.split_iter('\n') {
result.push(s.to_owned());
}
// assumes short_name and path are one and the same -- I should fix
-fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
- debug!("lib_output_file_name: given %s and parent %s and short name %s",
- workspace.to_str(), parent, short_name);
+fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
+ debug!("lib_output_file_name: given %s and short name %s",
+ workspace.to_str(), short_name);
library_in_workspace(&Path(short_name),
short_name,
Build,
}
/// Add a comment at the end
-fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
+fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
use conditions::bad_path::cond;
let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
- let contents = os::list_dir_path(&pkg_src_dir);
let mut maybe_p = None;
- for p in contents.iter() {
- if p.filetype() == Some(".rs") {
- maybe_p = Some(p);
- break;
- }
+ let maybe_file = pkg_src_dir.push(filename);
+ debug!("Trying to frob %s -- %s", pkg_src_dir.to_str(), filename);
+ if os::path_exists(&maybe_file) {
+ maybe_p = Some(maybe_file);
}
+ debug!("Frobbed? %?", maybe_p);
match maybe_p {
- Some(p) => {
+ Some(ref p) => {
let w = io::file_writer(p, &[io::Append]);
match w {
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
debug!("temp_workspace = %s", temp_workspace.to_str());
// should have test, bench, lib, and main
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
- ctxt.install(src);
+ ctxt.install(src, &Everything);
// Check that all files exist
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
debug!("exec = %s", exec.to_str());
// Uses task::try because of #9001
let result = do task::try {
let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
- ctxt.install(pkg_src);
+ ctxt.install(pkg_src, &Everything);
};
// Not the best test -- doesn't test that we failed in the right way.
// Best we can do for now.
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
- ".rust",
- "bar"));
- let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
+ let bar_lib = lib_output_file_name(&workspace, "bar");
+ let bar_date_1 = datestamp(&bar_lib);
+
+ frob_source_file(&workspace, &p_id, "main.rs");
+
+ // Now make `bar` read-only so that subsequent rebuilds of it will fail
+ assert!(chmod_read_only(&bar_lib));
+
+ match command_line_test_partial([~"build", ~"foo"], &workspace) {
+ Success(*) => (), // ok
+ Fail(status) if status == 65 => fail!("no_rebuilding_dep failed: it tried to rebuild bar"),
+ Fail(_) => fail!("no_rebuilding_dep failed for some other reason")
+ }
- frob_source_file(&workspace, &p_id);
- command_line_test([~"build", ~"foo"], &workspace);
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
- ".rust",
- "bar"));
- let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
+ "bar"));
assert_eq!(bar_date_1, bar_date_2);
- assert!(foo_date_1 < foo_date_2);
- assert!(foo_date_1 > bar_date_1);
}
#[test]
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+ let bar_lib_name = lib_output_file_name(&workspace, "bar");
let bar_date = datestamp(&bar_lib_name);
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
touch_source_file(&workspace, &dep_id);
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
- frob_source_file(&workspace, &dep_id);
+ let bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
+ frob_source_file(&workspace, &dep_id, "lib.rs");
// should adjust the datestamp
command_line_test([~"build", ~"foo"], &workspace);
- let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+ let new_bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
assert!(new_bar_date > bar_date);
}
}
#[test]
-#[ignore (reason = "#7402 not yet implemented")]
fn rust_path_install_target() {
let dir_for_path = mkdtemp(&os::tmpdir(),
"source_workspace").expect("rust_path_install_target failed");
let workspace = create_local_package(&p_id);
writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
"#[cfg(quux)] fn main() {}");
- assert!(command_line_test_partial([test_sysroot().to_str(),
+ match command_line_test_partial([test_sysroot().to_str(),
~"build",
~"foo"],
- &workspace).is_none());
+ &workspace) {
+ Success(*) => fail!("test_cfg_fail failed"),
+ _ => ()
+ }
}
assert_executable_exists(&workspace, "foo");
}
+#[test]
+fn test_dependencies_terminate() {
+ // let a_id = PkgId::new("a");
+ let b_id = PkgId::new("b");
+// let workspace = create_local_package_with_dep(&b_id, &a_id);
+ let workspace = create_local_package(&b_id);
+ let b_dir = workspace.push_many([~"src", ~"b-0.1"]);
+ // writeFile(&b_dir.push("lib.rs"), "extern mod a; pub fn f() {}");
+ let b_subdir = b_dir.push("test");
+ assert!(os::mkdir_recursive(&b_subdir, U_RWX));
+ writeFile(&b_subdir.push("test.rs"),
+ "extern mod b; use b::f; #[test] fn g() { f() }");
+ command_line_test([~"install", ~"b"], &workspace);
+}
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
}
}
+
+#[cfg(target_os = "win32")]
+fn chmod_read_only(p: &Path) -> bool {
+ #[fixed_stack_segment];
+ unsafe {
+ do p.to_str().with_c_str |src_buf| {
+ libc::chmod(src_buf, libc::consts::os::posix88::S_IRUSR as c_int) == 0 as libc::c_int
+ }
+ }
+}
+
+#[cfg(not(target_os = "win32"))]
+fn chmod_read_only(p: &Path) -> bool {
+ #[fixed_stack_segment];
+ unsafe {
+ do p.to_str().with_c_str |src_buf| {
+ libc::chmod(src_buf,
+ libc::consts::os::posix88::S_IRUSR as libc::mode_t) == 0
+ as libc::c_int
+ }
+ }
+}
Options:
-c, --cfg Pass a cfg flag to the package script");
}
+
+pub fn init() {
+ io::println("rustpkg init name
+
+This makes a new workspace for working on a project named name.
+");
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::libc;
use std::os;
use extra::workcache;
use rustc::driver::{driver, session};
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
use messages::error;
-pub use target::{OutputType, Main, Lib, Bench, Test};
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
use workcache_support::{digest_file_with_date, digest_only_date};
// It would be nice to have the list of commands in just one place -- for example,
// you could update the match in rustpkg.rc but forget to update this list. I think
// that should be fixed.
static COMMANDS: &'static [&'static str] =
- &["build", "clean", "do", "info", "install", "list", "prefer", "test", "uninstall",
+ &["build", "clean", "do", "info", "init", "install", "list", "prefer", "test", "uninstall",
"unprefer"];
// not sure if we should support anything else
let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
+ // Make the output directory if it doesn't exist already
+ assert!(os::mkdir_recursive(&out_dir, U_RWX));
let binary = os::args()[0].to_managed();
optimize: if opt { session::Aggressive } else { session::No },
test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use),
- addl_lib_search_paths: @mut (~[out_dir.clone()]),
+ addl_lib_search_paths: @mut (~[]),
output_type: output_type,
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
};
// Register dependency on the source file
exec.discover_input("file", input.to_str(), digest_file_with_date(input));
+ debug!("Built %s, date = %?", outputs.out_filename.to_str(),
+ datestamp(&outputs.out_filename));
+
Some(outputs.out_filename)
}
workspaces[0]
};
let (outputs_disc, inputs_disc) =
- context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
+ context.install(PkgSrc::new(dep_workspace.clone(),
+ false, pkg_id), &JustOne(Path(lib_crate_filename)));
debug!("Installed %s, returned %? dependencies and \
%? transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());
debug!("Adding additional search path: %s", lib_name);
let installed_library =
installed_library_in_workspace(&Path(lib_name), &dep_workspace)
- .expect( fmt!("rustpkg failed to install dependency %s",
+ .expect(fmt!("rustpkg failed to install dependency %s",
lib_name));
let install_dir = installed_library.pop();
- debug!("Installed %s into %s", lib_name, install_dir.to_str());
+ debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
+ datestamp(&installed_library));
save(install_dir);
}
}}
};
}
-#[cfg(windows)]
-pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- /* FIXME (#1768): Investigate how to do this on win32
- Node wraps symlinks by having a .bat,
- but that won't work with minGW. */
-
- false
-}
-
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "android")]
-#[cfg(target_os = "freebsd")]
-#[cfg(target_os = "macos")]
-pub fn link_exe(src: &Path, dest: &Path) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- use std::c_str::ToCStr;
- use std::libc;
-
- unsafe {
- do src.with_c_str |src_buf| {
- do dest.with_c_str |dest_buf| {
- libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
- libc::chmod(dest_buf, 755) == 0 as libc::c_int
- }
- }
- }
-}
-
pub fn mk_string_lit(s: @str) -> ast::lit {
Spanned {
node: ast::lit_str(s),
// tjc: cheesy
fn debug_flags() -> ~[~str] { ~[] }
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
+
+
+/// Returns the last-modified date as an Option
+pub fn datestamp(p: &Path) -> Option<libc::time_t> {
+ debug!("Scrutinizing datestamp for %s - does it exist? %?", p.to_str(), os::path_exists(p));
+ let out = p.stat().map(|stat| stat.st_mtime);
+ debug!("Date = %?", out);
+ out.map(|t| { *t as libc::time_t })
+}
e.discover_output("binary", p.to_str(), digest_only_date(p));
}
}
+
+/// Returns the function name for building a crate
+pub fn crate_tag(p: &Path) -> ~str {
+ p.to_str() // implicitly, it's "build(p)"...
+}
// Implementation detail. Shouldn't be public
#[allow(missing_doc)]
pub fn reserve_raw(ty: *TyDesc, ptr: *mut *mut Box<Vec<()>>, n: uint) {
-
+ // check for `uint` overflow
unsafe {
- let size_in_bytes = n * (*ty).size;
- if size_in_bytes > (**ptr).data.alloc {
- let total_size = size_in_bytes + sys::size_of::<Vec<()>>();
+ if n > (**ptr).data.alloc / (*ty).size {
+ let alloc = n * (*ty).size;
+ let total_size = alloc + sys::size_of::<Vec<()>>();
+ if alloc / (*ty).size != n || total_size < alloc {
+ fail!("vector size is too large: %u", n);
+ }
(*ptr) = local_realloc(*ptr as *(), total_size) as *mut Box<Vec<()>>;
- (**ptr).data.alloc = size_in_bytes;
+ (**ptr).data.alloc = alloc;
}
}
/// Determine if two borrowed pointers point to the same thing.
#[inline]
pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
- to_uint(thing) == to_uint(other)
+ (thing as *T) == (other as *T)
}
// Equality for region pointers
#[inline]
fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
}
+
+#[cfg(test)]
+mod tests {
+ use super::ref_eq;
+
+ #[test]
+ fn test_ref_eq() {
+ let x = 1;
+ let y = 1;
+
+ assert!(ref_eq(&x, &x));
+ assert!(!ref_eq(&x, &y));
+ }
+}
condition! {
// This should be &[u8] but there's a lifetime issue (#5370).
- // NOTE: this super::NullByteResolution should be NullByteResolution
- // Change this next time the snapshot is updated.
- pub null_byte: (~[u8]) -> super::NullByteResolution;
+ pub null_byte: (~[u8]) -> NullByteResolution;
}
/// The representation of a C String.
}
impl Drop for CString {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
if self.owns_buffer_ {
unsafe {
// avoid calling str::to_str_radix because we don't really need to allocate
// here.
f('\\');
- let pad = cond!(
- (c <= '\xff') { f('x'); 2 }
- (c <= '\uffff') { f('u'); 4 }
- _ { f('U'); 8 }
- );
+ let pad = match () {
+ _ if c <= '\xff' => { f('x'); 2 }
+ _ if c <= '\uffff' => { f('u'); 4 }
+ _ => { f('U'); 8 }
+ };
for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
unsafe {
match ((c as i32) >> offset) & 0xf {
static MAX_FOUR_B: uint = 2097152u;
let code = c as uint;
- cond!(
- (code < MAX_ONE_B) { 1u }
- (code < MAX_TWO_B) { 2u }
- (code < MAX_THREE_B) { 3u }
- (code < MAX_FOUR_B) { 4u }
- _ { fail!("invalid character!") }
- )
+ match () {
+ _ if code < MAX_ONE_B => 1u,
+ _ if code < MAX_TWO_B => 2u,
+ _ if code < MAX_THREE_B => 3u,
+ _ if code < MAX_FOUR_B => 4u,
+ _ => fail!("invalid character!"),
+ }
}
impl ToStr for char {
#[unsafe_destructor]
impl<'self, T, U> Drop for Guard<'self, T, U> {
- fn drop(&self) {
+ fn drop(&mut self) {
debug!("Guard: popping handler from TLS");
let curr = local_data::pop(self.cond.key);
match curr {
}
impl Drop for FILERes {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
}
impl Drop for FdRes {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
#[unsafe_destructor]
impl<T> Drop for Res<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
match self.arg.opt_level {
None => (),
Some(level) => {
pub type ssize_t = i32;
}
#[cfg(target_arch = "x86")]
- #[cfg(target_arch = "mips")]
pub mod posix01 {
use libc::types::os::arch::c95::{c_short, c_long, time_t};
use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t};
pub type blksize_t = i32;
pub type blkcnt_t = i32;
- #[cfg(target_arch = "x86")]
pub struct stat {
st_dev: dev_t,
__pad1: c_short,
__unused4: c_long,
__unused5: c_long,
}
-
- #[cfg(target_arch = "mips")]
- pub struct stat {
- st_dev: c_ulong,
- st_pad1: [c_long, ..3],
- st_ino: ino_t,
- st_mode: mode_t,
- st_nlink: nlink_t,
- st_uid: uid_t,
- st_gid: gid_t,
- st_rdev: c_ulong,
- st_pad2: [c_long, ..2],
- st_size: off_t,
- st_pad3: c_long,
- st_atime: time_t,
- st_atime_nsec: c_long,
- st_mtime: time_t,
- st_mtime_nsec: c_long,
- st_ctime: time_t,
- st_ctime_nsec: c_long,
- st_blksize: blksize_t,
- st_blocks: blkcnt_t,
- st_pad5: [c_long, ..14],
- }
}
#[cfg(target_arch = "arm")]
pub mod posix01 {
st_ino: c_ulonglong
}
}
+ #[cfg(target_arch = "mips")]
+ pub mod posix01 {
+ use libc::types::os::arch::c95::{c_long, c_ulong, time_t};
+ use libc::types::os::arch::posix88::{gid_t, ino_t};
+ use libc::types::os::arch::posix88::{mode_t, off_t};
+ use libc::types::os::arch::posix88::{uid_t};
+
+ pub type nlink_t = u32;
+ pub type blksize_t = i32;
+ pub type blkcnt_t = i32;
+
+ pub struct stat {
+ st_dev: c_ulong,
+ st_pad1: [c_long, ..3],
+ st_ino: ino_t,
+ st_mode: mode_t,
+ st_nlink: nlink_t,
+ st_uid: uid_t,
+ st_gid: gid_t,
+ st_rdev: c_ulong,
+ st_pad2: [c_long, ..2],
+ st_size: off_t,
+ st_pad3: c_long,
+ st_atime: time_t,
+ st_atime_nsec: c_long,
+ st_mtime: time_t,
+ st_mtime_nsec: c_long,
+ st_ctime: time_t,
+ st_ctime_nsec: c_long,
+ st_blksize: blksize_t,
+ st_blocks: blkcnt_t,
+ st_pad5: [c_long, ..14],
+ }
+ }
pub mod posix08 {}
pub mod bsd44 {}
pub mod extra {}
pub static EPIPE : c_int = 32;
pub static EDOM : c_int = 33;
pub static ERANGE : c_int = 34;
+
+ pub static ENOMSG: c_int = 35;
+ pub static EIDRM: c_int = 36;
+ pub static ECHRNG: c_int = 37;
+ pub static EL2NSYNC: c_int = 38;
+ pub static EL3HLT: c_int = 39;
+ pub static EL3RST: c_int = 40;
+ pub static ELNRNG: c_int = 41;
+ pub static EUNATCH: c_int = 42;
+ pub static ENOCSI: c_int = 43;
+ pub static EL2HLT: c_int = 44;
+ pub static EDEADLK: c_int = 45;
+ pub static ENOLCK: c_int = 46;
+ pub static EBADE: c_int = 50;
+ pub static EBADR: c_int = 51;
+ pub static EXFULL: c_int = 52;
+ pub static ENOANO: c_int = 53;
+ pub static EBADRQC: c_int = 54;
+ pub static EBADSLT: c_int = 55;
+ pub static EDEADLOCK: c_int = 56;
+ pub static EBFONT: c_int = 59;
+ pub static ENOSTR: c_int = 60;
+ pub static ENODATA: c_int = 61;
+ pub static ETIME: c_int = 62;
+ pub static ENOSR: c_int = 63;
+ pub static ENONET: c_int = 64;
+ pub static ENOPKG: c_int = 65;
+ pub static EREMOTE: c_int = 66;
+ pub static ENOLINK: c_int = 67;
+ pub static EADV: c_int = 68;
+ pub static ESRMNT: c_int = 69;
+ pub static ECOMM: c_int = 70;
+ pub static EPROTO: c_int = 71;
+ pub static EDOTDOT: c_int = 73;
+ pub static EMULTIHOP: c_int = 74;
+ pub static EBADMSG: c_int = 77;
+ pub static ENAMETOOLONG: c_int = 78;
+ pub static EOVERFLOW: c_int = 79;
+ pub static ENOTUNIQ: c_int = 80;
+ pub static EBADFD: c_int = 81;
+ pub static EREMCHG: c_int = 82;
+ pub static ELIBACC: c_int = 83;
+ pub static ELIBBAD: c_int = 84;
+ pub static ELIBSCN: c_int = 95;
+ pub static ELIBMAX: c_int = 86;
+ pub static ELIBEXEC: c_int = 87;
+ pub static EILSEQ: c_int = 88;
+ pub static ENOSYS: c_int = 89;
+ pub static ELOOP: c_int = 90;
+ pub static ERESTART: c_int = 91;
+ pub static ESTRPIPE: c_int = 92;
+ pub static ENOTEMPTY: c_int = 93;
+ pub static EUSERS: c_int = 94;
+ pub static ENOTSOCK: c_int = 95;
+ pub static EDESTADDRREQ: c_int = 96;
+ pub static EMSGSIZE: c_int = 97;
+ pub static EPROTOTYPE: c_int = 98;
+ pub static ENOPROTOOPT: c_int = 99;
+ pub static EPROTONOSUPPORT: c_int = 120;
+ pub static ESOCKTNOSUPPORT: c_int = 121;
+ pub static EOPNOTSUPP: c_int = 122;
+ pub static EPFNOSUPPORT: c_int = 123;
+ pub static EAFNOSUPPORT: c_int = 124;
+ pub static EADDRINUSE: c_int = 125;
+ pub static EADDRNOTAVAIL: c_int = 126;
+ pub static ENETDOWN: c_int = 127;
+ pub static ENETUNREACH: c_int = 128;
+ pub static ENETRESET: c_int = 129;
+ pub static ECONNABORTED: c_int = 130;
+ pub static ECONNRESET: c_int = 131;
+ pub static ENOBUFS: c_int = 132;
+ pub static EISCONN: c_int = 133;
+ pub static ENOTCONN: c_int = 134;
+ pub static EUCLEAN: c_int = 135;
+ pub static ENOTNAM: c_int = 137;
+ pub static ENAVAIL: c_int = 138;
+ pub static EISNAM: c_int = 139;
+ pub static EREMOTEIO: c_int = 140;
+ pub static ESHUTDOWN: c_int = 143;
+ pub static ETOOMANYREFS: c_int = 144;
+ pub static ETIMEDOUT: c_int = 145;
+ pub static ECONNREFUSED: c_int = 146;
+ pub static EHOSTDOWN: c_int = 147;
+ pub static EHOSTUNREACH: c_int = 148;
+ pub static EWOULDBLOCK: c_int = EAGAIN;
+ pub static EALREADY: c_int = 149;
+ pub static EINPROGRESS: c_int = 150;
+ pub static ESTALE: c_int = 151;
+ pub static ECANCELED: c_int = 158;
+
+ pub static ENOMEDIUM: c_int = 159;
+ pub static EMEDIUMTYPE: c_int = 160;
+ pub static ENOKEY: c_int = 161;
+ pub static EKEYEXPIRED: c_int = 162;
+ pub static EKEYREVOKED: c_int = 163;
+ pub static EKEYREJECTED: c_int = 164;
+
+ pub static EOWNERDEAD: c_int = 165;
+ pub static ENOTRECOVERABLE: c_int = 166;
+
+ pub static ERFKILL: c_int = 167;
+
+ pub static EHWPOISON: c_int = 168;
+
+ pub static EDQUOT: c_int = 1133;
}
pub mod posix01 {
use libc::types::os::arch::c95::c_int;
rt::logging::console_off();
}
-#[cfg(not(test), stage0)]
-#[lang="log_type"]
-#[allow(missing_doc)]
-pub fn log_type<T>(_level: u32, object: &T) {
- use sys;
-
- // XXX: Bad allocation
- let msg = sys::log_str(object);
- newsched_log_str(msg);
-}
-
fn newsched_log_str(msg: ~str) {
use rt::task::Task;
use rt::local::Local;
/// Returns `NaN` if either of the numbers are `NaN`.
#[inline]
fn min(&self, other: &f32) -> f32 {
- cond!(
- (self.is_NaN()) { *self }
- (other.is_NaN()) { *other }
- (*self < *other) { *self }
- _ { *other }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if other.is_NaN() => *other,
+ _ if *self < *other => *self,
+ _ => *other,
+ }
}
/// Returns `NaN` if either of the numbers are `NaN`.
#[inline]
fn max(&self, other: &f32) -> f32 {
- cond!(
- (self.is_NaN()) { *self }
- (other.is_NaN()) { *other }
- (*self > *other) { *self }
- _ { *other }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if other.is_NaN() => *other,
+ _ if *self > *other => *self,
+ _ => *other,
+ }
}
/// Returns the number constrained within the range `mn <= self <= mx`.
/// If any of the numbers are `NaN` then `NaN` is returned.
#[inline]
fn clamp(&self, mn: &f32, mx: &f32) -> f32 {
- cond!(
- (self.is_NaN()) { *self }
- (!(*self <= *mx)) { *mx }
- (!(*self >= *mn)) { *mn }
- _ { *self }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if !(*self <= *mx) => *mx,
+ _ if !(*self >= *mn) => *mn,
+ _ => *self,
+ }
}
}
}
}
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently, '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f32> {
- strconv::from_str_common(num, 10u, true, true, true,
- strconv::ExpDec, false, false)
-}
-
///
/// Convert a string in base 16 to a float.
/// Accepts a optional binary exponent.
strconv::ExpBin, false, false)
}
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
- strconv::from_str_common(num, rdx, true, true, false,
- strconv::ExpNone, false, false)
-}
-
impl FromStr for f32 {
+ ///
+ /// Convert a string in base 10 to a float.
+ /// Accepts a optional decimal exponent.
+ ///
+ /// This function accepts strings such as
+ ///
+ /// * '3.14'
+ /// * '+3.14', equivalent to '3.14'
+ /// * '-3.14'
+ /// * '2.5E10', or equivalently, '2.5e10'
+ /// * '2.5E-10'
+ /// * '.' (understood as 0)
+ /// * '5.'
+ /// * '.5', or, equivalently, '0.5'
+ /// * '+inf', 'inf', '-inf', 'NaN'
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
- fn from_str(val: &str) -> Option<f32> { from_str(val) }
+ fn from_str(val: &str) -> Option<f32> {
+ strconv::from_str_common(val, 10u, true, true, true,
+ strconv::ExpDec, false, false)
+ }
}
impl num::FromStrRadix for f32 {
+ ///
+ /// Convert a string in an given base to a float.
+ ///
+ /// Due to possible conflicts, this function does **not** accept
+ /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ /// does it recognize exponents of any kind.
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ /// * radix - The base to use. Must lie in the range [2 .. 36]
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
- from_str_radix(val, rdx)
+ strconv::from_str_common(val, rdx, true, true, false,
+ strconv::ExpNone, false, false)
}
}
/// Returns `NaN` if either of the numbers are `NaN`.
#[inline]
fn min(&self, other: &f64) -> f64 {
- cond!(
- (self.is_NaN()) { *self }
- (other.is_NaN()) { *other }
- (*self < *other) { *self }
- _ { *other }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if other.is_NaN() => *other,
+ _ if *self < *other => *self,
+ _ => *other,
+ }
}
/// Returns `NaN` if either of the numbers are `NaN`.
#[inline]
fn max(&self, other: &f64) -> f64 {
- cond!(
- (self.is_NaN()) { *self }
- (other.is_NaN()) { *other }
- (*self > *other) { *self }
- _ { *other }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if other.is_NaN() => *other,
+ _ if *self > *other => *self,
+ _ => *other,
+ }
}
/// Returns the number constrained within the range `mn <= self <= mx`.
/// If any of the numbers are `NaN` then `NaN` is returned.
#[inline]
fn clamp(&self, mn: &f64, mx: &f64) -> f64 {
- cond!(
- (self.is_NaN()) { *self }
- (!(*self <= *mx)) { *mx }
- (!(*self >= *mn)) { *mn }
- _ { *self }
- )
+ match () {
+ _ if self.is_NaN() => *self,
+ _ if !(*self <= *mx) => *mx,
+ _ if !(*self >= *mn) => *mn,
+ _ => *self,
+ }
}
}
}
}
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently, '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<f64> {
- strconv::from_str_common(num, 10u, true, true, true,
- strconv::ExpDec, false, false)
-}
-
///
/// Convert a string in base 16 to a float.
/// Accepts a optional binary exponent.
strconv::ExpBin, false, false)
}
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
- strconv::from_str_common(num, rdx, true, true, false,
- strconv::ExpNone, false, false)
-}
-
impl FromStr for f64 {
+ ///
+ /// Convert a string in base 10 to a float.
+ /// Accepts a optional decimal exponent.
+ ///
+ /// This function accepts strings such as
+ ///
+ /// * '3.14'
+ /// * '+3.14', equivalent to '3.14'
+ /// * '-3.14'
+ /// * '2.5E10', or equivalently, '2.5e10'
+ /// * '2.5E-10'
+ /// * '.' (understood as 0)
+ /// * '5.'
+ /// * '.5', or, equivalently, '0.5'
+ /// * '+inf', 'inf', '-inf', 'NaN'
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
- fn from_str(val: &str) -> Option<f64> { from_str(val) }
+ fn from_str(val: &str) -> Option<f64> {
+ strconv::from_str_common(val, 10u, true, true, true,
+ strconv::ExpDec, false, false)
+ }
}
impl num::FromStrRadix for f64 {
+ ///
+ /// Convert a string in an given base to a float.
+ ///
+ /// Due to possible conflicts, this function does **not** accept
+ /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ /// does it recognize exponents of any kind.
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ /// * radix - The base to use. Must lie in the range [2 .. 36]
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
- from_str_radix(val, rdx)
+ strconv::from_str_common(val, rdx, true, true, false,
+ strconv::ExpNone, false, false)
}
}
}
}
-///
-/// Convert a string in base 10 to a float.
-/// Accepts a optional decimal exponent.
-///
-/// This function accepts strings such as
-///
-/// * '3.14'
-/// * '+3.14', equivalent to '3.14'
-/// * '-3.14'
-/// * '2.5E10', or equivalently, '2.5e10'
-/// * '2.5E-10'
-/// * '.' (understood as 0)
-/// * '5.'
-/// * '.5', or, equivalently, '0.5'
-/// * '+inf', 'inf', '-inf', 'NaN'
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str(num: &str) -> Option<float> {
- strconv::from_str_common(num, 10u, true, true, true,
- strconv::ExpDec, false, false)
-}
-
///
/// Convert a string in base 16 to a float.
/// Accepts a optional binary exponent.
strconv::ExpBin, false, false)
}
-///
-/// Convert a string in an given base to a float.
-///
-/// Due to possible conflicts, this function does **not** accept
-/// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
-/// does it recognize exponents of any kind.
-///
-/// Leading and trailing whitespace represent an error.
-///
-/// # Arguments
-///
-/// * num - A string
-/// * radix - The base to use. Must lie in the range [2 .. 36]
-///
-/// # Return value
-///
-/// `none` if the string did not represent a valid number. Otherwise,
-/// `Some(n)` where `n` is the floating-point number represented by `num`.
-///
-#[inline]
-pub fn from_str_radix(num: &str, radix: uint) -> Option<float> {
- strconv::from_str_common(num, radix, true, true, false,
- strconv::ExpNone, false, false)
-}
-
impl FromStr for float {
+ ///
+ /// Convert a string in base 10 to a float.
+ /// Accepts a optional decimal exponent.
+ ///
+ /// This function accepts strings such as
+ ///
+ /// * '3.14'
+ /// * '+3.14', equivalent to '3.14'
+ /// * '-3.14'
+ /// * '2.5E10', or equivalently, '2.5e10'
+ /// * '2.5E-10'
+ /// * '.' (understood as 0)
+ /// * '5.'
+ /// * '.5', or, equivalently, '0.5'
+ /// * '+inf', 'inf', '-inf', 'NaN'
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
- fn from_str(val: &str) -> Option<float> { from_str(val) }
+ fn from_str(val: &str) -> Option<float> {
+ strconv::from_str_common(val, 10u, true, true, true,
+ strconv::ExpDec, false, false)
+ }
}
impl num::FromStrRadix for float {
+ ///
+ /// Convert a string in an given base to a float.
+ ///
+ /// Due to possible conflicts, this function does **not** accept
+ /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ /// does it recognize exponents of any kind.
+ ///
+ /// Leading and trailing whitespace represent an error.
+ ///
+ /// # Arguments
+ ///
+ /// * num - A string
+ /// * radix - The base to use. Must lie in the range [2 .. 36]
+ ///
+ /// # Return value
+ ///
+ /// `none` if the string did not represent a valid number. Otherwise,
+ /// `Some(n)` where `n` is the floating-point number represented by `num`.
+ ///
#[inline]
fn from_str_radix(val: &str, radix: uint) -> Option<float> {
- from_str_radix(val, radix)
+ strconv::from_str_common(val, radix, true, true, false,
+ strconv::ExpNone, false, false)
}
}
#[test]
pub fn test_from_str() {
- assert_eq!(from_str("3"), Some(3.));
- assert_eq!(from_str("3.14"), Some(3.14));
- assert_eq!(from_str("+3.14"), Some(3.14));
- assert_eq!(from_str("-3.14"), Some(-3.14));
- assert_eq!(from_str("2.5E10"), Some(25000000000.));
- assert_eq!(from_str("2.5e10"), Some(25000000000.));
- assert_eq!(from_str("25000000000.E-10"), Some(2.5));
- assert_eq!(from_str("."), Some(0.));
- assert_eq!(from_str(".e1"), Some(0.));
- assert_eq!(from_str(".e-1"), Some(0.));
- assert_eq!(from_str("5."), Some(5.));
- assert_eq!(from_str(".5"), Some(0.5));
- assert_eq!(from_str("0.5"), Some(0.5));
- assert_eq!(from_str("-.5"), Some(-0.5));
- assert_eq!(from_str("-5"), Some(-5.));
- assert_eq!(from_str("inf"), Some(infinity));
- assert_eq!(from_str("+inf"), Some(infinity));
- assert_eq!(from_str("-inf"), Some(neg_infinity));
+ assert_eq!(from_str::<float>("3"), Some(3.));
+ assert_eq!(from_str::<float>("3.14"), Some(3.14));
+ assert_eq!(from_str::<float>("+3.14"), Some(3.14));
+ assert_eq!(from_str::<float>("-3.14"), Some(-3.14));
+ assert_eq!(from_str::<float>("2.5E10"), Some(25000000000.));
+ assert_eq!(from_str::<float>("2.5e10"), Some(25000000000.));
+ assert_eq!(from_str::<float>("25000000000.E-10"), Some(2.5));
+ assert_eq!(from_str::<float>("."), Some(0.));
+ assert_eq!(from_str::<float>(".e1"), Some(0.));
+ assert_eq!(from_str::<float>(".e-1"), Some(0.));
+ assert_eq!(from_str::<float>("5."), Some(5.));
+ assert_eq!(from_str::<float>(".5"), Some(0.5));
+ assert_eq!(from_str::<float>("0.5"), Some(0.5));
+ assert_eq!(from_str::<float>("-.5"), Some(-0.5));
+ assert_eq!(from_str::<float>("-5"), Some(-5.));
+ assert_eq!(from_str::<float>("inf"), Some(infinity));
+ assert_eq!(from_str::<float>("+inf"), Some(infinity));
+ assert_eq!(from_str::<float>("-inf"), Some(neg_infinity));
// note: NaN != NaN, hence this slightly complex test
- match from_str("NaN") {
+ match from_str::<float>("NaN") {
Some(f) => assert!(f.is_NaN()),
None => fail!()
}
// note: -0 == 0, hence these slightly more complex tests
- match from_str("-0") {
+ match from_str::<float>("-0") {
Some(v) if v.is_zero() => assert!(v.is_negative()),
_ => fail!()
}
- match from_str("0") {
+ match from_str::<float>("0") {
Some(v) if v.is_zero() => assert!(v.is_positive()),
_ => fail!()
}
- assert!(from_str("").is_none());
- assert!(from_str("x").is_none());
- assert!(from_str(" ").is_none());
- assert!(from_str(" ").is_none());
- assert!(from_str("e").is_none());
- assert!(from_str("E").is_none());
- assert!(from_str("E1").is_none());
- assert!(from_str("1e1e1").is_none());
- assert!(from_str("1e1.1").is_none());
- assert!(from_str("1e1-1").is_none());
+ assert!(from_str::<float>("").is_none());
+ assert!(from_str::<float>("x").is_none());
+ assert!(from_str::<float>(" ").is_none());
+ assert!(from_str::<float>(" ").is_none());
+ assert!(from_str::<float>("e").is_none());
+ assert!(from_str::<float>("E").is_none());
+ assert!(from_str::<float>("E1").is_none());
+ assert!(from_str::<float>("1e1e1").is_none());
+ assert!(from_str::<float>("1e1.1").is_none());
+ assert!(from_str::<float>("1e1-1").is_none());
}
#[test]
let mut tmp: uint = n - 1u;
let mut shift: uint = 1u;
while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
- return tmp + 1u;
+ tmp + 1u
+}
+
+/// Returns the smallest power of 2 greater than or equal to `n`
+#[inline]
+pub fn next_power_of_two_opt(n: uint) -> Option<uint> {
+ let halfbits: uint = sys::size_of::<uint>() * 4u;
+ let mut tmp: uint = n - 1u;
+ let mut shift: uint = 1u;
+ while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
+ tmp.checked_add(&1)
}
#[cfg(target_word_size = "32")]
/// Returns the number constrained within the range `mn <= self <= mx`.
#[inline]
fn clamp(&self, mn: &$T, mx: &$T) -> $T {
- cond!(
- (*self > *mx) { *mx }
- (*self < *mn) { *mn }
- _ { *self }
- )
+ match () {
+ _ if (*self > *mx) => *mx,
+ _ if (*self < *mn) => *mn,
+ _ => *self,
+ }
}
}
#[lang="drop"]
pub trait Drop {
- fn drop(&self);
+ fn drop(&mut self);
}
#[lang="add"]
}
impl Drop for HasDtor {
- fn drop(&self) {
+ fn drop(&mut self) {
}
}
HasDtor { x : 10 };
}
}
-}
\ No newline at end of file
+}
#[unsafe_destructor]
impl ::ops::Drop for R {
- fn drop(&self) { *(self.i) += 1; }
+ fn drop(&mut self) { *(self.i) += 1; }
}
fn R(i: @mut int) -> R {
}
}
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
- (fn $name:ident ()) => (
- extern {
- fn $name();
- }
- )
-)
-}
-
/*
Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
if (ch as uint == 0) {
fail!("os::env() failure getting env string from OS: %s", os::last_os_error());
}
- let mut curr_ptr: uint = ch as uint;
- let mut result = ~[];
- while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
- let env_pair = str::raw::from_c_str(
- curr_ptr as *libc::c_char);
- result.push(env_pair);
- curr_ptr +=
- libc::strlen(curr_ptr as *libc::c_char) as uint
- + 1;
- }
+ let result = str::raw::from_c_multistring(ch as *libc::c_char, None);
FreeEnvironmentStringsA(ch);
result
}
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
- use libc::types::os::arch::extra::LPSTR;
+ use libc::types::os::arch::extra::LPWSTR;
use libc::types::os::arch::extra::LPVOID;
+ use libc::types::os::arch::extra::WCHAR;
#[cfg(target_arch = "x86")]
#[link_name = "kernel32"]
#[abi = "stdcall"]
extern "stdcall" {
- fn FormatMessageA(flags: DWORD,
+ fn FormatMessageW(flags: DWORD,
lpSrc: LPVOID,
msgId: DWORD,
langId: DWORD,
- buf: LPSTR,
+ buf: LPWSTR,
nsize: DWORD,
args: *c_void)
-> DWORD;
#[cfg(target_arch = "x86_64")]
#[link_name = "kernel32"]
extern {
- fn FormatMessageA(flags: DWORD,
+ fn FormatMessageW(flags: DWORD,
lpSrc: LPVOID,
msgId: DWORD,
langId: DWORD,
- buf: LPSTR,
+ buf: LPWSTR,
nsize: DWORD,
args: *c_void)
-> DWORD;
let langId = 0x0800 as DWORD;
let err = errno() as DWORD;
- let mut buf = [0 as c_char, ..TMPBUF_SZ];
+ let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
unsafe {
do buf.as_mut_buf |buf, len| {
- let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
ptr::mut_null(),
err,
}
}
- do buf.as_imm_buf |buf, _len| {
- str::raw::from_c_str(buf)
- }
+ str::from_utf16(buf)
}
}
#[cfg(unix)]
impl Drop for MemoryMap {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
#[cfg(windows)]
impl Drop for MemoryMap {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
pub use os::consts::arm::*;
#[cfg(target_arch = "mips")]
- use os::consts::mips::*;
+ pub use os::consts::mips::*;
pub mod unix {
pub static FAMILY: &'static str = "unix";
use cmp::Equiv;
use iter::{range, Iterator};
use option::{Option, Some, None};
-#[cfg(stage0)]
-use sys;
use unstable::intrinsics;
use util::swap;
#[cfg(not(test))] use cmp::{Eq, Ord};
-/// Calculate the offset from a pointer. The count *must* be in bounds or
-/// otherwise the loads of this address are undefined.
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
- (ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
-}
-
-/// Calculate the offset from a mut pointer
-#[inline]
-#[cfg(stage0)]
-pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
- (ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
-}
-
/// Calculate the offset from a pointer
#[inline]
-#[cfg(not(stage0))]
pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
intrinsics::offset(ptr, count)
}
/// Calculate the offset from a mut pointer. The count *must* be in bounds or
/// otherwise the loads of this address are undefined.
#[inline]
-#[cfg(not(stage0))]
pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
intrinsics::offset(ptr as *T, count) as *mut T
}
}
// Equality for pointers
-#[cfg(stage0, not(test))]
-impl<T> Eq for *T {
- #[inline]
- fn eq(&self, other: &*T) -> bool {
- (*self as uint) == (*other as uint)
- }
- #[inline]
- fn ne(&self, other: &*T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
impl<T> Eq for *T {
#[inline]
fn eq(&self, other: &*T) -> bool {
fn ne(&self, other: &*T) -> bool { !self.eq(other) }
}
-#[cfg(stage0, not(test))]
-impl<T> Eq for *mut T {
- #[inline]
- fn eq(&self, other: &*mut T) -> bool {
- (*self as uint) == (*other as uint)
- }
- #[inline]
- fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
impl<T> Eq for *mut T {
#[inline]
fn eq(&self, other: &*mut T) -> bool {
}
// Comparison for pointers
-#[cfg(stage0, not(test))]
-impl<T> Ord for *T {
- #[inline]
- fn lt(&self, other: &*T) -> bool {
- (*self as uint) < (*other as uint)
- }
- #[inline]
- fn le(&self, other: &*T) -> bool {
- (*self as uint) <= (*other as uint)
- }
- #[inline]
- fn ge(&self, other: &*T) -> bool {
- (*self as uint) >= (*other as uint)
- }
- #[inline]
- fn gt(&self, other: &*T) -> bool {
- (*self as uint) > (*other as uint)
- }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
impl<T> Ord for *T {
#[inline]
fn lt(&self, other: &*T) -> bool {
}
}
-#[cfg(stage0, not(test))]
-impl<T> Ord for *mut T {
- #[inline]
- fn lt(&self, other: &*mut T) -> bool {
- (*self as uint) < (*other as uint)
- }
- #[inline]
- fn le(&self, other: &*mut T) -> bool {
- (*self as uint) <= (*other as uint)
- }
- #[inline]
- fn ge(&self, other: &*mut T) -> bool {
- (*self as uint) >= (*other as uint)
- }
- #[inline]
- fn gt(&self, other: &*mut T) -> bool {
- (*self as uint) > (*other as uint)
- }
-}
-
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
impl<T> Ord for *mut T {
#[inline]
fn lt(&self, other: &*mut T) -> bool {
}
// used to make space in TLS for a random number generator
-static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
+local_data_key!(tls_rng_state: @@mut IsaacRng)
/**
* Gives back a lazily initialized task-local random number generator,
+++ /dev/null
-// 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.
-
-/*!
-
-Runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
-use libc::c_void;
-use sys;
-use unstable::raw;
-
-/**
- * Trait for visitor that wishes to reflect on data. To use this, create a
- * struct that encapsulates the set of pointers you wish to walk through a
- * data structure, and implement both `MovePtr` for it as well as `TyVisitor`;
- * then build a MovePtrAdaptor wrapped around your struct.
- */
-pub trait MovePtr {
- fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void);
- fn push_ptr(&self);
- fn pop_ptr(&self);
-}
-
-/// Helper function for alignment calculation.
-#[inline]
-pub fn align(size: uint, align: uint) -> uint {
- ((size + align) - 1u) & !(align - 1u)
-}
-
-/// Adaptor to wrap around visitors implementing MovePtr.
-pub struct MovePtrAdaptor<V> {
- inner: V
-}
-pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
- MovePtrAdaptor { inner: v }
-}
-
-impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
- #[inline]
- pub fn bump(&self, sz: uint) {
- do self.inner.move_ptr() |p| {
- ((p as uint) + sz) as *c_void
- };
- }
-
- #[inline]
- pub fn align(&self, a: uint) {
- do self.inner.move_ptr() |p| {
- align(p as uint, a) as *c_void
- };
- }
-
- #[inline]
- pub fn align_to<T>(&self) {
- self.align(sys::min_align_of::<T>());
- }
-
- #[inline]
- pub fn bump_past<T>(&self) {
- self.bump(sys::size_of::<T>());
- }
-}
-
-/// Abstract type-directed pointer-movement using the MovePtr trait
-impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
- fn visit_bot(&self) -> bool {
- self.align_to::<()>();
- if ! self.inner.visit_bot() { return false; }
- self.bump_past::<()>();
- true
- }
-
- fn visit_nil(&self) -> bool {
- self.align_to::<()>();
- if ! self.inner.visit_nil() { return false; }
- self.bump_past::<()>();
- true
- }
-
- fn visit_bool(&self) -> bool {
- self.align_to::<bool>();
- if ! self.inner.visit_bool() { return false; }
- self.bump_past::<bool>();
- true
- }
-
- fn visit_int(&self) -> bool {
- self.align_to::<int>();
- if ! self.inner.visit_int() { return false; }
- self.bump_past::<int>();
- true
- }
-
- fn visit_i8(&self) -> bool {
- self.align_to::<i8>();
- if ! self.inner.visit_i8() { return false; }
- self.bump_past::<i8>();
- true
- }
-
- fn visit_i16(&self) -> bool {
- self.align_to::<i16>();
- if ! self.inner.visit_i16() { return false; }
- self.bump_past::<i16>();
- true
- }
-
- fn visit_i32(&self) -> bool {
- self.align_to::<i32>();
- if ! self.inner.visit_i32() { return false; }
- self.bump_past::<i32>();
- true
- }
-
- fn visit_i64(&self) -> bool {
- self.align_to::<i64>();
- if ! self.inner.visit_i64() { return false; }
- self.bump_past::<i64>();
- true
- }
-
- fn visit_uint(&self) -> bool {
- self.align_to::<uint>();
- if ! self.inner.visit_uint() { return false; }
- self.bump_past::<uint>();
- true
- }
-
- fn visit_u8(&self) -> bool {
- self.align_to::<u8>();
- if ! self.inner.visit_u8() { return false; }
- self.bump_past::<u8>();
- true
- }
-
- fn visit_u16(&self) -> bool {
- self.align_to::<u16>();
- if ! self.inner.visit_u16() { return false; }
- self.bump_past::<u16>();
- true
- }
-
- fn visit_u32(&self) -> bool {
- self.align_to::<u32>();
- if ! self.inner.visit_u32() { return false; }
- self.bump_past::<u32>();
- true
- }
-
- fn visit_u64(&self) -> bool {
- self.align_to::<u64>();
- if ! self.inner.visit_u64() { return false; }
- self.bump_past::<u64>();
- true
- }
-
- fn visit_float(&self) -> bool {
- self.align_to::<float>();
- if ! self.inner.visit_float() { return false; }
- self.bump_past::<float>();
- true
- }
-
- fn visit_f32(&self) -> bool {
- self.align_to::<f32>();
- if ! self.inner.visit_f32() { return false; }
- self.bump_past::<f32>();
- true
- }
-
- fn visit_f64(&self) -> bool {
- self.align_to::<f64>();
- if ! self.inner.visit_f64() { return false; }
- self.bump_past::<f64>();
- true
- }
-
- fn visit_char(&self) -> bool {
- self.align_to::<char>();
- if ! self.inner.visit_char() { return false; }
- self.bump_past::<char>();
- true
- }
-
- fn visit_estr_box(&self) -> bool {
- self.align_to::<@str>();
- if ! self.inner.visit_estr_box() { return false; }
- self.bump_past::<@str>();
- true
- }
-
- fn visit_estr_uniq(&self) -> bool {
- self.align_to::<~str>();
- if ! self.inner.visit_estr_uniq() { return false; }
- self.bump_past::<~str>();
- true
- }
-
- fn visit_estr_slice(&self) -> bool {
- self.align_to::<&'static str>();
- if ! self.inner.visit_estr_slice() { return false; }
- self.bump_past::<&'static str>();
- true
- }
-
- fn visit_estr_fixed(&self, n: uint,
- sz: uint,
- align: uint) -> bool {
- self.align(align);
- if ! self.inner.visit_estr_fixed(n, sz, align) { return false; }
- self.bump(sz);
- true
- }
-
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<@u8>();
- if ! self.inner.visit_box(mtbl, inner) { return false; }
- self.bump_past::<@u8>();
- true
- }
-
- fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~u8>();
- if ! self.inner.visit_uniq(mtbl, inner) { return false; }
- self.bump_past::<~u8>();
- true
- }
-
- fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~u8>();
- if ! self.inner.visit_uniq_managed(mtbl, inner) { return false; }
- self.bump_past::<~u8>();
- true
- }
-
- fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<*u8>();
- if ! self.inner.visit_ptr(mtbl, inner) { return false; }
- self.bump_past::<*u8>();
- true
- }
-
- fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<&'static u8>();
- if ! self.inner.visit_rptr(mtbl, inner) { return false; }
- self.bump_past::<&'static u8>();
- true
- }
-
- fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<raw::Vec<()>>();
- if ! self.inner.visit_vec(mtbl, inner) { return false; }
- true
- }
-
- fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~[u8]>();
- if ! self.inner.visit_vec(mtbl, inner) { return false; }
- self.bump_past::<~[u8]>();
- true
- }
-
- fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<@[u8]>();
- if ! self.inner.visit_evec_box(mtbl, inner) { return false; }
- self.bump_past::<@[u8]>();
- true
- }
-
- fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~[u8]>();
- if ! self.inner.visit_evec_uniq(mtbl, inner) { return false; }
- self.bump_past::<~[u8]>();
- true
- }
-
- fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<~[@u8]>();
- if ! self.inner.visit_evec_uniq_managed(mtbl, inner) { return false; }
- self.bump_past::<~[@u8]>();
- true
- }
-
- fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.align_to::<&'static [u8]>();
- if ! self.inner.visit_evec_slice(mtbl, inner) { return false; }
- self.bump_past::<&'static [u8]>();
- true
- }
-
- fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
- mtbl: uint, inner: *TyDesc) -> bool {
- self.align(align);
- if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) {
- return false;
- }
- self.bump(sz);
- true
- }
-
- fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
- self.align(align);
- if ! self.inner.visit_enter_rec(n_fields, sz, align) { return false; }
- true
- }
-
- fn visit_rec_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool {
- unsafe { self.align((*inner).align); }
- if ! self.inner.visit_rec_field(i, name, mtbl, inner) {
- return false;
- }
- unsafe { self.bump((*inner).size); }
- true
- }
-
- fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
- if ! self.inner.visit_leave_rec(n_fields, sz, align) { return false; }
- true
- }
-
- fn visit_enter_class(&self, n_fields: uint, sz: uint, align: uint)
- -> bool {
- self.align(align);
- if ! self.inner.visit_enter_class(n_fields, sz, align) {
- return false;
- }
- true
- }
-
- fn visit_class_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool {
- unsafe { self.align((*inner).align); }
- if ! self.inner.visit_class_field(i, name, mtbl, inner) {
- return false;
- }
- unsafe { self.bump((*inner).size); }
- true
- }
-
- fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
- -> bool {
- if ! self.inner.visit_leave_class(n_fields, sz, align) {
- return false;
- }
- true
- }
-
- fn visit_enter_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
- self.align(align);
- if ! self.inner.visit_enter_tup(n_fields, sz, align) { return false; }
- true
- }
-
- fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
- unsafe { self.align((*inner).align); }
- if ! self.inner.visit_tup_field(i, inner) { return false; }
- unsafe { self.bump((*inner).size); }
- true
- }
-
- fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
- if ! self.inner.visit_leave_tup(n_fields, sz, align) { return false; }
- true
- }
-
- fn visit_enter_fn(&self, purity: uint, proto: uint,
- n_inputs: uint, retstyle: uint) -> bool {
- if ! self.inner.visit_enter_fn(purity, proto, n_inputs, retstyle) {
- return false
- }
- true
- }
-
- fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool {
- if ! self.inner.visit_fn_input(i, mode, inner) { return false; }
- true
- }
-
- fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool {
- if ! self.inner.visit_fn_output(retstyle, inner) { return false; }
- true
- }
-
- fn visit_leave_fn(&self, purity: uint, proto: uint,
- n_inputs: uint, retstyle: uint) -> bool {
- if ! self.inner.visit_leave_fn(purity, proto, n_inputs, retstyle) {
- return false;
- }
- true
- }
-
- fn visit_enter_enum(&self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- sz: uint, align: uint)
- -> bool {
- self.align(align);
- if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) {
- return false;
- }
- true
- }
-
- fn visit_enter_enum_variant(&self, variant: uint,
- disr_val: int,
- n_fields: uint,
- name: &str) -> bool {
- if ! self.inner.visit_enter_enum_variant(variant, disr_val,
- n_fields, name) {
- return false;
- }
- true
- }
-
- fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
- self.inner.push_ptr();
- self.bump(offset);
- if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
- self.inner.pop_ptr();
- true
- }
-
- fn visit_leave_enum_variant(&self, variant: uint,
- disr_val: int,
- n_fields: uint,
- name: &str) -> bool {
- if ! self.inner.visit_leave_enum_variant(variant, disr_val,
- n_fields, name) {
- return false;
- }
- true
- }
-
- fn visit_leave_enum(&self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- sz: uint, align: uint) -> bool {
- if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
- return false;
- }
- self.bump(sz);
- true
- }
-
- fn visit_trait(&self) -> bool {
- self.align_to::<@TyVisitor>();
- if ! self.inner.visit_trait() { return false; }
- self.bump_past::<@TyVisitor>();
- true
- }
-
- fn visit_param(&self, i: uint) -> bool {
- if ! self.inner.visit_param(i) { return false; }
- true
- }
-
- fn visit_self(&self) -> bool {
- self.align_to::<&'static u8>();
- if ! self.inner.visit_self() { return false; }
- self.align_to::<&'static u8>();
- true
- }
-
- fn visit_type(&self) -> bool {
- if ! self.inner.visit_type() { return false; }
- true
- }
-
- fn visit_opaque_box(&self) -> bool {
- self.align_to::<@u8>();
- if ! self.inner.visit_opaque_box() { return false; }
- self.bump_past::<@u8>();
- true
- }
-
- fn visit_closure_ptr(&self, ck: uint) -> bool {
- self.align_to::<@fn()>();
- if ! self.inner.visit_closure_ptr(ck) { return false; }
- self.bump_past::<@fn()>();
- true
- }
-}
+++ /dev/null
-// 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.
-
-/*!
-
-More runtime type reflection
-
-*/
-
-#[allow(missing_doc)];
-
-use cast::transmute;
-use char;
-use container::Container;
-use io::{Writer, WriterUtil};
-use iter::Iterator;
-use libc::c_void;
-use option::{Some, None};
-use ptr;
-use reflect;
-use reflect::{MovePtr, align};
-use str::StrSlice;
-use to_str::ToStr;
-use vec::OwnedVector;
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
-use unstable::raw;
-
-#[cfg(test)] use io;
-
-/// Helpers
-
-trait EscapedCharWriter {
- fn write_escaped_char(&self, ch: char);
-}
-
-impl EscapedCharWriter for @Writer {
- fn write_escaped_char(&self, ch: char) {
- match ch {
- '\t' => self.write_str("\\t"),
- '\r' => self.write_str("\\r"),
- '\n' => self.write_str("\\n"),
- '\\' => self.write_str("\\\\"),
- '\'' => self.write_str("\\'"),
- '"' => self.write_str("\\\""),
- '\x20'..'\x7e' => self.write_char(ch),
- _ => {
- do char::escape_unicode(ch) |c| {
- self.write_char(c);
- }
- }
- }
- }
-}
-
-/// Representations
-
-trait Repr {
- fn write_repr(&self, writer: @Writer);
-}
-
-impl Repr for () {
- fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
-}
-
-impl Repr for bool {
- fn write_repr(&self, writer: @Writer) {
- writer.write_str(if *self { "true" } else { "false" })
- }
-}
-
-macro_rules! int_repr(($ty:ident) => (impl Repr for $ty {
- fn write_repr(&self, writer: @Writer) {
- do ::$ty::to_str_bytes(*self, 10u) |bits| {
- writer.write(bits);
- }
- }
-}))
-
-int_repr!(int)
-int_repr!(i8)
-int_repr!(i16)
-int_repr!(i32)
-int_repr!(i64)
-int_repr!(uint)
-int_repr!(u8)
-int_repr!(u16)
-int_repr!(u32)
-int_repr!(u64)
-
-macro_rules! num_repr(($ty:ident) => (impl Repr for $ty {
- fn write_repr(&self, writer: @Writer) {
- let s = self.to_str();
- writer.write(s.as_bytes());
- }
-}))
-
-num_repr!(float)
-num_repr!(f32)
-num_repr!(f64)
-
-// New implementation using reflect::MovePtr
-
-enum VariantState {
- SearchingFor(int),
- Matched,
- AlreadyFound
-}
-
-pub struct ReprVisitor {
- ptr: @mut *c_void,
- ptr_stk: @mut ~[*c_void],
- var_stk: @mut ~[VariantState],
- writer: @Writer
-}
-pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
- ReprVisitor {
- ptr: @mut ptr,
- ptr_stk: @mut ~[],
- var_stk: @mut ~[],
- writer: writer,
- }
-}
-
-impl MovePtr for ReprVisitor {
- #[inline]
- fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
- *self.ptr = adjustment(*self.ptr);
- }
- fn push_ptr(&self) {
- self.ptr_stk.push(*self.ptr);
- }
- fn pop_ptr(&self) {
- *self.ptr = self.ptr_stk.pop();
- }
-}
-
-impl ReprVisitor {
- // Various helpers for the TyVisitor impl
-
- #[inline]
- pub fn get<T>(&self, f: &fn(&T)) -> bool {
- unsafe {
- f(transmute::<*c_void,&T>(*self.ptr));
- }
- true
- }
-
- #[inline]
- pub fn visit_inner(&self, inner: *TyDesc) -> bool {
- self.visit_ptr_inner(*self.ptr, inner)
- }
-
- #[inline]
- pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
- unsafe {
- let u = ReprVisitor(ptr, self.writer);
- let v = reflect::MovePtrAdaptor(u);
- visit_tydesc(inner, @v as @TyVisitor);
- true
- }
- }
-
- #[inline]
- pub fn write<T:Repr>(&self) -> bool {
- do self.get |v:&T| {
- v.write_repr(self.writer);
- }
- }
-
- pub fn write_escaped_slice(&self, slice: &str) {
- self.writer.write_char('"');
- for ch in slice.iter() {
- self.writer.write_escaped_char(ch);
- }
- self.writer.write_char('"');
- }
-
- pub fn write_mut_qualifier(&self, mtbl: uint) {
- if mtbl == 0 {
- self.writer.write_str("mut ");
- } else if mtbl == 1 {
- // skip, this is ast::m_imm
- } else {
- assert_eq!(mtbl, 2);
- self.writer.write_str("const ");
- }
- }
-
- pub fn write_vec_range(&self,
- _mtbl: uint,
- ptr: *(),
- len: uint,
- inner: *TyDesc)
- -> bool {
- let mut p = ptr as *u8;
- let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
- self.writer.write_char('[');
- let mut first = true;
- let mut left = len;
- // unit structs have 0 size, and don't loop forever.
- let dec = if sz == 0 {1} else {sz};
- while left > 0 {
- if first {
- first = false;
- } else {
- self.writer.write_str(", ");
- }
- self.visit_ptr_inner(p as *c_void, inner);
- unsafe {
- p = align(ptr::offset(p, sz as int) as uint, al) as *u8;
- }
- left -= dec;
- }
- self.writer.write_char(']');
- true
- }
-
- pub fn write_unboxed_vec_repr(&self,
- mtbl: uint,
- v: &raw::Vec<()>,
- inner: *TyDesc)
- -> bool {
- self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
- v.fill, inner)
- }
-}
-
-impl TyVisitor for ReprVisitor {
- fn visit_bot(&self) -> bool {
- self.writer.write_str("!");
- true
- }
- fn visit_nil(&self) -> bool { self.write::<()>() }
- fn visit_bool(&self) -> bool { self.write::<bool>() }
- fn visit_int(&self) -> bool { self.write::<int>() }
- fn visit_i8(&self) -> bool { self.write::<i8>() }
- fn visit_i16(&self) -> bool { self.write::<i16>() }
- fn visit_i32(&self) -> bool { self.write::<i32>() }
- fn visit_i64(&self) -> bool { self.write::<i64>() }
-
- fn visit_uint(&self) -> bool { self.write::<uint>() }
- fn visit_u8(&self) -> bool { self.write::<u8>() }
- fn visit_u16(&self) -> bool { self.write::<u16>() }
- fn visit_u32(&self) -> bool { self.write::<u32>() }
- fn visit_u64(&self) -> bool { self.write::<u64>() }
-
- fn visit_float(&self) -> bool { self.write::<float>() }
- fn visit_f32(&self) -> bool { self.write::<f32>() }
- fn visit_f64(&self) -> bool { self.write::<f64>() }
-
- fn visit_char(&self) -> bool {
- do self.get::<char> |&ch| {
- self.writer.write_char('\'');
- self.writer.write_escaped_char(ch);
- self.writer.write_char('\'');
- }
- }
-
- fn visit_estr_box(&self) -> bool {
- do self.get::<@str> |s| {
- self.writer.write_char('@');
- self.write_escaped_slice(*s);
- }
- }
- fn visit_estr_uniq(&self) -> bool {
- do self.get::<~str> |s| {
- self.writer.write_char('~');
- self.write_escaped_slice(*s);
- }
- }
- fn visit_estr_slice(&self) -> bool {
- do self.get::<&str> |s| {
- self.write_escaped_slice(*s);
- }
- }
-
- // Type no longer exists, vestigial function.
- fn visit_estr_fixed(&self, _n: uint, _sz: uint,
- _align: uint) -> bool { fail!(); }
-
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('@');
- self.write_mut_qualifier(mtbl);
- do self.get::<&raw::Box<()>> |b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, inner);
- }
- }
-
- fn visit_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('~');
- do self.get::<*c_void> |b| {
- self.visit_ptr_inner(*b, inner);
- }
- }
-
- fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('~');
- do self.get::<&raw::Box<()>> |b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, inner);
- }
- }
-
- fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
- do self.get::<*c_void> |p| {
- self.writer.write_str(fmt!("(0x%x as *())",
- *p as uint));
- }
- }
-
- fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('&');
- self.write_mut_qualifier(mtbl);
- do self.get::<*c_void> |p| {
- self.visit_ptr_inner(*p, inner);
- }
- }
-
- // Type no longer exists, vestigial function.
- fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
-
-
- fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<raw::Vec<()>> |b| {
- self.write_unboxed_vec_repr(mtbl, b, inner);
- }
- }
-
- fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<&raw::Box<raw::Vec<()>>> |b| {
- self.writer.write_char('@');
- self.write_mut_qualifier(mtbl);
- self.write_unboxed_vec_repr(mtbl, &b.data, inner);
- }
- }
-
- fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<&raw::Vec<()>> |b| {
- self.writer.write_char('~');
- self.write_unboxed_vec_repr(mtbl, *b, inner);
- }
- }
-
- fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<&raw::Box<raw::Vec<()>>> |b| {
- self.writer.write_char('~');
- self.write_unboxed_vec_repr(mtbl, &b.data, inner);
- }
- }
-
- fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<raw::Slice<()>> |s| {
- self.writer.write_char('&');
- self.write_vec_range(mtbl, s.data, s.len, inner);
- }
- }
-
- fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
- mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<()> |b| {
- self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
- }
- }
-
- fn visit_enter_rec(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- self.writer.write_char('{');
- true
- }
-
- fn visit_rec_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool {
- if i != 0 {
- self.writer.write_str(", ");
- }
- self.write_mut_qualifier(mtbl);
- self.writer.write_str(name);
- self.writer.write_str(": ");
- self.visit_inner(inner);
- true
- }
-
- fn visit_leave_rec(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- self.writer.write_char('}');
- true
- }
-
- fn visit_enter_class(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- self.writer.write_char('{');
- true
- }
- fn visit_class_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool {
- if i != 0 {
- self.writer.write_str(", ");
- }
- self.write_mut_qualifier(mtbl);
- self.writer.write_str(name);
- self.writer.write_str(": ");
- self.visit_inner(inner);
- true
- }
- fn visit_leave_class(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- self.writer.write_char('}');
- true
- }
-
- fn visit_enter_tup(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- self.writer.write_char('(');
- true
- }
- fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
- if i != 0 {
- self.writer.write_str(", ");
- }
- self.visit_inner(inner);
- true
- }
- fn visit_leave_tup(&self, _n_fields: uint,
- _sz: uint, _align: uint) -> bool {
- if _n_fields == 1 {
- self.writer.write_char(',');
- }
- self.writer.write_char(')');
- true
- }
-
- fn visit_enter_enum(&self,
- _n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- _sz: uint,
- _align: uint) -> bool {
- let var_stk: &mut ~[VariantState] = self.var_stk;
- let disr = unsafe {
- get_disr(transmute(*self.ptr))
- };
- var_stk.push(SearchingFor(disr));
- true
- }
-
- fn visit_enter_enum_variant(&self, _variant: uint,
- disr_val: int,
- n_fields: uint,
- name: &str) -> bool {
- let mut write = false;
- match self.var_stk.pop() {
- SearchingFor(sought) => {
- if disr_val == sought {
- self.var_stk.push(Matched);
- write = true;
- } else {
- self.var_stk.push(SearchingFor(sought));
- }
- }
- Matched | AlreadyFound => {
- self.var_stk.push(AlreadyFound);
- }
- }
-
- if write {
- self.writer.write_str(name);
- if n_fields > 0 {
- self.writer.write_char('(');
- }
- }
- true
- }
-
- fn visit_enum_variant_field(&self,
- i: uint,
- _offset: uint,
- inner: *TyDesc)
- -> bool {
- match self.var_stk[self.var_stk.len() - 1] {
- Matched => {
- if i != 0 {
- self.writer.write_str(", ");
- }
- if ! self.visit_inner(inner) {
- return false;
- }
- }
- _ => ()
- }
- true
- }
-
- fn visit_leave_enum_variant(&self, _variant: uint,
- _disr_val: int,
- n_fields: uint,
- _name: &str) -> bool {
- match self.var_stk[self.var_stk.len() - 1] {
- Matched => {
- if n_fields > 0 {
- self.writer.write_char(')');
- }
- }
- _ => ()
- }
- true
- }
-
- fn visit_leave_enum(&self,
- _n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- _sz: uint,
- _align: uint)
- -> bool {
- let var_stk: &mut ~[VariantState] = self.var_stk;
- match var_stk.pop() {
- SearchingFor(*) => fail!("enum value matched no variant"),
- _ => true
- }
- }
-
- fn visit_enter_fn(&self, _purity: uint, _proto: uint,
- _n_inputs: uint, _retstyle: uint) -> bool { true }
- fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
- true
- }
- fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
- true
- }
- fn visit_leave_fn(&self, _purity: uint, _proto: uint,
- _n_inputs: uint, _retstyle: uint) -> bool { true }
-
-
- fn visit_trait(&self) -> bool { true }
- fn visit_param(&self, _i: uint) -> bool { true }
- fn visit_self(&self) -> bool { true }
- fn visit_type(&self) -> bool { true }
-
- fn visit_opaque_box(&self) -> bool {
- self.writer.write_char('@');
- do self.get::<&raw::Box<()>> |b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, b.type_desc);
- }
- }
-
- fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
-}
-
-pub fn write_repr<T>(writer: @Writer, object: &T) {
- unsafe {
- let ptr = ptr::to_unsafe_ptr(object) as *c_void;
- let tydesc = get_tydesc::<T>();
- let u = ReprVisitor(ptr, writer);
- let v = reflect::MovePtrAdaptor(u);
- visit_tydesc(tydesc, @v as @TyVisitor)
- }
-}
-
-#[cfg(test)]
-struct P {a: int, b: float}
-
-#[test]
-fn test_repr() {
-
- fn exact_test<T>(t: &T, e:&str) {
- let s : &str = io::with_str_writer(|w| write_repr(w, t));
- if s != e {
- error!("expected '%s', got '%s'",
- e, s);
- }
- assert_eq!(s, e);
- }
-
- exact_test(&10, "10");
- exact_test(&true, "true");
- exact_test(&false, "false");
- exact_test(&1.234, "1.234");
- exact_test(&(&"hello"), "\"hello\"");
- exact_test(&(@"hello"), "@\"hello\"");
- exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
-
- exact_test(&(@10), "@10");
- exact_test(&(@mut 10), "@10"); // FIXME: #4210: incorrect
- exact_test(&((@mut 10, 2)), "(@mut 10, 2)");
- exact_test(&(~10), "~10");
- exact_test(&(&10), "&10");
- let mut x = 10;
- exact_test(&(&mut x), "&mut 10");
- exact_test(&(@mut [1, 2]), "@mut [1, 2]");
-
- exact_test(&(1,), "(1,)");
- exact_test(&(@[1,2,3,4,5,6,7,8]),
- "@[1, 2, 3, 4, 5, 6, 7, 8]");
- exact_test(&(@[1u8,2u8,3u8,4u8]),
- "@[1, 2, 3, 4]");
- exact_test(&(@["hi", "there"]),
- "@[\"hi\", \"there\"]");
- exact_test(&(~["hi", "there"]),
- "~[\"hi\", \"there\"]");
- exact_test(&(&["hi", "there"]),
- "&[\"hi\", \"there\"]");
- exact_test(&(P{a:10, b:1.234}),
- "{a: 10, b: 1.234}");
- exact_test(&(@P{a:10, b:1.234}),
- "@{a: 10, b: 1.234}");
- exact_test(&(~P{a:10, b:1.234}),
- "~{a: 10, b: 1.234}");
- exact_test(&(10_u8, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u16, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u32, ~"hello"),
- "(10, ~\"hello\")");
- exact_test(&(10_u64, ~"hello"),
- "(10, ~\"hello\")");
-
- struct Foo;
- exact_test(&(~[Foo, Foo, Foo]), "~[{}, {}, {}]");
-}
}
}
- #[cfg(stage0)]
- mod macro_hack {
- #[macro_escape];
- macro_rules! externfn(
- (fn $name:ident () $(-> $ret_ty:ty),*) => (
- extern {
- fn $name() $(-> $ret_ty),*;
- }
- )
- )
- }
-
externfn!(fn rust_take_global_args_lock())
externfn!(fn rust_drop_global_args_lock())
externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
#[unsafe_destructor]
impl<T> Drop for ChanOne<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
if self.suppress_finalize { return }
unsafe {
#[unsafe_destructor]
impl<T> Drop for PortOne<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
if self.suppress_finalize { return }
unsafe {
/// Wraps a Writer and buffers output to it
///
-/// NOTE: `BufferedWriter` will NOT flush its buffer when dropped.
+/// Note that `BufferedWriter` will NOT flush its buffer when dropped.
pub struct BufferedWriter<W> {
priv inner: W,
priv buf: ~[u8],
/// Wraps a Stream and buffers input and output to and from it
///
-/// NOTE: `BufferedStream` will NOT flush its output buffer when dropped.
+/// Note that `BufferedStream` will NOT flush its output buffer when dropped.
// FIXME #9155 this should be a newtype struct
pub struct BufferedStream<S> {
priv inner: BufferedReader<InternalBufferedWriter<S>>
let start_len = buf.len();
let mut total_read = 0;
- buf.reserve_at_least(start_len + len);
+ buf.reserve_additional(len);
vec::raw::set_len(buf, start_len + len);
do (|| {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+/*! Synchronous File I/O
+
+This module provides a set of functions and traits for working
+with regular files & directories on a filesystem.
+
+At the top-level of the module are a set of freestanding functions,
+associated with various filesystem operations. They all operate
+on a `PathLike` object.
+
+All operations in this module, including those as part of `FileStream` et al
+block the task during execution. Most will raise `std::rt::io::{io_error,read_error}`
+conditions in the event of failure.
+
+Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When
+`use`'d alongside a value whose type implements them (A `std::path::Path` impl is
+a part of this module), they expose a set of functions for operations against
+a given file location, depending on whether the path already exists. Whenever
+possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their
+free function counterparts.
+*/
+
use prelude::*;
use super::support::PathLike;
use super::{Reader, Writer, Seek};
-use super::{SeekSet, SeekCur, SeekEnd, SeekStyle};
+use super::{SeekStyle,SeekSet, SeekCur, SeekEnd,
+ Open, Read, Write, Create, ReadWrite};
use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject};
use rt::io::{io_error, read_error, EndOfFile,
- FileMode, FileAccess, Open, Read, Create, ReadWrite};
+ FileMode, FileAccess, FileStat, IoError,
+ PathAlreadyExists, PathDoesntExist,
+ MismatchedFileTypeForOperation, ignore_io_error};
use rt::local::Local;
-use rt::test::*;
+use option::{Some, None};
+use path::Path;
+use super::super::test::*;
/// Open a file for reading/writing, as indicated by `path`.
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::open;
+/// use std::rt::io::{FileMode, FileAccess};
+///
+/// let p = &Path("/some/file/path.txt");
+///
+/// do io_error::cond.trap(|_| {
+/// // hoo-boy...
+/// }).inside {
+/// let stream = match open(p, Create, ReadWrite) {
+/// Some(s) => s,
+/// None => fail!("whoops! I'm sure this raised, anyways..");
+/// }
+/// // do some stuff with that stream
+///
+/// // the file stream will be closed at the end of this block
+/// }
+/// // ..
+///
+/// `FileMode` and `FileAccess` provide information about the permissions
+/// context in which a given stream is created. More information about them
+/// can be found in `std::rt::io`'s docs.
+///
+/// Note that, with this function, a `FileStream` is returned regardless of
+/// the access-limitations indicated by `FileAccess` (e.g. calling `write` on a
+/// `FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you
+/// desire a more-correctly-constrained interface to files, use the
+/// `{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo`
+///
+/// # Errors
+///
+/// This function will raise an `io_error` condition under a number of different circumstances,
+/// to include but not limited to:
+///
+/// * Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g.
+/// opening a non-existant file with `FileMode` or `Open`)
+/// * Attempting to open a file with a `FileAccess` that the user lacks permissions
+/// for
+/// * Filesystem-level errors (full disk, etc)
pub fn open<P: PathLike>(path: &P,
mode: FileMode,
access: FileAccess
}
}
-/// Unlink (remove) a file from the filesystem, as indicated
-/// by `path`.
+/// Unlink a file from the underlying filesystem.
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::unlink;
+///
+/// let p = &Path("/some/file/path.txt");
+/// unlink(p);
+/// // if we made it here without failing, then the
+/// // unlink operation was successful
+///
+/// Note that, just because an unlink call was successful, it is not
+/// guaranteed that a file is immediately deleted (e.g. depending on
+/// platform, other open file descriptors may prevent immediate removal)
+///
+/// # Errors
+///
+/// This function will raise an `io_error` condition if the user lacks permissions to
+/// remove the file or if some other filesystem-level error occurs
pub fn unlink<P: PathLike>(path: &P) {
let unlink_result = unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
}
}
-/// Abstraction representing *positional* access to a file. In this case,
-/// *positional* refers to it keeping an encounter *cursor* of where in the
-/// file a subsequent `read` or `write` will begin from. Users of a `FileStream`
-/// can `seek` to move the cursor to a given location *within the bounds of the
-/// file* and can ask to have the `FileStream` `tell` them the location, in
-/// bytes, of the cursor.
+/// Create a new, empty directory at the provided path
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::mkdir;
+///
+/// let p = &Path("/some/dir");
+/// mkdir(p);
+/// // If we got here, our directory exists! Horray!
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks permissions to make a
+/// new directory at the provided path, or if the directory already exists
+pub fn mkdir<P: PathLike>(path: &P) {
+ let mkdir_result = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).fs_mkdir(path)
+ };
+ match mkdir_result {
+ Ok(_) => (),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ }
+ }
+}
+
+/// Remove an existing, empty directory
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::rmdir;
+///
+/// let p = &Path("/some/dir");
+/// rmdir(p);
+/// // good riddance, you mean ol' directory
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks permissions to remove the
+/// directory at the provided path, or if the directory isn't empty
+pub fn rmdir<P: PathLike>(path: &P) {
+ let rmdir_result = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).fs_rmdir(path)
+ };
+ match rmdir_result {
+ Ok(_) => (),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ }
+ }
+}
+
+/// Get information on the file, directory, etc at the provided path
+///
+/// Given a `rt::io::support::PathLike`, query the file system to get
+/// information about a file, directory, etc.
+///
+/// Returns a `Some(std::rt::io::PathInfo)` on success
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::stat;
+///
+/// let p = &Path("/some/file/path.txt");
+///
+/// do io_error::cond.trap(|_| {
+/// // hoo-boy...
+/// }).inside {
+/// let info = match stat(p) {
+/// Some(s) => s,
+/// None => fail!("whoops! I'm sure this raised, anyways..");
+/// }
+/// if stat.is_file {
+/// // just imagine the possibilities ...
+/// }
+///
+/// // the file stream will be closed at the end of this block
+/// }
+/// // ..
+///
+/// # Errors
+///
+/// This call will raise an `io_error` condition if the user lacks the requisite
+/// permissions to perform a `stat` call on the given path or if there is no
+/// entry in the filesystem at the provided path.
+pub fn stat<P: PathLike>(path: &P) -> Option<FileStat> {
+ let open_result = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).fs_stat(path)
+ };
+ match open_result {
+ Ok(p) => {
+ Some(p)
+ },
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+}
+
+/// Retrieve a vector containing all entries within a provided directory
+///
+/// # Example
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::support::PathLike;
+/// use std::rt::io::file::readdir;
+///
+/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
+/// if dir.is_dir() {
+/// let contents = dir.readdir();
+/// for entry in contents.iter() {
+/// if entry.is_dir() { visit_dirs(entry, cb); }
+/// else { cb(entry); }
+/// }
+/// }
+/// else { fail!("nope"); }
+/// }
+///
+/// # Errors
+///
+/// Will raise an `io_error` condition if the provided `path` doesn't exist,
+/// the process lacks permissions to view the contents or if the `path` points
+/// at a non-directory file
+pub fn readdir<P: PathLike>(path: &P) -> Option<~[Path]> {
+ let readdir_result = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).fs_readdir(path, 0)
+ };
+ match readdir_result {
+ Ok(p) => {
+ Some(p)
+ },
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+}
+
+/// Constrained version of `FileStream` that only exposes read-specific operations.
///
-/// This abstraction is roughly modeled on the access workflow as represented
-/// by `open(2)`, `read(2)`, `write(2)` and friends.
+/// Can be retreived via `FileInfo.open_reader()`.
+pub struct FileReader { priv stream: FileStream }
+
+/// a `std::rt::io::Reader` trait impl for file I/O.
+impl Reader for FileReader {
+ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ self.stream.read(buf)
+ }
+
+ fn eof(&mut self) -> bool {
+ self.stream.eof()
+ }
+}
+
+/// a `std::rt::io::Seek` trait impl for file I/O.
+impl Seek for FileReader {
+ fn tell(&self) -> u64 {
+ self.stream.tell()
+ }
+
+ fn seek(&mut self, pos: i64, style: SeekStyle) {
+ self.stream.seek(pos, style);
+ }
+}
+
+/// Constrained version of `FileStream` that only exposes write-specific operations.
///
-/// The `open` and `unlink` static methods are provided to manage creation/removal
-/// of files. All other methods operatin on an instance of `FileStream`.
+/// Can be retreived via `FileInfo.open_writer()`.
+pub struct FileWriter { priv stream: FileStream }
+
+/// a `std::rt::io::Writer` trait impl for file I/O.
+impl Writer for FileWriter {
+ fn write(&mut self, buf: &[u8]) {
+ self.stream.write(buf);
+ }
+
+ fn flush(&mut self) {
+ self.stream.flush();
+ }
+}
+
+/// a `std::rt::io::Seek` trait impl for file I/O.
+impl Seek for FileWriter {
+ fn tell(&self) -> u64 {
+ self.stream.tell()
+ }
+
+ fn seek(&mut self, pos: i64, style: SeekStyle) {
+ self.stream.seek(pos, style);
+ }
+}
+
+/// Unconstrained file access type that exposes read and write operations
+///
+/// Can be retreived via `file::open()` and `FileInfo.open_stream()`.
+///
+/// # Errors
+///
+/// This type will raise an io_error condition if operations are attempted against
+/// it for which its underlying file descriptor was not configured at creation
+/// time, via the `FileAccess` parameter to `file::open()`.
+///
+/// For this reason, it is best to use the access-constrained wrappers that are
+/// exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`.
pub struct FileStream {
fd: ~RtioFileStream,
last_nread: int,
}
-impl FileStream {
-}
-
+/// a `std::rt::io::Reader` trait impl for file I/O.
impl Reader for FileStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.fd.read(buf) {
}
}
+/// a `std::rt::io::Writer` trait impl for file I/O.
impl Writer for FileStream {
fn write(&mut self, buf: &[u8]) {
match self.fd.write(buf) {
}
}
+/// a `std::rt::io:Seek` trait impl for file I/O.
impl Seek for FileStream {
fn tell(&self) -> u64 {
let res = self.fd.tell();
}
}
+/// Shared functionality between `FileInfo` and `DirectoryInfo`
+pub trait FileSystemInfo {
+ /// Get the filesystem path that this instance points at,
+ /// whether it is valid or not. In this way, it can be used to
+ /// to specify a path of a non-existent file which it
+ /// later creates
+ fn get_path<'a>(&'a self) -> &'a Path;
+
+ /// Get information on the file, directory, etc at the provided path
+ ///
+ /// Consult the `file::stat` documentation for more info.
+ ///
+ /// This call preserves identical runtime/error semantics with `file::stat`
+ fn stat(&self) -> Option<FileStat> {
+ stat(self.get_path())
+ }
+
+ /// Boolean value indicator whether the underlying file exists on the filesystem
+ ///
+ /// # Errors
+ ///
+ /// Will not raise a condition
+ fn exists(&self) -> bool {
+ match ignore_io_error(|| self.stat()) {
+ Some(_) => true,
+ None => false
+ }
+ }
+
+}
+
+/// Represents a file, whose underlying path may or may not be valid
+///
+/// # Example
+///
+/// * Check if a file exists, reading from it if so
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::file::{FileInfo, FileReader};
+///
+/// let f = &Path("/some/file/path.txt");
+/// if f.exists() {
+/// let reader = f.open_reader(Open);
+/// let mut mem = [0u8, 8*64000];
+/// reader.read(mem);
+/// // ...
+/// }
+///
+/// * Is the given path a file?
+///
+/// let f = get_file_path_from_wherever();
+/// match f.is_file() {
+/// true => doing_something_with_a_file(f),
+/// _ => {}
+/// }
+pub trait FileInfo : FileSystemInfo {
+ /// Whether the underlying implemention (be it a file path,
+ /// or something else) points at a "regular file" on the FS. Will return
+ /// false for paths to non-existent locations or directories or
+ /// other non-regular files (named pipes, etc).
+ ///
+ /// # Errors
+ ///
+ /// Will not raise a condition
+ fn is_file(&self) -> bool {
+ match ignore_io_error(|| self.stat()) {
+ Some(s) => s.is_file,
+ None => false
+ }
+ }
+
+ /// Attempts to open a regular file for reading/writing based
+ /// on provided inputs
+ ///
+ /// See `file::open` for more information on runtime semantics and error conditions
+ fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option<FileStream> {
+ match ignore_io_error(|| self.stat()) {
+ Some(s) => match s.is_file {
+ true => open(self.get_path(), mode, access),
+ false => None
+ },
+ None => open(self.get_path(), mode, access)
+ }
+ }
+
+ /// Attempts to open a regular file in read-only mode, based
+ /// on provided inputs
+ ///
+ /// See `file::open` for more information on runtime semantics and error conditions
+ fn open_reader(&self, mode: FileMode) -> Option<FileReader> {
+ match self.open_stream(mode, Read) {
+ Some(s) => Some(FileReader { stream: s}),
+ None => None
+ }
+ }
+
+ /// Attempts to open a regular file in write-only mode, based
+ /// on provided inputs
+ ///
+ /// See `file::open` for more information on runtime semantics and error conditions
+ fn open_writer(&self, mode: FileMode) -> Option<FileWriter> {
+ match self.open_stream(mode, Write) {
+ Some(s) => Some(FileWriter { stream: s}),
+ None => None
+ }
+ }
+
+ /// Attempt to remove a file from the filesystem
+ ///
+ /// See `file::unlink` for more information on runtime semantics and error conditions
+ fn unlink(&self) {
+ unlink(self.get_path());
+ }
+}
+
+/// `FileSystemInfo` implementation for `Path`s
+impl FileSystemInfo for Path {
+ fn get_path<'a>(&'a self) -> &'a Path { self }
+}
+
+/// `FileInfo` implementation for `Path`s
+impl FileInfo for Path { }
+
+/// Represents a directory, whose underlying path may or may not be valid
+///
+/// # Example
+///
+/// * Check if a directory exists, `mkdir`'ing it if not
+///
+/// use std;
+/// use std::path::Path;
+/// use std::rt::io::file::{DirectoryInfo};
+///
+/// let dir = &Path("/some/dir");
+/// if !dir.exists() {
+/// dir.mkdir();
+/// }
+///
+/// * Is the given path a directory? If so, iterate on its contents
+///
+/// fn visit_dirs(dir: &Path, cb: &fn(&Path)) {
+/// if dir.is_dir() {
+/// let contents = dir.readdir();
+/// for entry in contents.iter() {
+/// if entry.is_dir() { visit_dirs(entry, cb); }
+/// else { cb(entry); }
+/// }
+/// }
+/// else { fail!("nope"); }
+/// }
+trait DirectoryInfo : FileSystemInfo {
+ /// Whether the underlying implemention (be it a file path,
+ /// or something else) is pointing at a directory in the underlying FS.
+ /// Will return false for paths to non-existent locations or if the item is
+ /// not a directory (eg files, named pipes, links, etc)
+ ///
+ /// # Errors
+ ///
+ /// Will not raise a condition
+ fn is_dir(&self) -> bool {
+ match ignore_io_error(|| self.stat()) {
+ Some(s) => s.is_dir,
+ None => false
+ }
+ }
+
+ /// Create a directory at the location pointed to by the
+ /// type underlying the given `DirectoryInfo`.
+ ///
+ /// # Errors
+ ///
+ /// This method will raise a `PathAlreadyExists` kind of `io_error` condition
+ /// if the provided path exists
+ ///
+ /// See `file::mkdir` for more information on runtime semantics and error conditions
+ fn mkdir(&self) {
+ match ignore_io_error(|| self.stat()) {
+ Some(_) => {
+ io_error::cond.raise(IoError {
+ kind: PathAlreadyExists,
+ desc: "Path already exists",
+ detail:
+ Some(fmt!("%s already exists; can't mkdir it", self.get_path().to_str()))
+ })
+ },
+ None => mkdir(self.get_path())
+ }
+ }
+
+ /// Remove a directory at the given location.
+ ///
+ /// # Errors
+ ///
+ /// This method will raise a `PathDoesntExist` kind of `io_error` condition
+ /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation`
+ /// kind of `io_error` condition if the provided path points at any
+ /// non-directory file type
+ ///
+ /// See `file::rmdir` for more information on runtime semantics and error conditions
+ fn rmdir(&self) {
+ match ignore_io_error(|| self.stat()) {
+ Some(s) => {
+ match s.is_dir {
+ true => rmdir(self.get_path()),
+ false => {
+ let ioerr = IoError {
+ kind: MismatchedFileTypeForOperation,
+ desc: "Cannot do rmdir() on a non-directory",
+ detail: Some(fmt!(
+ "%s is a non-directory; can't rmdir it",
+ self.get_path().to_str()))
+ };
+ io_error::cond.raise(ioerr);
+ }
+ }
+ },
+ None =>
+ io_error::cond.raise(IoError {
+ kind: PathDoesntExist,
+ desc: "Path doesn't exist",
+ detail: Some(fmt!("%s doesn't exist; can't rmdir it", self.get_path().to_str()))
+ })
+ }
+ }
+
+ // Get a collection of all entries at the given
+ // directory
+ fn readdir(&self) -> Option<~[Path]> {
+ readdir(self.get_path())
+ }
+}
+
+/// `DirectoryInfo` impl for `path::Path`
+impl DirectoryInfo for Path { }
+
fn file_test_smoke_test_impl() {
do run_in_mt_newsched_task {
let message = "it's alright. have a good time";
}
#[test]
-#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_smoke_test() {
file_test_smoke_test_impl();
}
}
#[test]
-#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_non_positional_read() {
file_test_io_non_positional_read_impl();
}
assert!(tell_pos_post_read == message.len() as u64);
}
}
+
#[test]
-#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_and_tell_smoke_test() {
file_test_io_seeking_impl();
}
fn file_test_io_seek_and_write_impl() {
- use io;
do run_in_mt_newsched_task {
use str;
let initial_msg = "food-is-yummy";
}
unlink(filename);
let read_str = str::from_utf8(read_mem);
- io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg));
assert!(read_str == final_msg.to_owned());
}
}
+
#[test]
-#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_and_write() {
file_test_io_seek_and_write_impl();
}
unlink(filename);
}
}
+
#[test]
-#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_shakedown() {
file_test_io_seek_shakedown_impl();
}
+
+#[test]
+fn file_test_stat_is_correct_on_is_file() {
+ do run_in_mt_newsched_task {
+ let filename = &Path("./tmp/file_stat_correct_on_is_file.txt");
+ {
+ let mut fs = open(filename, Create, ReadWrite).unwrap();
+ let msg = "hw";
+ fs.write(msg.as_bytes());
+ }
+ let stat_res = match stat(filename) {
+ Some(s) => s,
+ None => fail!("shouldn't happen")
+ };
+ assert!(stat_res.is_file);
+ unlink(filename);
+ }
+}
+
+#[test]
+fn file_test_stat_is_correct_on_is_dir() {
+ do run_in_mt_newsched_task {
+ let filename = &Path("./tmp/file_stat_correct_on_is_dir");
+ mkdir(filename);
+ let stat_res = match stat(filename) {
+ Some(s) => s,
+ None => fail!("shouldn't happen")
+ };
+ assert!(stat_res.is_dir);
+ rmdir(filename);
+ }
+}
+
+#[test]
+fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
+ do run_in_mt_newsched_task {
+ let dir = &Path("./tmp/fileinfo_false_on_dir");
+ mkdir(dir);
+ assert!(dir.is_file() == false);
+ rmdir(dir);
+ }
+}
+
+#[test]
+fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
+ do run_in_mt_newsched_task {
+ let file = &Path("./tmp/fileinfo_check_exists_b_and_a.txt");
+ {
+ let msg = "foo".as_bytes();
+ let mut w = file.open_writer(Create);
+ w.write(msg);
+ }
+ assert!(file.exists());
+ file.unlink();
+ assert!(!file.exists());
+ }
+}
+
+#[test]
+fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
+ do run_in_mt_newsched_task {
+ let dir = &Path("./tmp/before_and_after_dir");
+ assert!(!dir.exists());
+ dir.mkdir();
+ assert!(dir.exists());
+ assert!(dir.is_dir());
+ dir.rmdir();
+ assert!(!dir.exists());
+ }
+}
+
+#[test]
+fn file_test_directoryinfo_readdir() {
+ use str;
+ do run_in_mt_newsched_task {
+ let dir = &Path("./tmp/di_readdir");
+ dir.mkdir();
+ let prefix = "foo";
+ for n in range(0,3) {
+ let f = dir.push(fmt!("%d.txt", n));
+ let mut w = f.open_writer(Create);
+ let msg_str = (prefix + n.to_str().to_owned()).to_owned();
+ let msg = msg_str.as_bytes();
+ w.write(msg);
+ }
+ match dir.readdir() {
+ Some(files) => {
+ let mut mem = [0u8, .. 4];
+ for f in files.iter() {
+ {
+ let n = f.filestem();
+ let mut r = f.open_reader(Open);
+ r.read(mem);
+ let read_str = str::from_utf8(mem);
+ let expected = match n {
+ Some(n) => prefix+n,
+ None => fail!("really shouldn't happen..")
+ };
+ assert!(expected == read_str);
+ }
+ f.unlink();
+ }
+ },
+ None => fail!("shouldn't happen")
+ }
+ dir.rmdir();
+ }
+}
\ No newline at end of file
use prelude::*;
use to_str::ToStr;
use str::{StrSlice, OwnedStr};
+use path::Path;
// Reexports
pub use self::stdio::stdin;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
pub use self::net::udp::UdpStream;
+pub use self::pipe::PipeStream;
+pub use self::pipe::UnboundPipeStream;
+pub use self::process::Process;
// Some extension traits that all Readers and Writers get.
pub use self::extensions::ReaderUtil;
/// Synchronous, non-blocking file I/O.
pub mod file;
+/// Synchronous, in-memory I/O.
+pub mod pipe;
+
+/// Child process management.
+pub mod process;
+
/// Synchronous, non-blocking network I/O.
pub mod net;
Closed,
ConnectionRefused,
ConnectionReset,
- BrokenPipe
+ BrokenPipe,
+ PathAlreadyExists,
+ PathDoesntExist,
+ MismatchedFileTypeForOperation
}
// FIXME: #8242 implementing manually because deriving doesn't work for some reason
Closed => ~"Closed",
ConnectionRefused => ~"ConnectionRefused",
ConnectionReset => ~"ConnectionReset",
- BrokenPipe => ~"BrokenPipe"
+ BrokenPipe => ~"BrokenPipe",
+ PathAlreadyExists => ~"PathAlreadyExists",
+ PathDoesntExist => ~"PathDoesntExist",
+ MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation"
}
}
}
// XXX: Can't put doc comments on macros
// Raised by `I/O` operations on error.
condition! {
- // NOTE: this super::IoError should be IoError
- // Change this next time the snapshot is updated.
- pub io_error: super::IoError -> ();
+ pub io_error: IoError -> ();
}
// XXX: Can't put doc comments on macros
// Raised by `read` on error
condition! {
- // NOTE: this super::IoError should be IoError
- // Change this next time the snapshot it updated.
- pub read_error: super::IoError -> ();
+ pub read_error: IoError -> ();
+}
+
+/// Helper for wrapper calls where you want to
+/// ignore any io_errors that might be raised
+pub fn ignore_io_error<T>(cb: &fn() -> T) -> T {
+ do io_error::cond.trap(|_| {
+ // just swallow the error.. downstream users
+ // who can make a decision based on a None result
+ // won't care
+ }).inside {
+ cb()
+ }
}
pub trait Reader {
Write,
ReadWrite
}
+
+pub struct FileStat {
+ /// A `Path` object containing information about the `PathInfo`'s location
+ path: Path,
+ /// `true` if the file pointed at by the `PathInfo` is a regular file
+ is_file: bool,
+ /// `true` if the file pointed at by the `PathInfo` is a directory
+ is_dir: bool,
+ /// The file pointed at by the `PathInfo`'s size in bytes
+ size: u64,
+ /// The file pointed at by the `PathInfo`'s creation time
+ created: u64,
+ /// The file pointed at by the `PathInfo`'s last-modification time in
+ /// platform-dependent msecs
+ modified: u64,
+ /// The file pointed at by the `PathInfo`'s last-accessd time (e.g. read) in
+ /// platform-dependent msecs
+ accessed: u64,
+}
}
#[test]
- #[ignore(cfg(windows))] // FIXME #8811
fn connect_error() {
do run_in_mt_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
- assert_eq!(e.kind, ConnectionRefused);
+ let expected_error = if cfg!(unix) {
+ ConnectionRefused
+ } else {
+ // On Win32, opening port 1 gives WSAEADDRNOTAVAIL error.
+ OtherIoError
+ };
+ assert_eq!(e.kind, expected_error);
called = true;
}).inside {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
--- /dev/null
+// 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.
+
+//! Synchronous, in-memory pipes.
+//!
+//! Currently these aren't particularly useful, there only exists bindings
+//! enough so that pipes can be created to child processes.
+
+use prelude::*;
+use super::{Reader, Writer};
+use rt::io::{io_error, read_error, EndOfFile};
+use rt::local::Local;
+use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory};
+use rt::rtio::RtioUnboundPipeObject;
+
+pub struct PipeStream(RtioPipeObject);
+pub struct UnboundPipeStream(~RtioUnboundPipeObject);
+
+impl PipeStream {
+ /// Creates a new pipe initialized, but not bound to any particular
+ /// source/destination
+ pub fn new() -> Option<UnboundPipeStream> {
+ let pipe = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).pipe_init(false)
+ };
+ match pipe {
+ Ok(p) => Some(UnboundPipeStream(p)),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+ }
+
+ pub fn bind(inner: RtioPipeObject) -> PipeStream {
+ PipeStream(inner)
+ }
+}
+
+impl Reader for PipeStream {
+ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
+ match (**self).read(buf) {
+ Ok(read) => Some(read),
+ Err(ioerr) => {
+ // EOF is indicated by returning None
+ if ioerr.kind != EndOfFile {
+ read_error::cond.raise(ioerr);
+ }
+ return None;
+ }
+ }
+ }
+
+ fn eof(&mut self) -> bool { fail!() }
+}
+
+impl Writer for PipeStream {
+ fn write(&mut self, buf: &[u8]) {
+ match (**self).write(buf) {
+ Ok(_) => (),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ }
+ }
+ }
+
+ fn flush(&mut self) { fail!() }
+}
--- /dev/null
+// 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.
+
+//! Bindings for executing child processes
+
+use prelude::*;
+
+use libc;
+use rt::io;
+use rt::io::io_error;
+use rt::local::Local;
+use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory};
+
+pub struct Process {
+ priv handle: ~RtioProcessObject,
+ io: ~[Option<io::PipeStream>],
+}
+
+/// This configuration describes how a new process should be spawned. This is
+/// translated to libuv's own configuration
+pub struct ProcessConfig<'self> {
+ /// Path to the program to run
+ program: &'self str,
+
+ /// Arguments to pass to the program (doesn't include the program itself)
+ args: &'self [~str],
+
+ /// Optional environment to specify for the program. If this is None, then
+ /// it will inherit the current process's environment.
+ env: Option<&'self [(~str, ~str)]>,
+
+ /// Optional working directory for the new process. If this is None, then
+ /// the current directory of the running process is inherited.
+ cwd: Option<&'self str>,
+
+ /// Any number of streams/file descriptors/pipes may be attached to this
+ /// process. This list enumerates the file descriptors and such for the
+ /// process to be spawned, and the file descriptors inherited will start at
+ /// 0 and go to the length of this array.
+ ///
+ /// Standard file descriptors are:
+ ///
+ /// 0 - stdin
+ /// 1 - stdout
+ /// 2 - stderr
+ io: ~[StdioContainer]
+}
+
+/// Describes what to do with a standard io stream for a child process.
+pub enum StdioContainer {
+ /// This stream will be ignored. This is the equivalent of attaching the
+ /// stream to `/dev/null`
+ Ignored,
+
+ /// The specified file descriptor is inherited for the stream which it is
+ /// specified for.
+ InheritFd(libc::c_int),
+
+ // XXX: these two shouldn't have libuv-specific implementation details
+
+ /// The specified libuv stream is inherited for the corresponding file
+ /// descriptor it is assigned to.
+ // XXX: this needs to be thought out more.
+ //InheritStream(uv::net::StreamWatcher),
+
+ /// Creates a pipe for the specified file descriptor which will be directed
+ /// into the previously-initialized pipe passed in.
+ ///
+ /// The first boolean argument is whether the pipe is readable, and the
+ /// second is whether it is writable. These properties are from the view of
+ /// the *child* process, not the parent process.
+ CreatePipe(io::UnboundPipeStream,
+ bool /* readable */,
+ bool /* writable */),
+}
+
+impl Process {
+ /// Creates a new pipe initialized, but not bound to any particular
+ /// source/destination
+ pub fn new(config: ProcessConfig) -> Option<Process> {
+ let process = unsafe {
+ let io: *mut IoFactoryObject = Local::unsafe_borrow();
+ (*io).spawn(config)
+ };
+ match process {
+ Ok((p, io)) => Some(Process{
+ handle: p,
+ io: io.move_iter().map(|p|
+ p.map_move(|p| io::PipeStream::bind(p))
+ ).collect()
+ }),
+ Err(ioerr) => {
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+ }
+
+ /// Returns the process id of this child process
+ pub fn id(&self) -> libc::pid_t { self.handle.id() }
+
+ /// Sends the specified signal to the child process, returning whether the
+ /// signal could be delivered or not.
+ ///
+ /// Note that this is purely a wrapper around libuv's `uv_process_kill`
+ /// function.
+ ///
+ /// If the signal delivery fails, then the `io_error` condition is raised on
+ pub fn signal(&mut self, signal: int) {
+ match self.handle.kill(signal) {
+ Ok(()) => {}
+ Err(err) => {
+ io_error::cond.raise(err)
+ }
+ }
+ }
+
+ /// Wait for the child to exit completely, returning the status that it
+ /// exited with. This function will continue to have the same return value
+ /// after it has been called at least once.
+ pub fn wait(&mut self) -> int { self.handle.wait() }
+}
+
+impl Drop for Process {
+ fn drop(&mut self) {
+ // Close all I/O before exiting to ensure that the child doesn't wait
+ // forever to print some text or something similar.
+ for _ in range(0, self.io.len()) {
+ self.io.pop();
+ }
+
+ self.wait();
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use prelude::*;
+ use super::*;
+
+ use rt::io::{Reader, Writer};
+ use rt::io::pipe::*;
+ use str;
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn smoke() {
+ let io = ~[];
+ let args = ProcessConfig {
+ program: "/bin/sh",
+ args: [~"-c", ~"true"],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ let p = Process::new(args);
+ assert!(p.is_some());
+ let mut p = p.unwrap();
+ assert_eq!(p.wait(), 0);
+ }
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn smoke_failure() {
+ let io = ~[];
+ let args = ProcessConfig {
+ program: "if-this-is-a-binary-then-the-world-has-ended",
+ args: [],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ let p = Process::new(args);
+ assert!(p.is_some());
+ let mut p = p.unwrap();
+ assert!(p.wait() != 0);
+ }
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn exit_reported_right() {
+ let io = ~[];
+ let args = ProcessConfig {
+ program: "/bin/sh",
+ args: [~"-c", ~"exit 1"],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ let p = Process::new(args);
+ assert!(p.is_some());
+ let mut p = p.unwrap();
+ assert_eq!(p.wait(), 1);
+ }
+
+ fn read_all(input: &mut Reader) -> ~str {
+ let mut ret = ~"";
+ let mut buf = [0, ..1024];
+ loop {
+ match input.read(buf) {
+ None | Some(0) => { break }
+ Some(n) => { ret = ret + str::from_utf8(buf.slice_to(n)); }
+ }
+ }
+ return ret;
+ }
+
+ fn run_output(args: ProcessConfig) -> ~str {
+ let p = Process::new(args);
+ assert!(p.is_some());
+ let mut p = p.unwrap();
+ assert!(p.io[0].is_none());
+ assert!(p.io[1].is_some());
+ let ret = read_all(p.io[1].get_mut_ref() as &mut Reader);
+ assert_eq!(p.wait(), 0);
+ return ret;
+ }
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn stdout_works() {
+ let pipe = PipeStream::new().unwrap();
+ let io = ~[Ignored, CreatePipe(pipe, false, true)];
+ let args = ProcessConfig {
+ program: "/bin/sh",
+ args: [~"-c", ~"echo foobar"],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ assert_eq!(run_output(args), ~"foobar\n");
+ }
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn set_cwd_works() {
+ let pipe = PipeStream::new().unwrap();
+ let io = ~[Ignored, CreatePipe(pipe, false, true)];
+ let cwd = Some("/");
+ let args = ProcessConfig {
+ program: "/bin/sh",
+ args: [~"-c", ~"pwd"],
+ env: None,
+ cwd: cwd,
+ io: io,
+ };
+ assert_eq!(run_output(args), ~"/\n");
+ }
+
+ #[test]
+ #[cfg(unix, not(android))]
+ fn stdin_works() {
+ let input = PipeStream::new().unwrap();
+ let output = PipeStream::new().unwrap();
+ let io = ~[CreatePipe(input, true, false),
+ CreatePipe(output, false, true)];
+ let args = ProcessConfig {
+ program: "/bin/sh",
+ args: [~"-c", ~"read line; echo $line"],
+ env: None,
+ cwd: None,
+ io: io,
+ };
+ let mut p = Process::new(args).expect("didn't create a proces?!");
+ p.io[0].get_mut_ref().write("foobar".as_bytes());
+ p.io[0] = None; // close stdin;
+ let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
+ assert_eq!(p.wait(), 0);
+ assert_eq!(out, ~"foobar\n");
+ }
+}
use super::PathLike;
#[test]
- #[ignore(cfg(windows))] // FIXME #8812
fn path_like_smoke_test() {
- let expected = "/home";
+ let expected = if cfg!(unix) { "/home" } else { "C:\\" };
let path = Path(expected);
path.path_as_str(|p| assert!(p == expected));
path.path_as_str(|p| assert!(p == expected));
impl Drop for KillFlag {
// Letting a KillFlag with a task inside get dropped would leak the task.
// We could free it here, but the task should get awoken by hand somehow.
- fn drop(&self) {
+ fn drop(&mut self) {
match self.load(Relaxed) {
KILL_RUNNING | KILL_KILLED => { },
_ => rtabort!("can't drop kill flag with a blocked task inside!"),
}
impl Drop for Death {
- fn drop(&self) {
+ fn drop(&mut self) {
// Mustn't be in an atomic or unkillable section at task death.
rtassert!(self.unkillable == 0);
rtassert!(self.wont_sleep == 0);
impl Drop for LocalHeap {
#[fixed_stack_segment] #[inline(never)]
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);
rust_delete_memory_region(self.memory_region);
return exit_code;
}
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
- (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
- extern {
- fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
- }
- )
-)
-}
-
/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
#[unsafe_destructor]
impl<T> Drop for RC<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
assert!(self.refcount() > 0);
unsafe {
- // FIXME(#4330) Need self by value to get mutability.
- let this: &mut RC<T> = cast::transmute_mut(self);
-
- match *this.get_mut_state() {
+ match *self.get_mut_state() {
(ref mut count, _) => {
*count = *count - 1
}
}
- if this.refcount() == 0 {
- let _: ~(uint, T) = cast::transmute(this.p);
+ if self.refcount() == 0 {
+ let _: ~(uint, T) = cast::transmute(self.p);
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use libc;
use option::*;
use result::*;
use libc::c_int;
use rt::io::IoError;
+use super::io::process::ProcessConfig;
use super::io::net::ip::{IpAddr, SocketAddr};
use rt::uv::uvio;
use path::Path;
use super::io::support::PathLike;
use super::io::{SeekStyle};
-use super::io::{FileMode, FileAccess};
+use super::io::{FileMode, FileAccess, FileStat};
// XXX: ~object doesn't work currently so these are some placeholder
// types to use instead
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
pub type RtioTimerObject = uvio::UvTimer;
pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
+pub type RtioPipeObject = uvio::UvPipeStream;
+pub type RtioUnboundPipeObject = uvio::UvUnboundPipe;
+pub type RtioProcessObject = uvio::UvProcess;
pub trait EventLoop {
fn run(&mut self);
-> Result<~RtioFileStream, IoError>;
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
+ fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>;
+ fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+ fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
+ fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
+ Result<~[Path], IoError>;
+ fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>;
+ fn spawn(&mut self, config: ProcessConfig)
+ -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn tell(&self) -> Result<u64, IoError>;
fn flush(&mut self) -> Result<(), IoError>;
}
+
+pub trait RtioProcess {
+ fn id(&self) -> libc::pid_t;
+ fn kill(&mut self, signal: int) -> Result<(), IoError>;
+ fn wait(&mut self) -> int;
+}
+
+pub trait RtioPipe {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
+}
struct S { field: () }
impl Drop for S {
- fn drop(&self) {
- let _foo = @0;
+ fn drop(&mut self) {
+ let _foo = @0;
}
}
let s = S { field: () };
do spawntask {
- let _ss = &s;
+ let _ss = &s;
}
}
}
}
impl Drop for StackSegment {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
unsafe {
}
impl Drop for Task {
- fn drop(&self) {
+ fn drop(&mut self) {
rtdebug!("called drop for a task: %u", borrow::to_uint(self));
rtassert!(self.destroyed)
}
}
extern {
- #[cfg(not(stage0))]
#[rust_stack]
fn rust_try(f: extern "C" fn(*c_void, *c_void),
code: *c_void,
data: *c_void) -> uintptr_t;
-
- #[cfg(stage0)]
- #[rust_stack]
- fn rust_try(f: *u8,
- code: *c_void,
- data: *c_void) -> uintptr_t;
}
}
fn tls() {
use local_data;
do run_in_newsched_task() {
- static key: local_data::Key<@~str> = &local_data::Key;
+ local_data_key!(key: @~str)
local_data::set(key, @~"data");
assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data");
- static key2: local_data::Key<@~str> = &local_data::Key;
+ local_data_key!(key2: @~str)
local_data::set(key2, @~"data");
assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data");
}
}
impl Drop for Thread {
- fn drop(&self) {
+ fn drop(&mut self) {
#[fixed_stack_segment]; #[inline(never)];
assert!(self.joined);
use rt::uv::uvll::*;
use super::super::io::support::PathLike;
use cast::transmute;
+use libc;
use libc::{c_int};
use option::{None, Some, Option};
impl Request for FsRequest;
pub struct RequestData {
- complete_cb: Option<FsCallback>,
- raw_fd: Option<c_int>
+ complete_cb: Option<FsCallback>
}
impl FsRequest {
- pub fn new(cb: Option<FsCallback>) -> FsRequest {
+ pub fn new() -> FsRequest {
let fs_req = unsafe { malloc_req(UV_FS) };
assert!(fs_req.is_not_null());
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
- fs_req.install_req_data(cb);
fs_req
}
- fn open_common<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
- cb: Option<FsCallback>) -> int {
- let complete_cb_ptr = match cb {
- Some(_) => compl_cb as *u8,
- None => 0 as *u8
+ pub fn open<P: PathLike>(self, loop_: &Loop, path: &P, flags: int, mode: int,
+ cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
};
- let is_sync = cb.is_none();
- let req = FsRequest::new(cb);
- let result = path.path_as_str(|p| {
+ path.path_as_str(|p| {
p.to_c_str().with_ref(|p| unsafe {
uvll::fs_open(loop_.native_handle(),
- req.native_handle(), p, flags, mode, complete_cb_ptr) as int
+ self.native_handle(), p, flags, mode, complete_cb_ptr)
})
});
- if is_sync { req.cleanup_and_delete(); }
- result
}
- pub fn open<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int,
- cb: FsCallback) {
- FsRequest::open_common(loop_, path, flags, mode, Some(cb));
+
+ pub fn open_sync<P: PathLike>(self, loop_: &Loop, path: &P,
+ flags: int, mode: int) -> Result<c_int, UvError> {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(None)
+ };
+ let result = path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_open(loop_.native_handle(),
+ self.native_handle(), p, flags, mode, complete_cb_ptr)
+ })
+ });
+ self.sync_cleanup(result)
}
- pub fn open_sync<P: PathLike>(loop_: &Loop, path: &P, flags: int, mode: int)
- -> Result<int, UvError> {
- let result = FsRequest::open_common(loop_, path, flags, mode, None);
- sync_cleanup(result)
+ pub fn unlink<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_unlink(loop_.native_handle(),
+ self.native_handle(), p, complete_cb_ptr)
+ })
+ });
}
- fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
- let complete_cb_ptr = match cb {
- Some(_) => compl_cb as *u8,
- None => 0 as *u8
+ pub fn unlink_sync<P: PathLike>(self, loop_: &Loop, path: &P)
+ -> Result<c_int, UvError> {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(None)
};
- let is_sync = cb.is_none();
- let req = FsRequest::new(cb);
let result = path.path_as_str(|p| {
p.to_c_str().with_ref(|p| unsafe {
uvll::fs_unlink(loop_.native_handle(),
- req.native_handle(), p, complete_cb_ptr) as int
+ self.native_handle(), p, complete_cb_ptr)
})
});
- if is_sync { req.cleanup_and_delete(); }
- result
+ self.sync_cleanup(result)
+ }
+
+ pub fn stat<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_stat(loop_.native_handle(),
+ self.native_handle(), p, complete_cb_ptr)
+ })
+ });
+ }
+
+ pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ let base_ptr = buf.base as *c_void;
+ let len = buf.len as uint;
+ unsafe {
+ uvll::fs_write(loop_.native_handle(), self.native_handle(),
+ fd, base_ptr,
+ len, offset, complete_cb_ptr)
+ };
}
- pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
- let result = FsRequest::unlink_common(loop_, path, Some(cb));
- sync_cleanup(result);
+ pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
+ -> Result<c_int, UvError> {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(None)
+ };
+ let base_ptr = buf.base as *c_void;
+ let len = buf.len as uint;
+ let result = unsafe {
+ uvll::fs_write(loop_.native_handle(), self.native_handle(),
+ fd, base_ptr,
+ len, offset, complete_cb_ptr)
+ };
+ self.sync_cleanup(result)
+ }
+
+ pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ let buf_ptr = buf.base as *c_void;
+ let len = buf.len as uint;
+ unsafe {
+ uvll::fs_read(loop_.native_handle(), self.native_handle(),
+ fd, buf_ptr,
+ len, offset, complete_cb_ptr)
+ };
}
- pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
- let result = FsRequest::unlink_common(loop_, path, None);
- sync_cleanup(result)
+ pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
+ -> Result<c_int, UvError> {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(None)
+ };
+ let buf_ptr = buf.base as *c_void;
+ let len = buf.len as uint;
+ let result = unsafe {
+ uvll::fs_read(loop_.native_handle(), self.native_handle(),
+ fd, buf_ptr,
+ len, offset, complete_cb_ptr)
+ };
+ self.sync_cleanup(result)
}
- pub fn install_req_data(&self, cb: Option<FsCallback>) {
+ pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ unsafe {
+ uvll::fs_close(loop_.native_handle(), self.native_handle(),
+ fd, complete_cb_ptr)
+ };
+ }
+ pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(None)
+ };
+ let result = unsafe {
+ uvll::fs_close(loop_.native_handle(), self.native_handle(),
+ fd, complete_cb_ptr)
+ };
+ self.sync_cleanup(result)
+ }
+
+ pub fn mkdir<P: PathLike>(self, loop_: &Loop, path: &P, mode: int, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_mkdir(loop_.native_handle(),
+ self.native_handle(), p, mode, complete_cb_ptr)
+ })
+ });
+ }
+
+ pub fn rmdir<P: PathLike>(self, loop_: &Loop, path: &P, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_rmdir(loop_.native_handle(),
+ self.native_handle(), p, complete_cb_ptr)
+ })
+ });
+ }
+
+ pub fn readdir<P: PathLike>(self, loop_: &Loop, path: &P,
+ flags: c_int, cb: FsCallback) {
+ let complete_cb_ptr = {
+ let mut me = self;
+ me.req_boilerplate(Some(cb))
+ };
+ path.path_as_str(|p| {
+ p.to_c_str().with_ref(|p| unsafe {
+ uvll::fs_readdir(loop_.native_handle(),
+ self.native_handle(), p, flags, complete_cb_ptr)
+ })
+ });
+ }
+
+ // accessors/utility funcs
+ fn sync_cleanup(self, result: c_int)
+ -> Result<c_int, UvError> {
+ self.cleanup_and_delete();
+ match status_to_maybe_uv_error(result as i32) {
+ Some(err) => Err(err),
+ None => Ok(result)
+ }
+ }
+ fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
+ let result = match cb {
+ Some(_) => {
+ compl_cb as *u8
+ },
+ None => 0 as *u8
+ };
+ self.install_req_data(cb);
+ result
+ }
+ pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
let data = ~RequestData {
- complete_cb: cb,
- raw_fd: None
+ complete_cb: cb
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
unsafe {
let data = uvll::get_data_for_req((self.native_handle()));
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
- return &mut **data;
+ &mut **data
}
}
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
}
+ pub fn get_stat(&self) -> uv_stat_t {
+ let stat = uv_stat_t::new();
+ unsafe { uvll::populate_stat(self.native_handle(), &stat); }
+ stat
+ }
+
+ pub fn get_ptr(&self) -> *libc::c_void {
+ unsafe {
+ uvll::get_ptr_from_fs_req(self.native_handle())
+ }
+ }
+
+ pub fn get_paths(&mut self) -> ~[~str] {
+ use str;
+ let ptr = self.get_ptr();
+ match self.get_result() {
+ n if (n <= 0) => {
+ ~[]
+ },
+ n => {
+ let n_len = n as uint;
+ // we pass in the len that uv tells us is there
+ // for the entries and we don't continue past that..
+ // it appears that sometimes the multistring isn't
+ // correctly delimited and we stray into garbage memory?
+ // in any case, passing Some(n_len) fixes it and ensures
+ // good results
+ let raw_path_strs = unsafe {
+ str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) };
+ let raw_len = raw_path_strs.len();
+ assert_eq!(raw_len, n_len);
+ raw_path_strs
+ }
+ }
+ }
+
fn cleanup_and_delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
}
}
-pub struct FileDescriptor(c_int);
-
-impl FileDescriptor {
- fn new(fd: c_int) -> FileDescriptor {
- FileDescriptor(fd)
- }
-
-
- pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor {
- FileDescriptor::new(req.get_result())
- }
-
- // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write
- fn write_common(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: Option<FsCallback>)
- -> int {
- let complete_cb_ptr = match cb {
- Some(_) => compl_cb as *u8,
- None => 0 as *u8
- };
- let is_sync = cb.is_none();
- let mut req = FsRequest::new(cb);
- let base_ptr = buf.base as *c_void;
- let len = buf.len as uint;
- req.get_req_data().raw_fd = Some(self.native_handle());
- let result = unsafe {
- uvll::fs_write(loop_.native_handle(), req.native_handle(),
- self.native_handle(), base_ptr,
- len, offset, complete_cb_ptr) as int
- };
- if is_sync { req.cleanup_and_delete(); }
- result
- }
- pub fn write(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
- self.write_common(loop_, buf, offset, Some(cb));
- }
- pub fn write_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
- -> Result<int, UvError> {
- let result = self.write_common(loop_, buf, offset, None);
- sync_cleanup(result)
- }
-
- fn read_common(&mut self, loop_: &Loop, buf: Buf,
- offset: i64, cb: Option<FsCallback>)
- -> int {
- let complete_cb_ptr = match cb {
- Some(_) => compl_cb as *u8,
- None => 0 as *u8
- };
- let is_sync = cb.is_none();
- let mut req = FsRequest::new(cb);
- req.get_req_data().raw_fd = Some(self.native_handle());
- let buf_ptr = buf.base as *c_void;
- let result = unsafe {
- uvll::fs_read(loop_.native_handle(), req.native_handle(),
- self.native_handle(), buf_ptr,
- buf.len as uint, offset, complete_cb_ptr) as int
- };
- if is_sync { req.cleanup_and_delete(); }
- result
- }
- pub fn read(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) {
- self.read_common(loop_, buf, offset, Some(cb));
- }
- pub fn read_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64)
- -> Result<int, UvError> {
- let result = self.read_common(loop_, buf, offset, None);
- sync_cleanup(result)
- }
-
- fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
- let complete_cb_ptr = match cb {
- Some(_) => compl_cb as *u8,
- None => 0 as *u8
- };
- let is_sync = cb.is_none();
- let req = FsRequest::new(cb);
- let result = unsafe {
- uvll::fs_close(loop_.native_handle(), req.native_handle(),
- self.native_handle(), complete_cb_ptr) as int
- };
- if is_sync { req.cleanup_and_delete(); }
- result
- }
- pub fn close(self, loop_: &Loop, cb: FsCallback) {
- self.close_common(loop_, Some(cb));
- }
- pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
- let result = self.close_common(loop_, None);
- sync_cleanup(result)
- }
-}
extern fn compl_cb(req: *uv_fs_t) {
let mut req: FsRequest = NativeHandle::from_native_handle(req);
// pull the user cb out of the req data
req.cleanup_and_delete();
}
-impl NativeHandle<c_int> for FileDescriptor {
- fn from_native_handle(handle: c_int) -> FileDescriptor {
- FileDescriptor(handle)
- }
- fn native_handle(&self) -> c_int {
- match self { &FileDescriptor(ptr) => ptr }
- }
-}
-
+#[cfg(test)]
mod test {
use super::*;
//use rt::test::*;
use unstable::run_in_bare_thread;
use path::Path;
use rt::uv::{Loop, Buf, slice_to_uv_buf};
- use libc::{O_CREAT, O_RDWR, O_RDONLY,
- S_IWUSR, S_IRUSR}; //NOTE: need defs for S_**GRP|S_**OTH in libc:: ...
- //S_IRGRP, S_IROTH};
+ use libc::{c_int, O_CREAT, O_RDWR, O_RDONLY,
+ S_IWUSR, S_IRUSR};
- fn file_test_full_simple_impl() {
+ #[test]
+ fn file_test_full_simple() {
do run_in_bare_thread {
let mut loop_ = Loop::new();
let create_flags = O_RDWR | O_CREAT;
let read_buf = slice_to_uv_buf(read_mem);
let read_buf_ptr: *Buf = &read_buf;
let p = Path(path_str);
- do FsRequest::open(&loop_, &p, create_flags as int, mode as int)
+ let open_req = FsRequest::new();
+ do open_req.open(&loop_, &p, create_flags as int, mode as int)
|req, uverr| {
assert!(uverr.is_none());
- let mut fd = FileDescriptor::from_open_req(req);
- let raw_fd = fd.native_handle();
+ let fd = req.get_result();
let buf = unsafe { *write_buf_ptr };
- do fd.write(&req.get_loop(), buf, -1) |req, uverr| {
- let fd = FileDescriptor(raw_fd);
- do fd.close(&req.get_loop()) |req, _| {
- let loop_ = req.get_loop();
+ let write_req = FsRequest::new();
+ do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
+ let close_req = FsRequest::new();
+ do close_req.close(&req.get_loop(), fd) |req, _| {
assert!(uverr.is_none());
- do FsRequest::open(&loop_, &Path(path_str), read_flags as int,0)
+ let loop_ = req.get_loop();
+ let open_req = FsRequest::new();
+ do open_req.open(&loop_, &Path(path_str), read_flags as int,0)
|req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
- let mut fd = FileDescriptor::from_open_req(req);
- let raw_fd = fd.native_handle();
+ let fd = req.get_result();
let read_buf = unsafe { *read_buf_ptr };
- do fd.read(&loop_, read_buf, 0) |req, uverr| {
+ let read_req = FsRequest::new();
+ do read_req.read(&loop_, fd, read_buf, 0) |req, uverr| {
assert!(uverr.is_none());
let loop_ = req.get_loop();
// we know nread >=0 because uverr is none..
read_buf.base, nread))
};
assert!(read_str == ~"hello");
- do FileDescriptor(raw_fd).close(&loop_) |req,uverr| {
+ let close_req = FsRequest::new();
+ do close_req.close(&loop_, fd) |req,uverr| {
assert!(uverr.is_none());
let loop_ = &req.get_loop();
- do FsRequest::unlink(loop_, &Path(path_str))
+ let unlink_req = FsRequest::new();
+ do unlink_req.unlink(loop_, &Path(path_str))
|_,uverr| {
assert!(uverr.is_none());
};
};
- }
+ };
};
};
};
loop_.close();
}
}
- fn file_test_full_simple_impl_sync() {
+
+ #[test]
+ fn file_test_full_simple_sync() {
do run_in_bare_thread {
// setup
let mut loop_ = Loop::new();
let write_val = "hello".as_bytes().to_owned();
let write_buf = slice_to_uv_buf(write_val);
// open/create
- let result = FsRequest::open_sync(&loop_, &Path(path_str),
+ let open_req = FsRequest::new();
+ let result = open_req.open_sync(&loop_, &Path(path_str),
create_flags as int, mode as int);
assert!(result.is_ok());
- let mut fd = FileDescriptor(result.unwrap() as i32);
+ let fd = result.unwrap();
// write
- let result = fd.write_sync(&loop_, write_buf, -1);
+ let write_req = FsRequest::new();
+ let result = write_req.write_sync(&loop_, fd, write_buf, -1);
assert!(result.is_ok());
// close
- let result = fd.close_sync(&loop_);
+ let close_req = FsRequest::new();
+ let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// re-open
- let result = FsRequest::open_sync(&loop_, &Path(path_str),
+ let open_req = FsRequest::new();
+ let result = open_req.open_sync(&loop_, &Path(path_str),
read_flags as int,0);
assert!(result.is_ok());
let len = 1028;
- let mut fd = FileDescriptor(result.unwrap() as i32);
+ let fd = result.unwrap();
// read
let read_mem: ~[u8] = vec::from_elem(len, 0u8);
let buf = slice_to_uv_buf(read_mem);
- let result = fd.read_sync(&loop_, buf, 0);
+ let read_req = FsRequest::new();
+ let result = read_req.read_sync(&loop_, fd, buf, 0);
assert!(result.is_ok());
let nread = result.unwrap();
// nread == 0 would be EOF.. we know it's >= zero because otherwise
read_mem.slice(0, nread as uint));
assert!(read_str == ~"hello");
// close
- let result = fd.close_sync(&loop_);
+ let close_req = FsRequest::new();
+ let result = close_req.close_sync(&loop_, fd);
assert!(result.is_ok());
// unlink
- let result = FsRequest::unlink_sync(&loop_, &Path(path_str));
+ let unlink_req = FsRequest::new();
+ let result = unlink_req.unlink_sync(&loop_, &Path(path_str));
assert!(result.is_ok());
} else { fail!("nread was 0.. wudn't expectin' that."); }
loop_.close();
}
}
- #[test]
- #[ignore(cfg(windows))] // FIXME #8814
- fn file_test_full_simple() {
- file_test_full_simple_impl();
- }
-
- #[test]
- #[ignore(cfg(windows))] // FIXME #8814
- fn file_test_full_simple_sync() {
- file_test_full_simple_impl_sync();
- }
-
fn naive_print(loop_: &Loop, input: &str) {
- let mut stdout = FileDescriptor(STDOUT_FILENO);
let write_val = input.as_bytes();
let write_buf = slice_to_uv_buf(write_val);
- stdout.write_sync(loop_, write_buf, -1);
+ let write_req = FsRequest::new();
+ write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
}
#[test]
loop_.close();
};
}
+ #[test]
+ fn file_test_stat_simple() {
+ do run_in_bare_thread {
+ let mut loop_ = Loop::new();
+ let path = "./tmp/file_test_stat_simple.txt";
+ let create_flags = O_RDWR |
+ O_CREAT;
+ let mode = S_IWUSR |
+ S_IRUSR;
+ let write_val = "hello".as_bytes().to_owned();
+ let write_buf = slice_to_uv_buf(write_val);
+ let write_buf_ptr: *Buf = &write_buf;
+ let open_req = FsRequest::new();
+ do open_req.open(&loop_, &path, create_flags as int, mode as int)
+ |req, uverr| {
+ assert!(uverr.is_none());
+ let fd = req.get_result();
+ let buf = unsafe { *write_buf_ptr };
+ let write_req = FsRequest::new();
+ do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat_req = FsRequest::new();
+ do stat_req.stat(&loop_, &path) |req, uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat = req.get_stat();
+ let sz: uint = stat.st_size as uint;
+ assert!(sz > 0);
+ let close_req = FsRequest::new();
+ do close_req.close(&loop_, fd) |req, uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let unlink_req = FsRequest::new();
+ do unlink_req.unlink(&loop_, &path) |req,uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat_req = FsRequest::new();
+ do stat_req.stat(&loop_, &path) |_, uverr| {
+ // should cause an error because the
+ // file doesn't exist anymore
+ assert!(uverr.is_some());
+ };
+ };
+ };
+ };
+ };
+ };
+ loop_.run();
+ loop_.close();
+ }
+ }
+
+ #[test]
+ fn file_test_mk_rm_dir() {
+ do run_in_bare_thread {
+ let mut loop_ = Loop::new();
+ let path = "./tmp/mk_rm_dir";
+ let mode = S_IWUSR |
+ S_IRUSR;
+ let mkdir_req = FsRequest::new();
+ do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat_req = FsRequest::new();
+ do stat_req.stat(&loop_, &path) |req, uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat = req.get_stat();
+ naive_print(&loop_, fmt!("%?", stat));
+ assert!(stat.is_dir());
+ let rmdir_req = FsRequest::new();
+ do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let stat_req = FsRequest::new();
+ do stat_req.stat(&loop_, &path) |req, uverr| {
+ assert!(uverr.is_some());
+ }
+ }
+ }
+ }
+ loop_.run();
+ loop_.close();
+ }
+ }
+ #[test]
+ fn file_test_mkdir_chokes_on_double_create() {
+ do run_in_bare_thread {
+ let mut loop_ = Loop::new();
+ let path = "./tmp/double_create_dir";
+ let mode = S_IWUSR |
+ S_IRUSR;
+ let mkdir_req = FsRequest::new();
+ do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ let mkdir_req = FsRequest::new();
+ do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| {
+ assert!(uverr.is_some());
+ let loop_ = req.get_loop();
+ let stat = req.get_stat();
+ let rmdir_req = FsRequest::new();
+ do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+ assert!(uverr.is_none());
+ let loop_ = req.get_loop();
+ }
+ }
+ }
+ loop_.run();
+ loop_.close();
+ }
+ }
+ #[test]
+ fn file_test_rmdir_chokes_on_nonexistant_path() {
+ do run_in_bare_thread {
+ let mut loop_ = Loop::new();
+ let path = "./tmp/never_existed_dir";
+ let rmdir_req = FsRequest::new();
+ do rmdir_req.rmdir(&loop_, &path) |req,uverr| {
+ assert!(uverr.is_some());
+ }
+ loop_.run();
+ loop_.close();
+ }
+ }
}
pub use self::idle::IdleWatcher;
pub use self::timer::TimerWatcher;
pub use self::async::AsyncWatcher;
+pub use self::process::Process;
+pub use self::pipe::Pipe;
/// The implementation of `rtio` for libuv
pub mod uvio;
pub mod timer;
pub mod async;
pub mod addrinfo;
+pub mod process;
+pub mod pipe;
/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
+// first int is exit_status, second is term_signal
+pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
timer_cb: Option<TimerCallback>,
async_cb: Option<AsyncCallback>,
udp_recv_cb: Option<UdpReceiveCallback>,
- udp_send_cb: Option<UdpSendCallback>
+ udp_send_cb: Option<UdpSendCallback>,
+ exit_cb: Option<ExitCallback>,
}
pub trait WatcherInterop {
timer_cb: None,
async_cb: None,
udp_recv_cb: None,
- udp_send_cb: None
+ udp_send_cb: None,
+ exit_cb: None,
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
--- /dev/null
+// 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 prelude::*;
+use libc;
+
+use rt::uv;
+use rt::uv::net;
+use rt::uv::uvll;
+
+pub struct Pipe(*uvll::uv_pipe_t);
+
+impl uv::Watcher for Pipe {}
+
+impl Pipe {
+ pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
+ unsafe {
+ let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
+ assert!(handle.is_not_null());
+ let ipc = ipc as libc::c_int;
+ assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
+ let mut ret: Pipe =
+ uv::NativeHandle::from_native_handle(handle);
+ ret.install_watcher_data();
+ ret
+ }
+ }
+
+ pub fn as_stream(&self) -> net::StreamWatcher {
+ net::StreamWatcher(**self as *uvll::uv_stream_t)
+ }
+
+ pub fn close(self, cb: uv::NullCallback) {
+ {
+ let mut this = self;
+ let data = this.get_watcher_data();
+ assert!(data.close_cb.is_none());
+ data.close_cb = Some(cb);
+ }
+
+ unsafe { uvll::close(self.native_handle(), close_cb); }
+
+ extern fn close_cb(handle: *uvll::uv_pipe_t) {
+ let mut process: Pipe = uv::NativeHandle::from_native_handle(handle);
+ process.get_watcher_data().close_cb.take_unwrap()();
+ process.drop_watcher_data();
+ unsafe { uvll::free_handle(handle as *libc::c_void) }
+ }
+ }
+}
+
+impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
+ fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
+ Pipe(handle)
+ }
+ fn native_handle(&self) -> *uvll::uv_pipe_t {
+ match self { &Pipe(ptr) => ptr }
+ }
+}
--- /dev/null
+// 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 prelude::*;
+use cell::Cell;
+use libc;
+use ptr;
+use util;
+use vec;
+
+use rt::io::process::*;
+use rt::uv;
+use rt::uv::uvio::UvPipeStream;
+use rt::uv::uvll;
+
+/// A process wraps the handle of the underlying uv_process_t.
+pub struct Process(*uvll::uv_process_t);
+
+impl uv::Watcher for Process {}
+
+impl Process {
+ /// Creates a new process, ready to spawn inside an event loop
+ pub fn new() -> Process {
+ let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
+ assert!(handle.is_not_null());
+ let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
+ ret.install_watcher_data();
+ return ret;
+ }
+
+ /// Spawn a new process inside the specified event loop.
+ ///
+ /// The `config` variable will be passed down to libuv, and the `exit_cb`
+ /// will be run only once, when the process exits.
+ ///
+ /// Returns either the corresponding process object or an error which
+ /// occurred.
+ pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig,
+ exit_cb: uv::ExitCallback)
+ -> Result<~[Option<UvPipeStream>], uv::UvError>
+ {
+ let cwd = config.cwd.map_move(|s| s.to_c_str());
+
+ extern fn on_exit(p: *uvll::uv_process_t,
+ exit_status: libc::c_int,
+ term_signal: libc::c_int) {
+ let mut p: Process = uv::NativeHandle::from_native_handle(p);
+ let err = match exit_status {
+ 0 => None,
+ _ => uv::status_to_maybe_uv_error(-1)
+ };
+ p.get_watcher_data().exit_cb.take_unwrap()(p,
+ exit_status as int,
+ term_signal as int,
+ err);
+ }
+
+ let io = util::replace(&mut config.io, ~[]);
+ let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
+ let mut ret_io = vec::with_capacity(io.len());
+ unsafe {
+ vec::raw::set_len(&mut stdio, io.len());
+ for (slot, other) in stdio.iter().zip(io.move_iter()) {
+ let io = set_stdio(slot as *uvll::uv_stdio_container_t, other);
+ ret_io.push(io);
+ }
+ }
+
+ let exit_cb = Cell::new(exit_cb);
+ let ret_io = Cell::new(ret_io);
+ do with_argv(config.program, config.args) |argv| {
+ do with_env(config.env) |envp| {
+ let options = uvll::uv_process_options_t {
+ exit_cb: on_exit,
+ file: unsafe { *argv },
+ args: argv,
+ env: envp,
+ cwd: match cwd {
+ Some(ref cwd) => cwd.with_ref(|p| p),
+ None => ptr::null(),
+ },
+ flags: 0,
+ stdio_count: stdio.len() as libc::c_int,
+ stdio: stdio.as_imm_buf(|p, _| p),
+ uid: 0,
+ gid: 0,
+ };
+
+ match unsafe {
+ uvll::spawn(loop_.native_handle(), **self, options)
+ } {
+ 0 => {
+ (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
+ Ok(ret_io.take())
+ }
+ err => Err(uv::UvError(err))
+ }
+ }
+ }
+ }
+
+ /// Sends a signal to this process.
+ ///
+ /// This is a wrapper around `uv_process_kill`
+ pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
+ match unsafe {
+ uvll::process_kill(self.native_handle(), signum as libc::c_int)
+ } {
+ 0 => Ok(()),
+ err => Err(uv::UvError(err))
+ }
+ }
+
+ /// Returns the process id of a spawned process
+ pub fn pid(&self) -> libc::pid_t {
+ unsafe { uvll::process_pid(**self) as libc::pid_t }
+ }
+
+ /// Closes this handle, invoking the specified callback once closed
+ pub fn close(self, cb: uv::NullCallback) {
+ {
+ let mut this = self;
+ let data = this.get_watcher_data();
+ assert!(data.close_cb.is_none());
+ data.close_cb = Some(cb);
+ }
+
+ unsafe { uvll::close(self.native_handle(), close_cb); }
+
+ extern fn close_cb(handle: *uvll::uv_process_t) {
+ let mut process: Process = uv::NativeHandle::from_native_handle(handle);
+ process.get_watcher_data().close_cb.take_unwrap()();
+ process.drop_watcher_data();
+ unsafe { uvll::free_handle(handle as *libc::c_void) }
+ }
+ }
+}
+
+unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
+ io: StdioContainer) -> Option<UvPipeStream> {
+ match io {
+ Ignored => {
+ uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
+ None
+ }
+ InheritFd(fd) => {
+ uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
+ uvll::set_stdio_container_fd(dst, fd);
+ None
+ }
+ CreatePipe(pipe, readable, writable) => {
+ let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
+ if readable {
+ flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
+ }
+ if writable {
+ flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
+ }
+ let handle = pipe.pipe.as_stream().native_handle();
+ uvll::set_stdio_container_flags(dst, flags);
+ uvll::set_stdio_container_stream(dst, handle);
+ Some(pipe.bind())
+ }
+ }
+}
+
+/// Converts the program and arguments to the argv array expected by libuv
+fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
+ // First, allocation space to put all the C-strings (we need to have
+ // ownership of them somewhere
+ let mut c_strs = vec::with_capacity(args.len() + 1);
+ c_strs.push(prog.to_c_str());
+ for arg in args.iter() {
+ c_strs.push(arg.to_c_str());
+ }
+
+ // Next, create the char** array
+ let mut c_args = vec::with_capacity(c_strs.len() + 1);
+ for s in c_strs.iter() {
+ c_args.push(s.with_ref(|p| p));
+ }
+ c_args.push(ptr::null());
+ c_args.as_imm_buf(|buf, _| f(buf))
+}
+
+/// Converts the environment to the env array expected by libuv
+fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
+ let env = match env {
+ Some(s) => s,
+ None => { return f(ptr::null()); }
+ };
+ // As with argv, create some temporary storage and then the actual array
+ let mut envp = vec::with_capacity(env.len());
+ for &(ref key, ref value) in env.iter() {
+ envp.push(fmt!("%s=%s", *key, *value).to_c_str());
+ }
+ let mut c_envp = vec::with_capacity(envp.len() + 1);
+ for s in envp.iter() {
+ c_envp.push(s.with_ref(|p| p));
+ }
+ c_envp.push(ptr::null());
+ c_envp.as_imm_buf(|buf, _| f(buf))
+}
+
+impl uv::NativeHandle<*uvll::uv_process_t> for Process {
+ fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
+ Process(handle)
+ }
+ fn native_handle(&self) -> *uvll::uv_process_t {
+ match self { &Process(ptr) => ptr }
+ }
+}
use cast;
use cell::Cell;
use clone::Clone;
-use libc::{c_int, c_uint, c_void};
+use libc::{c_int, c_uint, c_void, pid_t};
use ops::Drop;
use option::*;
use ptr;
use rt::io::IoError;
use rt::io::net::ip::{SocketAddr, IpAddr};
use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
+use rt::io::process::ProcessConfig;
+use rt::kill::BlockedTask;
use rt::local::Local;
use rt::rtio::*;
use rt::sched::{Scheduler, SchedHandle};
use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs};
use rt::uv::addrinfo::GetAddrInfoRequest;
use unstable::sync::Exclusive;
+use path::Path;
use super::super::io::support::PathLike;
use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY,
- S_IRUSR, S_IWUSR};
+ S_IRUSR, S_IWUSR, S_IRWXU};
use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
- CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite};
+ CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
+ FileStat};
use task;
#[cfg(test)] use container::Container;
}
impl Drop for UvEventLoop {
- fn drop(&self) {
- // XXX: Need mutable finalizer
- let this = unsafe {
- transmute::<&UvEventLoop, &mut UvEventLoop>(self)
- };
- this.uvio.uv_loop().close();
+ fn drop(&mut self) {
+ self.uvio.uv_loop().close();
}
}
}
impl Drop for UvRemoteCallback {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
let this: &mut UvRemoteCallback = cast::transmute_mut(self);
do this.exit_flag.with |should_exit| {
}
}
+/// Helper for a variety of simple uv_fs_* functions that
+/// have no ret val
+fn uv_fs_helper<P: PathLike>(loop_: &mut Loop, path: &P,
+ cb: ~fn(&mut FsRequest, &mut Loop, &P,
+ ~fn(&FsRequest, Option<UvError>)))
+ -> Result<(), IoError> {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+ let path_cell = Cell::new(path);
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ let mut new_req = FsRequest::new();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let path = path_cell.take();
+ do cb(&mut new_req, loop_, path) |_, err| {
+ let res = match err {
+ None => Ok(()),
+ Some(err) => Err(uv_error_to_io_error(err))
+ };
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ };
+ }
+ }
+ assert!(!result_cell.is_empty());
+ return result_cell.take();
+}
+
impl IoFactory for UvIoFactory {
// Connect to an address and return a new stream
// NB: This blocks the task waiting on the connection.
fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream {
let loop_ = Loop {handle: self.uv_loop().native_handle()};
- let fd = file::FileDescriptor(fd);
let home = get_handle_to_current_scheduler!();
~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream
}
let path_cell = Cell::new(path);
do task::unkillable { // FIXME(#8674)
let scheduler: ~Scheduler = Local::take();
+ let open_req = file::FsRequest::new();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let path = path_cell.take();
- do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int)
+ do open_req.open(self.uv_loop(), path, flags as int, create_mode as int)
|req,err| {
if err.is_none() {
let loop_ = Loop {handle: req.get_loop().native_handle()};
let home = get_handle_to_current_scheduler!();
- let fd = file::FileDescriptor(req.get_result());
+ let fd = req.get_result() as c_int;
let fs = ~UvFileStream::new(
loop_, fd, true, home) as ~RtioFileStream;
let res = Ok(fs);
}
};
};
- }
+ };
assert!(!result_cell.is_empty());
return result_cell.take();
}
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+ do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| {
+ do unlink_req.unlink(l, p) |req, err| {
+ cb(req, err)
+ };
+ }
+ }
+ fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError> {
+ use str::StrSlice;
let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+ let result_cell_ptr: *Cell<Result<FileStat,
+ IoError>> = &result_cell;
let path_cell = Cell::new(path);
do task::unkillable { // FIXME(#8674)
let scheduler: ~Scheduler = Local::take();
+ let stat_req = file::FsRequest::new();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let path = path_cell.take();
- do file::FsRequest::unlink(self.uv_loop(), path) |_, err| {
+ let path_str = path.path_as_str(|p| p.to_owned());
+ do stat_req.stat(self.uv_loop(), path)
+ |req,err| {
let res = match err {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err))
+ None => {
+ let stat = req.get_stat();
+ Ok(FileStat {
+ path: Path(path_str),
+ is_file: stat.is_file(),
+ is_dir: stat.is_dir(),
+ size: stat.st_size,
+ created: stat.st_ctim.tv_sec as u64,
+ modified: stat.st_mtim.tv_sec as u64,
+ accessed: stat.st_atim.tv_sec as u64
+ })
+ },
+ Some(e) => {
+ Err(uv_error_to_io_error(e))
+ }
};
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
- }
+ };
assert!(!result_cell.is_empty());
return result_cell.take();
}
assert!(!result_cell.is_empty());
return result_cell.take();
}
+ fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+ let mode = S_IRWXU as int;
+ do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| {
+ do mkdir_req.mkdir(l, p, mode as int) |req, err| {
+ cb(req, err)
+ };
+ }
+ }
+ fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError> {
+ do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| {
+ do rmdir_req.rmdir(l, p) |req, err| {
+ cb(req, err)
+ };
+ }
+ }
+ fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) ->
+ Result<~[Path], IoError> {
+ use str::StrSlice;
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<~[Path],
+ IoError>> = &result_cell;
+ let path_cell = Cell::new(path);
+ do task::unkillable { // FIXME(#8674)
+ let scheduler: ~Scheduler = Local::take();
+ let stat_req = file::FsRequest::new();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let path = path_cell.take();
+ let path_str = path.path_as_str(|p| p.to_owned());
+ do stat_req.readdir(self.uv_loop(), path, flags)
+ |req,err| {
+ let res = match err {
+ None => {
+ let rel_paths = req.get_paths();
+ let mut paths = ~[];
+ for r in rel_paths.iter() {
+ paths.push(Path(path_str+"/"+*r));
+ }
+ Ok(paths)
+ },
+ Some(e) => {
+ Err(uv_error_to_io_error(e))
+ }
+ };
+ unsafe { (*result_cell_ptr).put_back(res); }
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ };
+ };
+ };
+ assert!(!result_cell.is_empty());
+ return result_cell.take();
+ }
+
+ fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> {
+ let home = get_handle_to_current_scheduler!();
+ Ok(~UvUnboundPipe { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
+ }
+
+ fn spawn(&mut self, config: ProcessConfig)
+ -> Result<(~RtioProcessObject, ~[Option<RtioPipeObject>]), IoError>
+ {
+ // Sadly, we must create the UvProcess before we actually call uv_spawn
+ // so that the exit_cb can close over it and notify it when the process
+ // has exited.
+ let mut ret = ~UvProcess {
+ process: Process::new(),
+ home: None,
+ exit_status: None,
+ term_signal: None,
+ exit_error: None,
+ descheduled: None,
+ };
+ let ret_ptr = unsafe {
+ *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
+ };
+
+ // The purpose of this exit callback is to record the data about the
+ // exit and then wake up the task which may be waiting for the process
+ // to exit. This is all performed in the current io-loop, and the
+ // implementation of UvProcess ensures that reading these fields always
+ // occurs on the current io-loop.
+ let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
+ unsafe {
+ assert!((*ret_ptr).exit_status.is_none());
+ (*ret_ptr).exit_status = Some(exit_status);
+ (*ret_ptr).term_signal = Some(term_signal);
+ (*ret_ptr).exit_error = error;
+ match (*ret_ptr).descheduled.take() {
+ Some(task) => {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task);
+ }
+ None => {}
+ }
+ }
+ };
+
+ match ret.process.spawn(self.uv_loop(), config, exit_cb) {
+ Ok(io) => {
+ // Only now do we actually get a handle to this scheduler.
+ ret.home = Some(get_handle_to_current_scheduler!());
+ Ok((ret, io))
+ }
+ Err(uverr) => {
+ // We still need to close the process handle we created, but
+ // that's taken care for us in the destructor of UvProcess
+ Err(uv_error_to_io_error(uverr))
+ }
+ }
+ }
}
pub struct UvTcpListener {
}
impl Drop for UvTcpListener {
- fn drop(&self) {
- // XXX need mutable finalizer
- let self_ = unsafe { transmute::<&UvTcpListener, &mut UvTcpListener>(self) };
- do self_.home_for_io_with_sched |self_, scheduler| {
+ fn drop(&mut self) {
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task = Cell::new(task);
do self_.watcher.as_stream().close {
}
}
+fn read_stream(mut watcher: StreamWatcher,
+ scheduler: ~Scheduler,
+ buf: &mut [u8]) -> Result<uint, IoError> {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
+
+ let buf_ptr: *&mut [u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_sched, task| {
+ let task_cell = Cell::new(task);
+ // XXX: We shouldn't reallocate these callbacks every
+ // call to read
+ let alloc: AllocCallback = |_| unsafe {
+ slice_to_uv_buf(*buf_ptr)
+ };
+ do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
+
+ // Stop reading so that no read callbacks are
+ // triggered before the user calls `read` again.
+ // XXX: Is there a performance impact to calling
+ // stop here?
+ watcher.read_stop();
+
+ let result = if status.is_none() {
+ assert!(nread >= 0);
+ Ok(nread as uint)
+ } else {
+ Err(uv_error_to_io_error(status.unwrap()))
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
+
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+}
+
+fn write_stream(mut watcher: StreamWatcher,
+ scheduler: ~Scheduler,
+ buf: &[u8]) -> Result<(), IoError> {
+ let result_cell = Cell::new_empty();
+ let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
+ let buf_ptr: *&[u8] = &buf;
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
+ do watcher.write(buf) |_watcher, status| {
+ let result = if status.is_none() {
+ Ok(())
+ } else {
+ Err(uv_error_to_io_error(status.unwrap()))
+ };
+
+ unsafe { (*result_cell_ptr).put_back(result); }
+
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+
+ assert!(!result_cell.is_empty());
+ result_cell.take()
+}
+
+pub struct UvUnboundPipe {
+ pipe: Pipe,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvUnboundPipe {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvUnboundPipe {
+ fn drop(&mut self) {
+ do self.home_for_io |self_| {
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.pipe.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+ }
+}
+
+impl UvUnboundPipe {
+ pub unsafe fn bind(~self) -> UvPipeStream {
+ UvPipeStream { inner: self }
+ }
+}
+
+pub struct UvPipeStream {
+ priv inner: ~UvUnboundPipe,
+}
+
+impl UvPipeStream {
+ pub fn new(inner: ~UvUnboundPipe) -> UvPipeStream {
+ UvPipeStream { inner: inner }
+ }
+}
+
+impl RtioPipe for UvPipeStream {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+ do self.inner.home_for_io_with_sched |self_, scheduler| {
+ read_stream(self_.pipe.as_stream(), scheduler, buf)
+ }
+ }
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+ do self.inner.home_for_io_with_sched |self_, scheduler| {
+ write_stream(self_.pipe.as_stream(), scheduler, buf)
+ }
+ }
+}
+
pub struct UvTcpStream {
watcher: TcpWatcher,
home: SchedHandle,
}
impl Drop for UvTcpStream {
- fn drop(&self) {
- // XXX need mutable finalizer
- let this = unsafe { transmute::<&UvTcpStream, &mut UvTcpStream>(self) };
- do this.home_for_io_with_sched |self_, scheduler| {
+ fn drop(&mut self) {
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.as_stream().close {
impl RtioTcpStream for UvTcpStream {
fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
do self.home_for_io_with_sched |self_, scheduler| {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
-
- let buf_ptr: *&mut [u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- let task_cell = Cell::new(task);
- // XXX: We shouldn't reallocate these callbacks every
- // call to read
- let alloc: AllocCallback = |_| unsafe {
- slice_to_uv_buf(*buf_ptr)
- };
- let mut watcher = self_.watcher.as_stream();
- do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
-
- // Stop reading so that no read callbacks are
- // triggered before the user calls `read` again.
- // XXX: Is there a performance impact to calling
- // stop here?
- watcher.read_stop();
-
- let result = if status.is_none() {
- assert!(nread >= 0);
- Ok(nread as uint)
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
+ read_stream(self_.watcher.as_stream(), scheduler, buf)
}
}
fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
do self.home_for_io_with_sched |self_, scheduler| {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let buf_ptr: *&[u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- let mut watcher = self_.watcher.as_stream();
- do watcher.write(buf) |_watcher, status| {
- let result = if status.is_none() {
- Ok(())
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
+ write_stream(self_.watcher.as_stream(), scheduler, buf)
}
}
}
impl Drop for UvUdpSocket {
- fn drop(&self) {
- // XXX need mutable finalizer
- let this = unsafe { transmute::<&UvUdpSocket, &mut UvUdpSocket>(self) };
- do this.home_for_io_with_sched |self_, scheduler| {
+ fn drop(&mut self) {
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.close {
}
impl Drop for UvTimer {
- fn drop(&self) {
- let self_ = unsafe { transmute::<&UvTimer, &mut UvTimer>(self) };
- do self_.home_for_io_with_sched |self_, scheduler| {
+ fn drop(&mut self) {
+ do self.home_for_io_with_sched |self_, scheduler| {
rtdebug!("closing UvTimer");
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
pub struct UvFileStream {
loop_: Loop,
- fd: file::FileDescriptor,
+ fd: c_int,
close_on_drop: bool,
home: SchedHandle
}
}
impl UvFileStream {
- fn new(loop_: Loop, fd: file::FileDescriptor, close_on_drop: bool,
+ fn new(loop_: Loop, fd: c_int, close_on_drop: bool,
home: SchedHandle) -> UvFileStream {
UvFileStream {
loop_: loop_,
do scheduler.deschedule_running_task_and_then |_, task| {
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
let task_cell = Cell::new(task);
- do self_.fd.read(&self_.loop_, buf, offset) |req, uverr| {
+ let read_req = file::FsRequest::new();
+ do read_req.read(&self_.loop_, self_.fd, buf, offset) |req, uverr| {
let res = match uverr {
None => Ok(req.get_result() as int),
Some(err) => Err(uv_error_to_io_error(err))
do scheduler.deschedule_running_task_and_then |_, task| {
let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
let task_cell = Cell::new(task);
- do self_.fd.write(&self_.loop_, buf, offset) |_, uverr| {
+ let write_req = file::FsRequest::new();
+ do write_req.write(&self_.loop_, self_.fd, buf, offset) |_, uverr| {
let res = match uverr {
None => Ok(()),
Some(err) => Err(uv_error_to_io_error(err))
Result<u64, IoError>{
#[fixed_stack_segment]; #[inline(never)];
unsafe {
- match lseek((*self.fd), pos as off_t, whence) {
+ match lseek(self.fd, pos as off_t, whence) {
-1 => {
Err(IoError {
kind: OtherIoError,
}
impl Drop for UvFileStream {
- fn drop(&self) {
- let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) };
+ fn drop(&mut self) {
if self.close_on_drop {
- do self_.home_for_io_with_sched |self_, scheduler| {
+ do self.home_for_io_with_sched |self_, scheduler| {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
- do self_.fd.close(&self.loop_) |_,_| {
+ let close_req = file::FsRequest::new();
+ do close_req.close(&self_.loop_, self_.fd) |_,_| {
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
}
}
+pub struct UvProcess {
+ process: process::Process,
+
+ // Sadly, this structure must be created before we return it, so in that
+ // brief interim the `home` is None.
+ home: Option<SchedHandle>,
+
+ // All None until the process exits (exit_error may stay None)
+ priv exit_status: Option<int>,
+ priv term_signal: Option<int>,
+ priv exit_error: Option<UvError>,
+
+ // Used to store which task to wake up from the exit_cb
+ priv descheduled: Option<BlockedTask>,
+}
+
+impl HomingIO for UvProcess {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.home.get_mut_ref() }
+}
+
+impl Drop for UvProcess {
+ fn drop(&mut self) {
+ let close = |self_: &mut UvProcess| {
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task = Cell::new(task);
+ do self_.process.close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task.take());
+ }
+ }
+ };
+
+ // If home is none, then this process never actually successfully
+ // spawned, so there's no need to switch event loops
+ if self.home.is_none() {
+ close(self)
+ } else {
+ self.home_for_io(close)
+ }
+ }
+}
+
+impl RtioProcess for UvProcess {
+ fn id(&self) -> pid_t {
+ self.process.pid()
+ }
+
+ fn kill(&mut self, signal: int) -> Result<(), IoError> {
+ do self.home_for_io |self_| {
+ match self_.process.kill(signal) {
+ Ok(()) => Ok(()),
+ Err(uverr) => Err(uv_error_to_io_error(uverr))
+ }
+ }
+ }
+
+ fn wait(&mut self) -> int {
+ // Make sure (on the home scheduler) that we have an exit status listed
+ do self.home_for_io |self_| {
+ match self_.exit_status {
+ Some(*) => {}
+ None => {
+ // If there's no exit code previously listed, then the
+ // process's exit callback has yet to be invoked. We just
+ // need to deschedule ourselves and wait to be reawoken.
+ let scheduler: ~Scheduler = Local::take();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ assert!(self_.descheduled.is_none());
+ self_.descheduled = Some(task);
+ }
+ assert!(self_.exit_status.is_some());
+ }
+ }
+ }
+
+ self.exit_status.unwrap()
+ }
+}
+
#[test]
fn test_simple_io_no_connect() {
do run_in_mt_newsched_task {
}
#[test]
-#[ignore(cfg(windows))] // FIXME #8816
fn test_udp_twice() {
do run_in_mt_newsched_task {
let server_addr = next_test_ip4();
}
#[test]
-#[ignore(cfg(windows))] // FIXME #8816
fn file_test_uvio_full_simple() {
do run_in_mt_newsched_task {
file_test_uvio_full_simple_impl();
use c_str::ToCStr;
use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
-#[cfg(not(stage0))]
use libc::ssize_t;
use libc::{malloc, free};
use libc;
pub static EPIPE: c_int = -libc::EPIPE;
}
+pub static PROCESS_SETUID: c_int = 1 << 0;
+pub static PROCESS_SETGID: c_int = 1 << 1;
+pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
+pub static PROCESS_DETACHED: c_int = 1 << 3;
+pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
+
+pub static STDIO_IGNORE: c_int = 0x00;
+pub static STDIO_CREATE_PIPE: c_int = 0x01;
+pub static STDIO_INHERIT_FD: c_int = 0x02;
+pub static STDIO_INHERIT_STREAM: c_int = 0x04;
+pub static STDIO_READABLE_PIPE: c_int = 0x10;
+pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
+
// see libuv/include/uv-unix.h
#[cfg(unix)]
pub struct uv_buf_t {
base: *u8,
}
+pub struct uv_process_options_t {
+ exit_cb: uv_exit_cb,
+ file: *libc::c_char,
+ args: **libc::c_char,
+ env: **libc::c_char,
+ cwd: *libc::c_char,
+ flags: libc::c_uint,
+ stdio_count: libc::c_int,
+ stdio: *uv_stdio_container_t,
+ uid: uv_uid_t,
+ gid: uv_gid_t,
+}
+
+// These fields are private because they must be interfaced with through the
+// functions below.
+pub struct uv_stdio_container_t {
+ priv flags: libc::c_int,
+ priv stream: *uv_stream_t,
+}
+
pub type uv_handle_t = c_void;
pub type uv_loop_t = c_void;
pub type uv_idle_t = c_void;
pub type uv_fs_t = c_void;
pub type uv_udp_send_t = c_void;
pub type uv_getaddrinfo_t = c_void;
+pub type uv_process_t = c_void;
+pub type uv_pipe_t = c_void;
+
+pub struct uv_timespec_t {
+ tv_sec: libc::c_long,
+ tv_nsec: libc::c_long
+}
+
+pub struct uv_stat_t {
+ st_dev: libc::uint64_t,
+ st_mode: libc::uint64_t,
+ st_nlink: libc::uint64_t,
+ st_uid: libc::uint64_t,
+ st_gid: libc::uint64_t,
+ st_rdev: libc::uint64_t,
+ st_ino: libc::uint64_t,
+ st_size: libc::uint64_t,
+ st_blksize: libc::uint64_t,
+ st_blocks: libc::uint64_t,
+ st_flags: libc::uint64_t,
+ st_gen: libc::uint64_t,
+ st_atim: uv_timespec_t,
+ st_mtim: uv_timespec_t,
+ st_ctim: uv_timespec_t,
+ st_birthtim: uv_timespec_t
+}
+
+impl uv_stat_t {
+ pub fn new() -> uv_stat_t {
+ uv_stat_t {
+ st_dev: 0,
+ st_mode: 0,
+ st_nlink: 0,
+ st_uid: 0,
+ st_gid: 0,
+ st_rdev: 0,
+ st_ino: 0,
+ st_size: 0,
+ st_blksize: 0,
+ st_blocks: 0,
+ st_flags: 0,
+ st_gen: 0,
+ st_atim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+ st_mtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+ st_ctim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
+ st_birthtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 }
+ }
+ }
+ pub fn is_file(&self) -> bool {
+ ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFREG as libc::uint64_t
+ }
+ pub fn is_dir(&self) -> bool {
+ ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFDIR as libc::uint64_t
+ }
+}
-#[cfg(stage0)]
-pub type uv_idle_cb = *u8;
-#[cfg(stage0)]
-pub type uv_alloc_cb = *u8;
-#[cfg(stage0)]
-pub type uv_read_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_send_cb = *u8;
-#[cfg(stage0)]
-pub type uv_udp_recv_cb = *u8;
-#[cfg(stage0)]
-pub type uv_close_cb = *u8;
-#[cfg(stage0)]
-pub type uv_walk_cb = *u8;
-#[cfg(stage0)]
-pub type uv_async_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connect_cb = *u8;
-#[cfg(stage0)]
-pub type uv_connection_cb = *u8;
-#[cfg(stage0)]
-pub type uv_timer_cb = *u8;
-#[cfg(stage0)]
-pub type uv_write_cb = *u8;
-#[cfg(stage0)]
-pub type uv_getaddrinfo_cb = *u8;
-
-#[cfg(not(stage0))]
pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_alloc_cb = extern "C" fn(stream: *uv_stream_t,
suggested_size: size_t) -> uv_buf_t;
-#[cfg(not(stage0))]
pub type uv_read_cb = extern "C" fn(stream: *uv_stream_t,
nread: ssize_t,
buf: uv_buf_t);
-#[cfg(not(stage0))]
pub type uv_udp_send_cb = extern "C" fn(req: *uv_udp_send_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t,
nread: ssize_t,
buf: uv_buf_t,
addr: *sockaddr,
flags: c_uint);
-#[cfg(not(stage0))]
pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t);
-#[cfg(not(stage0))]
pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t,
arg: *c_void);
-#[cfg(not(stage0))]
pub type uv_async_cb = extern "C" fn(handle: *uv_async_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_connect_cb = extern "C" fn(handle: *uv_connect_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_connection_cb = extern "C" fn(handle: *uv_connection_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
status: c_int);
-#[cfg(not(stage0))]
pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
status: c_int,
res: *addrinfo);
+pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
+ exit_status: c_int,
+ term_signal: c_int);
pub type sockaddr = c_void;
pub type sockaddr_in = c_void;
ai_next: *addrinfo
}
+#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
+#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
+#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
+#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
+
#[deriving(Eq)]
pub enum uv_handle_type {
UV_UNKNOWN_HANDLE,
UV_HANDLE_TYPE_MAX
}
+#[cfg(unix)]
#[deriving(Eq)]
pub enum uv_req_type {
UV_UNKNOWN_REQ,
UV_REQ_TYPE_MAX
}
+// uv_req_type may have additional fields defined by UV_REQ_TYPE_PRIVATE.
+// See UV_REQ_TYPE_PRIVATE at libuv/include/uv-win.h
+#[cfg(windows)]
+#[deriving(Eq)]
+pub enum uv_req_type {
+ UV_UNKNOWN_REQ,
+ UV_REQ,
+ UV_CONNECT,
+ UV_WRITE,
+ UV_SHUTDOWN,
+ UV_UDP_SEND,
+ UV_FS,
+ UV_WORK,
+ UV_GETADDRINFO,
+ UV_ACCEPT,
+ UV_FS_EVENT_REQ,
+ UV_POLL_REQ,
+ UV_PROCESS_EXIT,
+ UV_READ,
+ UV_UDP_RECV,
+ UV_WAKEUP,
+ UV_SIGNAL_REQ,
+ UV_REQ_TYPE_MAX
+}
+
#[deriving(Eq)]
pub enum uv_membership {
UV_LEAVE_GROUP,
}
#[test]
-#[ignore(cfg(windows))] // FIXME #8817
-#[fixed_stack_segment]
-#[inline(never)]
fn request_sanity_check() {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
}
rust_uv_fs_close(loop_ptr, req, fd, cb)
}
+pub unsafe fn fs_stat(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_fs_stat(loop_ptr, req, path, cb)
+}
+pub unsafe fn fs_fstat(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_fs_fstat(loop_ptr, req, fd, cb)
+}
+pub unsafe fn fs_mkdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, mode: int,
+ cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_fs_mkdir(loop_ptr, req, path, mode as c_int, cb)
+}
+pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
+ cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_fs_rmdir(loop_ptr, req, path, cb)
+}
+pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
+ flags: c_int, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_fs_readdir(loop_ptr, req, path, flags, cb)
+}
+pub unsafe fn populate_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_populate_uv_stat(req_in, stat_out)
+}
pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_fs_req_cleanup(req);
}
+pub unsafe fn spawn(loop_ptr: *c_void, result: *uv_process_t,
+ options: uv_process_options_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_spawn(loop_ptr, result, options);
+}
+
+pub unsafe fn process_kill(p: *uv_process_t, signum: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_process_kill(p, signum);
+}
+
+pub unsafe fn process_pid(p: *uv_process_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ return rust_uv_process_pid(p);
+}
+
+pub unsafe fn set_stdio_container_flags(c: *uv_stdio_container_t,
+ flags: libc::c_int) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_flags(c, flags);
+}
+
+pub unsafe fn set_stdio_container_fd(c: *uv_stdio_container_t,
+ fd: libc::c_int) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_fd(c, fd);
+}
+
+pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
+ stream: *uv_stream_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_set_stdio_container_stream(c, stream);
+}
+
+pub unsafe fn pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ rust_uv_pipe_init(loop_ptr, p, ipc)
+}
+
// data access helpers
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_get_result_from_fs_req(req)
}
+pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ rust_uv_get_ptr_from_fs_req(req)
+}
pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
#[fixed_stack_segment]; #[inline(never)];
buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
cb: *u8) -> c_int;
+ fn rust_uv_fs_stat(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int;
+ fn rust_uv_fs_fstat(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int;
+ fn rust_uv_fs_mkdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+ mode: c_int, cb: *u8) -> c_int;
+ fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+ cb: *u8) -> c_int;
+ fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
+ flags: c_int, cb: *u8) -> c_int;
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
+ fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
+ fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
node: *c_char, service: *c_char,
hints: *addrinfo) -> c_int;
fn rust_uv_freeaddrinfo(ai: *addrinfo);
+ fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
+ options: uv_process_options_t) -> c_int;
+ fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
+ fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
+ fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
+ fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
+ fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
+ stream: *uv_stream_t);
+ fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
}
}
impl Drop for Process {
- fn drop(&self) {
- // FIXME(#4330) Need self by value to get mutability.
- let mut_self: &mut Process = unsafe { cast::transmute(self) };
-
- mut_self.finish();
- mut_self.close_outputs();
+ fn drop(&mut self) {
+ self.finish();
+ self.close_outputs();
free_handle(self.handle);
}
}
use libc::funcs::bsd44::getdtablesize;
mod rustrt {
- use libc::c_void;
-
#[abi = "cdecl"]
extern {
pub fn rust_unset_sigprocmask();
- pub fn rust_set_environ(envp: *c_void);
}
}
+ #[cfg(windows)]
+ unsafe fn set_environ(_envp: *c_void) {}
+ #[cfg(target_os = "macos")]
+ unsafe fn set_environ(envp: *c_void) {
+ externfn!(fn _NSGetEnviron() -> *mut *c_void);
+
+ *_NSGetEnviron() = envp;
+ }
+ #[cfg(not(target_os = "macos"), not(windows))]
+ unsafe fn set_environ(envp: *c_void) {
+ extern {
+ static mut environ: *c_void;
+ }
+ environ = envp;
+ }
+
unsafe {
let pid = fork();
do with_envp(env) |envp| {
if !envp.is_null() {
- rustrt::rust_set_environ(envp);
+ set_environ(envp);
}
do with_argv(prog, args) |argv| {
execvp(*argv, argv);
let mut tmps = vec::with_capacity(env.len());
for pair in env.iter() {
- // Use of match here is just to workaround limitations
- // in the stage0 irrefutable pattern impl.
let kv = fmt!("%s=%s", pair.first(), pair.second());
tmps.push(kv.to_c_str());
}
pub mod sys;
pub mod cast;
pub mod fmt;
-#[cfg(stage0)] #[path = "repr_stage0.rs"]
-pub mod repr;
-#[cfg(not(stage0))]
pub mod repr;
pub mod cleanup;
-#[cfg(stage0)] #[path = "reflect_stage0.rs"]
-pub mod reflect;
-#[cfg(not(stage0))]
pub mod reflect;
pub mod condition;
pub mod logging;
use char::Char;
use clone::{Clone, DeepClone};
use container::{Container, Mutable};
-use num::Times;
-use iter::{Iterator, FromIterator, Extendable};
+use iter::{Iterator, FromIterator, Extendable, range};
use iter::{Filter, AdditiveIterator, Map};
use iter::{Invert, DoubleEndedIterator, ExactSize};
use libc;
use ptr::RawPtr;
use to_str::ToStr;
use uint;
-use unstable::raw::{Repr, Slice};
use vec;
use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
use default::Default;
fn concat(&self) -> ~str {
if self.is_empty() { return ~""; }
+ // `len` calculation may overflow but push_str but will check boundaries
let len = self.iter().map(|s| s.as_slice().len()).sum();
- let mut s = with_capacity(len);
+ let mut result = with_capacity(len);
- unsafe {
- do s.as_mut_buf |buf, _| {
- let mut buf = buf;
- for ss in self.iter() {
- do ss.as_slice().as_imm_buf |ssbuf, sslen| {
- ptr::copy_memory(buf, ssbuf, sslen);
- buf = buf.offset(sslen as int);
- }
- }
- }
- raw::set_len(&mut s, len);
+ for s in self.iter() {
+ result.push_str(s.as_slice())
}
- s
+ result
}
/// Concatenate a vector of strings, placing a given separator between each.
if sep.is_empty() { return self.concat(); }
// this is wrong without the guarantee that `self` is non-empty
+ // `len` calculation may overflow but push_str but will check boundaries
let len = sep.len() * (self.len() - 1)
+ self.iter().map(|s| s.as_slice().len()).sum();
- let mut s = ~"";
+ let mut result = with_capacity(len);
let mut first = true;
- s.reserve(len);
-
- unsafe {
- do s.as_mut_buf |buf, _| {
- do sep.as_imm_buf |sepbuf, seplen| {
- let mut buf = buf;
- for ss in self.iter() {
- do ss.as_slice().as_imm_buf |ssbuf, sslen| {
- if first {
- first = false;
- } else {
- ptr::copy_memory(buf, sepbuf, seplen);
- buf = buf.offset(seplen as int);
- }
- ptr::copy_memory(buf, ssbuf, sslen);
- buf = buf.offset(sslen as int);
- }
- }
- }
+ for s in self.iter() {
+ if first {
+ first = false;
+ } else {
+ result.push_str(sep);
}
- raw::set_len(&mut s, len);
+ result.push_str(s.as_slice());
}
- s
+ result
}
}
/// Unsafe operations
pub mod raw {
- use option::Some;
+ use option::{Option, Some};
use cast;
use libc;
use ptr;
}
}
- /// Appends a byte to a string. (Not UTF-8 safe).
+ /// Appends a byte to a string.
+ /// The caller must preserve the valid UTF-8 property.
#[inline]
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
- let v: &mut ~[u8] = cast::transmute(s);
- v.push(b);
+ as_owned_vec(s).push(b)
}
- /// Appends a vector of bytes to a string. (Not UTF-8 safe).
- unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
- let new_len = s.len() + bytes.len();
- s.reserve_at_least(new_len);
- for byte in bytes.iter() { push_byte(&mut *s, *byte); }
+ /// Appends a vector of bytes to a string.
+ /// The caller must preserve the valid UTF-8 property.
+ #[inline]
+ pub unsafe fn push_bytes(s: &mut ~str, bytes: &[u8]) {
+ vec::bytes::push_bytes(as_owned_vec(s), bytes);
}
- /// Removes the last byte from a string and returns it. (Not UTF-8 safe).
+ /// Removes the last byte from a string and returns it.
+ /// The caller must preserve the valid UTF-8 property.
pub unsafe fn pop_byte(s: &mut ~str) -> u8 {
let len = s.len();
assert!((len > 0u));
return b;
}
- /// Removes the first byte from a string and returns it. (Not UTF-8 safe).
+ /// Removes the first byte from a string and returns it.
+ /// The caller must preserve the valid UTF-8 property.
pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
let len = s.len();
assert!((len > 0u));
return b;
}
+ /// Access the str in its vector representation.
+ /// The caller must preserve the valid UTF-8 property when modifying.
+ #[inline]
+ pub unsafe fn as_owned_vec<'a>(s: &'a mut ~str) -> &'a mut ~[u8] {
+ cast::transmute(s)
+ }
+
/// Sets the length of a string
///
/// This will explicitly set the size of the string, without actually
/// the string is actually the specified size.
#[inline]
pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
- let v: &mut ~[u8] = cast::transmute(s);
- vec::raw::set_len(v, new_len)
+ vec::raw::set_len(as_owned_vec(s), new_len)
+ }
+
+ /// Parses a C "multistring", eg windows env values or
+ /// the req->ptr result in a uv_fs_readdir() call.
+ /// Optionally, a `count` can be passed in, limiting the
+ /// parsing to only being done `count`-times.
+ #[inline]
+ pub unsafe fn from_c_multistring(buf: *libc::c_char, count: Option<uint>) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ let mut curr_ptr: uint = buf as uint;
+ let mut result = ~[];
+ let mut ctr = 0;
+ let (limited_count, limit) = match count {
+ Some(limit) => (true, limit),
+ None => (false, 0)
+ };
+ while(((limited_count && ctr < limit) || !limited_count)
+ && *(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
+ let env_pair = from_c_str(
+ curr_ptr as *libc::c_char);
+ result.push(env_pair);
+ curr_ptr +=
+ libc::strlen(curr_ptr as *libc::c_char) as uint
+ + 1;
+ ctr += 1;
+ }
+ result
}
/// Sets the length of a string
}
}
+ #[test]
+ fn test_str_multistring_parsing() {
+ use option::None;
+ unsafe {
+ let input = bytes!("zero", "\x00", "one", "\x00", "\x00");
+ let ptr = vec::raw::to_ptr(input);
+ let mut result = from_c_multistring(ptr as *libc::c_char, None);
+ assert!(result.len() == 2);
+ let mut ctr = 0;
+ for x in result.iter() {
+ match ctr {
+ 0 => assert_eq!(x, &~"zero"),
+ 1 => assert_eq!(x, &~"one"),
+ _ => fail!("shouldn't happen!")
+ }
+ ctr += 1;
+ }
+ }
+ }
}
/*
/// Given a string, make a new string with repeated copies of it.
fn repeat(&self, nn: uint) -> ~str {
- do self.as_imm_buf |buf, len| {
- let mut ret = with_capacity(nn * len);
-
- unsafe {
- do ret.as_mut_buf |rbuf, _len| {
- let mut rbuf = rbuf;
-
- do nn.times {
- ptr::copy_memory(rbuf, buf, len);
- rbuf = rbuf.offset(len as int);
- }
- }
- raw::set_len(&mut ret, nn * len);
- }
- ret
+ let mut ret = with_capacity(nn * self.len());
+ for _ in range(0, nn) {
+ ret.push_str(*self);
}
+ ret
}
/// Retrieves the first character from a string slice and returns
/// Appends a string slice to the back of a string, without overallocating
#[inline]
fn push_str_no_overallocate(&mut self, rhs: &str) {
- unsafe {
- let llen = self.len();
- let rlen = rhs.len();
- self.reserve(llen + rlen);
- do self.as_imm_buf |lbuf, _llen| {
- do rhs.as_imm_buf |rbuf, _rlen| {
- let dst = ptr::offset(lbuf, llen as int);
- let dst = cast::transmute_mut_unsafe(dst);
- ptr::copy_memory(dst, rbuf, rlen);
- }
- }
- raw::set_len(self, llen + rlen);
- }
+ let new_cap = self.len() + rhs.len();
+ self.reserve(new_cap);
+ self.push_str(rhs);
}
/// Appends a string slice to the back of a string
#[inline]
fn push_str(&mut self, rhs: &str) {
unsafe {
- let llen = self.len();
- let rlen = rhs.len();
- self.reserve_at_least(llen + rlen);
- do self.as_imm_buf |lbuf, _llen| {
- do rhs.as_imm_buf |rbuf, _rlen| {
- let dst = ptr::offset(lbuf, llen as int);
- let dst = cast::transmute_mut_unsafe(dst);
- ptr::copy_memory(dst, rbuf, rlen);
- }
- }
- raw::set_len(self, llen + rlen);
+ raw::push_bytes(self, rhs.as_bytes());
}
}
#[inline]
fn push_char(&mut self, c: char) {
let cur_len = self.len();
- self.reserve_at_least(cur_len + 4); // may use up to 4 bytes
-
- // Attempt to not use an intermediate buffer by just pushing bytes
- // directly onto this string.
+ // may use up to 4 bytes.
unsafe {
- let v = self.repr();
- let len = c.encode_utf8(cast::transmute(Slice {
- data: ((&(*v).data) as *u8).offset(cur_len as int),
- len: 4,
- }));
- raw::set_len(self, cur_len + len);
+ raw::as_owned_vec(self).reserve_additional(4);
+
+ // Attempt to not use an intermediate buffer by just pushing bytes
+ // directly onto this string.
+ let used = do self.as_mut_buf |buf, _| {
+ do vec::raw::mut_buf_as_slice(buf.offset(cur_len as int), 4) |slc| {
+ c.encode_utf8(slc)
+ }
+ };
+ raw::set_len(self, cur_len + used);
}
}
#[inline]
fn reserve(&mut self, n: uint) {
unsafe {
- let v: &mut ~[u8] = cast::transmute(self);
- (*v).reserve(n);
+ raw::as_owned_vec(self).reserve(n)
}
}
/// * n - The number of bytes to reserve space for
#[inline]
fn reserve_at_least(&mut self, n: uint) {
- self.reserve(uint::next_power_of_two(n))
+ self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n))
}
/// Returns the number of single-byte characters the string can hold without
#[inline]
fn as_mut_buf<T>(&mut self, f: &fn(*mut u8, uint) -> T) -> T {
- let v: &mut ~[u8] = unsafe { cast::transmute(self) };
- v.as_mut_buf(f)
+ unsafe {
+ raw::as_owned_vec(self).as_mut_buf(f)
+ }
}
}
with_capacity(100);
}
}
+
+ #[bench]
+ fn bench_push_str(bh: &mut BenchHarness) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+ do bh.iter {
+ let mut r = ~"";
+ r.push_str(s);
+ }
+ }
+
+ #[bench]
+ fn bench_connect(bh: &mut BenchHarness) {
+ let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
+ let sep = "→";
+ let v = [s, s, s, s, s, s, s, s, s, s];
+ do bh.iter {
+ assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9);
+ }
+ }
}
use c_str::ToCStr;
use cast;
-#[cfg(stage0)]
-use io;
use libc;
use libc::{c_char, size_t};
use repr;
}
}
-#[cfg(not(stage0))]
pub fn log_str<T>(t: &T) -> ~str {
use rt::io;
use rt::io::Decorator;
repr::write_repr(&mut result as &mut io::Writer, t);
str::from_utf8_owned(result.inner())
}
-#[cfg(stage0)]
-pub fn log_str<T>(t: &T) -> ~str {
- do io::with_str_writer |w| {
- repr::write_repr(w, t)
- }
-}
/// Trait for initiating task failure.
pub trait FailWithCause {
impl Drop for Taskgroup {
// Runs on task exit.
- fn drop(&self) {
- unsafe {
- // FIXME(#4330) Need self by value to get mutability.
- let this: &mut Taskgroup = transmute(self);
-
- // If we are failing, the whole taskgroup needs to die.
- do RuntimeGlue::with_task_handle_and_failing |me, failing| {
- if failing {
- for x in this.notifier.mut_iter() {
- x.failed = true;
- }
- // Take everybody down with us. After this point, every
- // other task in the group will see 'tg' as none, which
- // indicates the whole taskgroup is failing (and forbids
- // new spawns from succeeding).
- let tg = do access_group(&self.tasks) |tg| { tg.take() };
- // It's safe to send kill signals outside the lock, because
- // we have a refcount on all kill-handles in the group.
- kill_taskgroup(tg, me);
- } else {
- // Remove ourselves from the group(s).
- do access_group(&self.tasks) |tg| {
- leave_taskgroup(tg, me, true);
- }
+ fn drop(&mut self) {
+ // If we are failing, the whole taskgroup needs to die.
+ do RuntimeGlue::with_task_handle_and_failing |me, failing| {
+ if failing {
+ for x in self.notifier.mut_iter() {
+ x.failed = true;
+ }
+ // Take everybody down with us. After this point, every
+ // other task in the group will see 'tg' as none, which
+ // indicates the whole taskgroup is failing (and forbids
+ // new spawns from succeeding).
+ let tg = do access_group(&self.tasks) |tg| { tg.take() };
+ // It's safe to send kill signals outside the lock, because
+ // we have a refcount on all kill-handles in the group.
+ kill_taskgroup(tg, me);
+ } else {
+ // Remove ourselves from the group(s).
+ do access_group(&self.tasks) |tg| {
+ leave_taskgroup(tg, me, true);
}
- // It doesn't matter whether this happens before or after dealing
- // with our own taskgroup, so long as both happen before we die.
- // We remove ourself from every ancestor we can, so no cleanup; no
- // break.
- do each_ancestor(&mut this.ancestors, |_| {}) |ancestor_group| {
- leave_taskgroup(ancestor_group, me, false);
- true
- };
}
+ // It doesn't matter whether this happens before or after dealing
+ // with our own taskgroup, so long as both happen before we die.
+ // We remove ourself from every ancestor we can, so no cleanup; no
+ // break.
+ do each_ancestor(&mut self.ancestors, |_| {}) |ancestor_group| {
+ leave_taskgroup(ancestor_group, me, false);
+ true
+ };
}
}
}
}
impl Drop for AutoNotify {
- fn drop(&self) {
+ fn drop(&mut self) {
let result = if self.failed { Failure } else { Success };
self.notify_chan.send(result);
}
#[unsafe_destructor]
impl<T> Drop for AtomicOption<T> {
- fn drop(&self) {
- // This will ensure that the contained data is
- // destroyed, unless it's null.
- unsafe {
- // FIXME(#4330) Need self by value to get mutability.
- let this : &mut AtomicOption<T> = cast::transmute(self);
- let _ = this.take(SeqCst);
- }
+ fn drop(&mut self) {
+ let _ = self.take(SeqCst);
}
}
pub struct DynamicLibrary { priv handle: *libc::c_void }
impl Drop for DynamicLibrary {
- fn drop(&self) {
+ fn drop(&mut self) {
match do dl::check_for_errors_in {
unsafe {
dl::close(self.handle)
#[unsafe_destructor]
impl<'self> Drop for Finallyalizer<'self> {
- fn drop(&self) {
+ fn drop(&mut self) {
(self.dtor)();
}
}
pub enum Opaque { }
#[lang="ty_visitor"]
-#[cfg(not(test), stage0)]
-pub trait TyVisitor {
- fn visit_bot(&self) -> bool;
- fn visit_nil(&self) -> bool;
- fn visit_bool(&self) -> bool;
-
- fn visit_int(&self) -> bool;
- fn visit_i8(&self) -> bool;
- fn visit_i16(&self) -> bool;
- fn visit_i32(&self) -> bool;
- fn visit_i64(&self) -> bool;
-
- fn visit_uint(&self) -> bool;
- fn visit_u8(&self) -> bool;
- fn visit_u16(&self) -> bool;
- fn visit_u32(&self) -> bool;
- fn visit_u64(&self) -> bool;
-
- fn visit_float(&self) -> bool;
- fn visit_f32(&self) -> bool;
- fn visit_f64(&self) -> bool;
-
- fn visit_char(&self) -> bool;
-
- fn visit_estr_box(&self) -> bool;
- fn visit_estr_uniq(&self) -> bool;
- fn visit_estr_slice(&self) -> bool;
- fn visit_estr_fixed(&self, n: uint, sz: uint, align: uint) -> bool;
-
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_ptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool;
-
- fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_evec_fixed(&self, n: uint, sz: uint, align: uint,
- mtbl: uint, inner: *TyDesc) -> bool;
-
- fn visit_enter_rec(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
- fn visit_rec_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_leave_rec(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
-
- fn visit_enter_class(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
- fn visit_class_field(&self, i: uint, name: &str,
- mtbl: uint, inner: *TyDesc) -> bool;
- fn visit_leave_class(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
-
- fn visit_enter_tup(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
- fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool;
- fn visit_leave_tup(&self, n_fields: uint,
- sz: uint, align: uint) -> bool;
-
- fn visit_enter_enum(&self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- sz: uint, align: uint) -> bool;
- fn visit_enter_enum_variant(&self, variant: uint,
- disr_val: int,
- n_fields: uint,
- name: &str) -> bool;
- fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool;
- fn visit_leave_enum_variant(&self, variant: uint,
- disr_val: int,
- n_fields: uint,
- name: &str) -> bool;
- fn visit_leave_enum(&self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
- sz: uint, align: uint) -> bool;
-
- fn visit_enter_fn(&self, purity: uint, proto: uint,
- n_inputs: uint, retstyle: uint) -> bool;
- fn visit_fn_input(&self, i: uint, mode: uint, inner: *TyDesc) -> bool;
- fn visit_fn_output(&self, retstyle: uint, inner: *TyDesc) -> bool;
- fn visit_leave_fn(&self, purity: uint, proto: uint,
- n_inputs: uint, retstyle: uint) -> bool;
-
- fn visit_trait(&self) -> bool;
- fn visit_param(&self, i: uint) -> bool;
- fn visit_self(&self) -> bool;
- fn visit_type(&self) -> bool;
- fn visit_opaque_box(&self) -> bool;
- fn visit_closure_ptr(&self, ck: uint) -> bool;
-}
-
-#[lang="ty_visitor"]
-#[cfg(not(test), not(stage0))]
+#[cfg(not(test))]
pub trait TyVisitor {
fn visit_bot(&mut self) -> bool;
fn visit_nil(&mut self) -> bool;
/// Returns `true` if a type is managed (will be allocated on the local heap)
pub fn contains_managed<T>() -> bool;
- #[cfg(stage0)]
- pub fn visit_tydesc(td: *TyDesc, tv: &TyVisitor);
- #[cfg(not(stage0))]
pub fn visit_tydesc(td: *TyDesc, tv: &mut TyVisitor);
pub fn frame_address(f: &once fn(*u8));
#[unsafe_destructor]
impl<T> Drop for UnsafeArc<T>{
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
// Happens when destructing an unwrapper's handle and from `#[unsafe_no_drop_flag]`
if self.data.is_null() {
}
impl Drop for LittleLock {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
rust_destroy_little_lock(self.l);
}
}
}
-#[cfg(stage0)]
-mod macro_hack {
-#[macro_escape];
-macro_rules! externfn(
- (fn $name:ident () $(-> $ret_ty:ty),*) => (
- extern {
- fn $name() $(-> $ret_ty),*;
- }
- );
- (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
- extern {
- fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
- }
- )
-)
-}
-
externfn!(fn rust_create_little_lock() -> rust_little_lock)
externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
}
impl Drop for NonCopyable {
- fn drop(&self) { }
+ fn drop(&mut self) { }
}
/// A type with no inhabitants
struct Foo { five: int }
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
assert_eq!(self.five, 5);
unsafe {
did_run = true;
fn reserve(&mut self, n: uint);
fn reserve_at_least(&mut self, n: uint);
+ fn reserve_additional(&mut self, n: uint);
fn capacity(&self) -> uint;
fn shrink_to_fit(&mut self);
* # Arguments
*
* * n - The number of elements to reserve space for
+ *
+ * # Failure
+ *
+ * This method always succeeds in reserving space for `n` elements, or it does
+ * not return.
*/
fn reserve(&mut self, n: uint) {
// Only make the (slow) call into the runtime if we have to
*/
#[inline]
fn reserve_at_least(&mut self, n: uint) {
- self.reserve(uint::next_power_of_two(n));
+ self.reserve(uint::next_power_of_two_opt(n).unwrap_or(n));
+ }
+
+ /**
+ * Reserves capacity for at least `n` additional elements in the given vector.
+ *
+ * # Failure
+ *
+ * Fails if the new required capacity overflows uint.
+ *
+ * May also fail if `reserve` fails.
+ */
+ #[inline]
+ fn reserve_additional(&mut self, n: uint) {
+ if self.capacity() - self.len() < n {
+ match self.len().checked_add(&n) {
+ None => fail!("vec::reserve_additional: `uint` overflow"),
+ Some(new_cap) => self.reserve_at_least(new_cap)
+ }
+ }
}
/// Returns the number of elements the vector can hold without reallocating.
let repr: **Box<Vec<()>> = cast::transmute(&mut *self);
let fill = (**repr).data.fill;
if (**repr).data.alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
+ self.reserve_additional(1);
}
push_fast(self, t);
let repr: **Vec<()> = cast::transmute(&mut *self);
let fill = (**repr).fill;
if (**repr).alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
+ self.reserve_additional(1);
}
push_fast(self, t);
let self_len = self.len();
let rhs_len = rhs.len();
let new_len = self_len + rhs_len;
- self.reserve_at_least(new_len);
+ self.reserve_additional(rhs.len());
unsafe { // Note: infallible.
let self_p = vec::raw::to_mut_ptr(*self);
let rhs_p = vec::raw::to_ptr(rhs);
// Bound checks are done at vec::raw::copy_memory.
unsafe { vec::raw::copy_memory(dst, src, count) }
}
+
+ /**
+ * Allocate space in `dst` and append the data in `src`.
+ */
+ #[inline]
+ pub fn push_bytes(dst: &mut ~[u8], src: &[u8]) {
+ let old_len = dst.len();
+ dst.reserve_additional(src.len());
+ unsafe {
+ do dst.as_mut_buf |p_dst, len_dst| {
+ do src.as_imm_buf |p_src, len_src| {
+ ptr::copy_memory(p_dst.offset(len_dst as int), p_src, len_src)
+ }
+ }
+ vec::raw::set_len(dst, old_len + src.len());
+ }
+ }
}
impl<A: Clone> Clone for ~[A] {
v.push(2);
}
+ #[test]
+ #[should_fail]
+ fn test_overflow_does_not_cause_segfault_managed() {
+ let mut v = ~[@1];
+ v.reserve(-1);
+ v.push(@2);
+ }
+
#[test]
fn test_mut_split() {
let mut values = [1u8,2,3,4,5];
// fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_sctable() -> @mut SCTable {
- static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
+ local_data_key!(sctable_key: @@mut SCTable)
match local_data::get(sctable_key, |k| k.map_move(|k| *k)) {
None => {
let new_table = @@mut new_sctable_internal();
// okay, I admit, putting this in TLS is not so nice:
// fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_resolve_table() -> @mut ResolveTable {
- static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
+ local_data_key!(resolve_table_key: @@mut ResolveTable)
match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
None => {
let new_table = @@mut HashMap::new();
}
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
- static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
+ local_data_key!(tls_terminal: @Option<term::Terminal>)
let stderr = io::stderr();
self.expr(span, ast::ExprFnBlock(fn_decl, blk))
}
- #[cfg(stage0)]
- fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
- let ext_cx = *self;
- let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
- quote_expr!(|| $blk_e )
- }
- #[cfg(not(stage0))]
fn lambda0(&self, _span: Span, blk: ast::Block) -> @ast::Expr {
let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
quote_expr!(*self, || $blk_e )
}
- #[cfg(stage0)]
- fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
- let ext_cx = *self;
- let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
- quote_expr!(|$ident| $blk_e )
- }
- #[cfg(not(stage0))]
fn lambda1(&self, _span: Span, blk: ast::Block, ident: ast::Ident) -> @ast::Expr {
let blk_e = self.expr(blk.span, ast::ExprBlock(blk.clone()));
quote_expr!(*self, |$ident| $blk_e )
// string literal, push each byte to vector expression
ast::lit_str(s) => {
for byte in s.byte_iter() {
- bytes.push(cx.expr_u8(sp, byte));
+ bytes.push(cx.expr_u8(expr.span, byte));
}
}
// u8 literal, push to vector expression
ast::lit_uint(v, ast::ty_u8) => {
if v > 0xFF {
- cx.span_err(sp, "Too large u8 literal in bytes!")
+ cx.span_err(expr.span, "Too large u8 literal in bytes!")
} else {
- bytes.push(cx.expr_u8(sp, v as u8));
+ bytes.push(cx.expr_u8(expr.span, v as u8));
}
}
// integer literal, push to vector expression
ast::lit_int_unsuffixed(v) => {
if v > 0xFF {
- cx.span_err(sp, "Too large integer literal in bytes!")
+ cx.span_err(expr.span, "Too large integer literal in bytes!")
} else if v < 0 {
- cx.span_err(sp, "Negative integer literal in bytes!")
+ cx.span_err(expr.span, "Negative integer literal in bytes!")
} else {
- bytes.push(cx.expr_u8(sp, v as u8));
+ bytes.push(cx.expr_u8(expr.span, v as u8));
}
}
// char literal, push to vector expression
ast::lit_char(v) => {
if char::from_u32(v).unwrap().is_ascii() {
- bytes.push(cx.expr_u8(sp, v as u8));
+ bytes.push(cx.expr_u8(expr.span, v as u8));
} else {
- cx.span_err(sp, "Non-ascii char literal in bytes!")
+ cx.span_err(expr.span, "Non-ascii char literal in bytes!")
}
}
- _ => cx.span_err(sp, "Unsupported literal in bytes!")
+ _ => cx.span_err(expr.span, "Unsupported literal in bytes!")
},
- _ => cx.span_err(sp, "Non-literal in bytes!")
+ _ => cx.span_err(expr.span, "Non-literal in bytes!")
}
}
use std::os;
-#[cfg(stage0)]
-pub fn expand_option_env(ext_cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
- -> base::MacResult {
- let var = get_single_str_from_tts(ext_cx, sp, tts, "option_env!");
-
- let e = match os::getenv(var) {
- None => quote_expr!(::std::option::None::<&'static str>),
- Some(s) => quote_expr!(::std::option::Some($s))
- };
- MRExpr(e)
-}
-#[cfg(not(stage0))]
pub fn expand_option_env(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
-> base::MacResult {
let var = get_single_str_from_tts(cx, sp, tts, "option_env!");
use super::*;
- static key: ::std::local_data::Key<
- @::std::condition::Handler<$input, $out>> =
- &::std::local_data::Key;
+ local_data_key!(key: @::std::condition::Handler<$input, $out>)
pub static cond :
::std::condition::Condition<$input,$out> =
use super::*;
- static key: ::std::local_data::Key<
- @::std::condition::Handler<$input, $out>> =
- &::std::local_data::Key;
+ local_data_key!(key: @::std::condition::Handler<$input, $out>)
pub static cond :
::std::condition::Condition<$input,$out> =
}
)
- //
- // A scheme-style conditional that helps to improve code clarity in some instances when
- // the `if`, `else if`, and `else` keywords obscure predicates undesirably.
- //
- // # Example
- //
- // ~~~
- // let clamped =
- // if x > mx { mx }
- // else if x < mn { mn }
- // else { x };
- // ~~~
- //
- // Using `cond!`, the above could be written as:
- //
- // ~~~
- // let clamped = cond!(
- // (x > mx) { mx }
- // (x < mn) { mn }
- // _ { x }
- // );
- // ~~~
- //
- // The optional default case is denoted by `_`.
- //
- macro_rules! cond (
- ( $(($pred:expr) $body:block)+ _ $default:block ) => (
- $(if $pred $body else)+
- $default
- );
- // for if the default case was ommitted
- ( $(($pred:expr) $body:block)+ ) => (
- $(if $pred $body)else+
- );
- )
-
// NOTE(acrichto): start removing this after the next snapshot
macro_rules! printf (
($arg:expr) => (
($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
)
- // NOTE: use this after a snapshot lands to abstract the details
- // of the TLS interface.
macro_rules! local_data_key (
($name:ident: $ty:ty) => (
static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
self.ecx.span_err(sp, "expected token: `,`");
return (extra, None);
}
+ if *p.token == token::EOF { break } // accept trailing commas
if named || (token::is_ident(p.token) &&
p.look_ahead(1, |t| *t == token::EQ)) {
named = true;
'\\' => { c2 = '\\'; }
'\'' => { c2 = '\''; }
'"' => { c2 = '"'; }
+ '0' => { c2 = '\x00'; }
'x' => { c2 = scan_numeric_escape(rdr, 2u); }
'u' => { c2 = scan_numeric_escape(rdr, 4u); }
'U' => { c2 = scan_numeric_escape(rdr, 8u); }
'\'' => accum_str.push_char('\''),
'"' => accum_str.push_char('"'),
'\n' => consume_whitespace(rdr),
+ '0' => accum_str.push_char('\x00'),
'x' => {
accum_str.push_char(scan_numeric_escape(rdr, 2u));
}
#[test] fn string_to_tts_1 () {
let (tts,_ps) = string_to_tts_and_sess(@"fn a (b : int) { b; }");
assert_eq!(to_json_str(@tts),
- ~"[\
- [\"tt_tok\",null,[\"IDENT\",\"fn\",false]],\
- [\"tt_tok\",null,[\"IDENT\",\"a\",false]],\
- [\
- \"tt_delim\",\
- [\
- [\"tt_tok\",null,\"LPAREN\"],\
- [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
- [\"tt_tok\",null,\"COLON\"],\
- [\"tt_tok\",null,[\"IDENT\",\"int\",false]],\
- [\"tt_tok\",null,\"RPAREN\"]\
+ ~"[\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"fn\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"a\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_delim\",\
+ \"fields\":[\
+ [\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"LPAREN\"\
]\
- ],\
- [\
- \"tt_delim\",\
- [\
- [\"tt_tok\",null,\"LBRACE\"],\
- [\"tt_tok\",null,[\"IDENT\",\"b\",false]],\
- [\"tt_tok\",null,\"SEMI\"],\
- [\"tt_tok\",null,\"RBRACE\"]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"b\",\
+ false\
+ ]\
+ }\
]\
- ]\
- ]"
- );
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"COLON\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"int\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"RPAREN\"\
+ ]\
+ }\
+ ]\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_delim\",\
+ \"fields\":[\
+ [\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"LBRACE\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ {\
+ \"variant\":\"IDENT\",\
+ \"fields\":[\
+ \"b\",\
+ false\
+ ]\
+ }\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"SEMI\"\
+ ]\
+ },\
+ {\
+ \"variant\":\"tt_tok\",\
+ \"fields\":[\
+ null,\
+ \"RBRACE\"\
+ ]\
+ }\
+ ]\
+ ]\
+ }\
+]"
+ );
}
#[test] fn ret_expr() {
#[unsafe_destructor]
impl Drop for Parser {
/* do not copy the parser; its state is tied to outside state */
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn is_plain_ident_or_underscore(t: &token::Token) -> bool {
// if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one.
pub fn get_ident_interner() -> @ident_interner {
- static key: local_data::Key<@@::parse::token::ident_interner> =
- &local_data::Key;
+ local_data_key!(key: @@::parse::token::ident_interner)
match local_data::get(key, |k| k.map_move(|k| *k)) {
Some(interner) => *interner,
None => {
* the entire buffered window, but can't output anything until the size is >=
* 0 (sizes are set to negative while they're pending calculation).
*
- * So SCAN takeks input and buffers tokens and pending calculations, while
+ * So SCAN takes input and buffers tokens and pending calculations, while
* PRINT gobbles up completed calculations and tokens from the buffer. The
* theory is that the two can never get more than 3N tokens apart, because
* once there's "obviously" too much data to fit on a line, in a size
print_ident(s, segment.identifier);
- if segment.lifetime.is_some() || !segment.types.is_empty() {
- // If this is the last segment, print the bounds.
- if i == path.segments.len() - 1 {
- match *opt_bounds {
- None => {}
- Some(ref bounds) => print_bounds(s, bounds, true),
- }
+ // If this is the last segment, print the bounds.
+ if i == path.segments.len() - 1 {
+ match *opt_bounds {
+ None => {}
+ Some(ref bounds) => print_bounds(s, bounds, true),
}
+ }
+ if segment.lifetime.is_some() || !segment.types.is_empty() {
if colons_before_params {
word(s.s, "::")
}
VALGRIND_STACK_DEREGISTER(id);
}
+#if defined(__WIN32__)
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // empty stub for windows to keep linker happy
+}
+
+#else
+
+#include <signal.h>
+#include <unistd.h>
+
+extern "C" CDECL void
+rust_unset_sigprocmask() {
+ // this can't be safely converted to rust code because the
+ // representation of sigset_t is platform-dependent
+ sigset_t sset;
+ sigemptyset(&sset);
+ sigprocmask(SIG_SETMASK, &sset, NULL);
+}
+
+#endif
+
//
// Local Variables:
// mode: C++
+++ /dev/null
-// 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.
-
-
-#include "rust_globals.h"
-
-#ifdef __APPLE__
-#include <crt_externs.h>
-#endif
-
-#if defined(__WIN32__)
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
- // empty stub for windows to keep linker happy
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
- // empty stub for windows to keep linker happy
-}
-
-#elif defined(__GNUC__)
-
-#include <signal.h>
-#include <unistd.h>
-
-#ifdef __FreeBSD__
-extern char **environ;
-#endif
-
-extern "C" CDECL void
-rust_unset_sigprocmask() {
- // this can't be safely converted to rust code because the
- // representation of sigset_t is platform-dependent
- sigset_t sset;
- sigemptyset(&sset);
- sigprocmask(SIG_SETMASK, &sset, NULL);
-}
-
-extern "C" CDECL void
-rust_set_environ(void* envp) {
- // FIXME: this could actually be converted to rust (see issue #2674)
-#ifdef __APPLE__
- *_NSGetEnviron() = (char **) envp;
-#else
- environ = (char **) envp;
-#endif
-}
-
-#else
-#error "Platform not supported."
-#endif
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
-// End:
-//
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
return req->result;
}
+extern "C" void*
+rust_uv_get_ptr_from_fs_req(uv_fs_t* req) {
+ return req->ptr;
+}
extern "C" uv_loop_t*
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
return req->loop;
rust_uv_get_loop_from_getaddrinfo_req(uv_getaddrinfo_t* req) {
return req->loop;
}
+
+extern "C" int
+rust_uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ return uv_fs_stat(loop, req, path, cb);
+}
+extern "C" int
+rust_uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ return uv_fs_fstat(loop, req, file, cb);
+}
+
+extern "C" void
+rust_uv_populate_uv_stat(uv_fs_t* req_in, uv_stat_t* stat_out) {
+ stat_out->st_dev = req_in->statbuf.st_dev;
+ stat_out->st_mode = req_in->statbuf.st_mode;
+ stat_out->st_nlink = req_in->statbuf.st_nlink;
+ stat_out->st_uid = req_in->statbuf.st_uid;
+ stat_out->st_gid = req_in->statbuf.st_gid;
+ stat_out->st_rdev = req_in->statbuf.st_rdev;
+ stat_out->st_ino = req_in->statbuf.st_ino;
+ stat_out->st_size = req_in->statbuf.st_size;
+ stat_out->st_blksize = req_in->statbuf.st_blksize;
+ stat_out->st_blocks = req_in->statbuf.st_blocks;
+ stat_out->st_flags = req_in->statbuf.st_flags;
+ stat_out->st_gen = req_in->statbuf.st_gen;
+ stat_out->st_atim.tv_sec = req_in->statbuf.st_atim.tv_sec;
+ stat_out->st_atim.tv_nsec = req_in->statbuf.st_atim.tv_nsec;
+ stat_out->st_mtim.tv_sec = req_in->statbuf.st_mtim.tv_sec;
+ stat_out->st_mtim.tv_nsec = req_in->statbuf.st_mtim.tv_nsec;
+ stat_out->st_ctim.tv_sec = req_in->statbuf.st_ctim.tv_sec;
+ stat_out->st_ctim.tv_nsec = req_in->statbuf.st_ctim.tv_nsec;
+ stat_out->st_birthtim.tv_sec = req_in->statbuf.st_birthtim.tv_sec;
+ stat_out->st_birthtim.tv_nsec = req_in->statbuf.st_birthtim.tv_nsec;
+}
+
+extern "C" int
+rust_uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) {
+ return uv_fs_mkdir(loop, req, path, mode, cb);
+}
+extern "C" int
+rust_uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ return uv_fs_rmdir(loop, req, path, cb);
+}
+
+extern "C" int
+rust_uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb) {
+ return uv_fs_readdir(loop, req, path, flags, cb);
+}
+
+extern "C" int
+rust_uv_spawn(uv_loop_t *loop, uv_process_t *p, uv_process_options_t options) {
+ return uv_spawn(loop, p, options);
+}
+
+extern "C" int
+rust_uv_process_kill(uv_process_t *p, int signum) {
+ return uv_process_kill(p, signum);
+}
+
+extern "C" void
+rust_set_stdio_container_flags(uv_stdio_container_t *c, int flags) {
+ c->flags = (uv_stdio_flags) flags;
+}
+
+extern "C" void
+rust_set_stdio_container_fd(uv_stdio_container_t *c, int fd) {
+ c->data.fd = fd;
+}
+
+extern "C" void
+rust_set_stdio_container_stream(uv_stdio_container_t *c, uv_stream_t *stream) {
+ c->data.stream = stream;
+}
+
+extern "C" int
+rust_uv_process_pid(uv_process_t* p) {
+ return p->pid;
+}
+
+extern "C" int
+rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
+ return uv_pipe_init(loop, p, ipc);
+}
rust_log_console_on
rust_log_console_off
rust_should_log_console
-rust_set_environ
rust_unset_sigprocmask
rust_env_pairs
upcall_rust_personality
rust_uv_fs_read
rust_uv_fs_close
rust_uv_get_result_from_fs_req
+rust_uv_get_ptr_from_fs_req
rust_uv_get_loop_from_fs_req
+rust_uv_fs_stat
+rust_uv_fs_fstat
rust_uv_fs_req_cleanup
+rust_uv_populate_uv_stat
+rust_uv_fs_mkdir
+rust_uv_fs_rmdir
+rust_uv_fs_readdir
rust_dbg_lock_create
rust_dbg_lock_destroy
rust_dbg_lock_lock
rust_get_test_int
rust_get_task
rust_uv_get_loop_from_getaddrinfo_req
+rust_uv_spawn
+rust_uv_process_kill
+rust_set_stdio_container_flags
+rust_set_stdio_container_fd
+rust_set_stdio_container_stream
+rust_uv_process_pid
+rust_uv_pipe_init
ResolvedPath {path: path.clone(), typarams: tpbs.clone(), id: def_id.node}
}
}
-
-#[cfg(test)]
-mod tests {
- use super::NameValue;
-
- #[test]
- fn test_doc_collapsing() {
- assert_eq!(collapse_docs(~"// Foo\n//Bar\n // Baz\n"), ~"Foo\nBar\nBaz");
- assert_eq!(collapse_docs(~"* Foo\n * Bar\n *Baz\n"), ~"Foo\n Bar\nBaz");
- assert_eq!(collapse_docs(~"* Short desc\n *\n * Bar\n *Baz\n"), ~"Short desc\n\nBar\nBaz");
- assert_eq!(collapse_docs(~" * Foo"), ~"Foo");
- assert_eq!(collapse_docs(~"\n *\n *\n * Foo"), ~"Foo");
- }
-
- fn collapse_docs(input: ~str) -> ~str {
- let attrs = ~[NameValue(~"doc", input)];
- let attrs_clean = super::collapse_docs(attrs);
-
- match attrs_clean[0] {
- NameValue(~"doc", s) => s,
- _ => (fail!("dude where's my doc?"))
- }
- }
-}
+++ /dev/null
-// Copyright 2012-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.
-
-#[link(name = "rustdoc_ng",
- vers = "0.1.0",
- uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
-#[desc = "rustdoc, the Rust documentation extractor"];
-#[license = "MIT/ASL2"];
-#[crate_type = "lib"];
-
-#[deny(warnings)];
-
-extern mod syntax;
-extern mod rustc;
-
-extern mod extra;
-
-use extra::serialize::Encodable;
-
-pub mod core;
-pub mod doctree;
-pub mod clean;
-pub mod visit_ast;
-pub mod fold;
-pub mod plugins;
-pub mod passes;
-
-pub static SCHEMA_VERSION: &'static str = "0.8.0";
-
-pub static ctxtkey: std::local_data::Key<@core::DocContext> = &std::local_data::Key;
+++ /dev/null
-// Copyright 2012-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.
-
-#[link(name = "rustdoc_ng",
- vers = "0.1.0",
- uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6")];
-#[desc = "rustdoc, the Rust documentation extractor"];
-#[license = "MIT/ASL2"];
-#[crate_type = "bin"];
-
-extern mod extra;
-extern mod rustdoc_ng;
-
-use rustdoc_ng::*;
-use std::cell::Cell;
-
-use extra::serialize::Encodable;
-
-fn main() {
- use extra::getopts::*;
- use extra::getopts::groups::*;
-
- let args = std::os::args();
- let opts = ~[
- optmulti("L", "library-path", "directory to add to crate search path", "DIR"),
- optmulti("p", "plugin", "plugin to load and run", "NAME"),
- optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
- // auxillary pass (defaults to hidden_strip
- optmulti("a", "pass", "auxillary pass to run", "NAME"),
- optflag("n", "no-defult-passes", "do not run the default passes"),
- optflag("h", "help", "show this help message"),
- ];
-
- let matches = getopts(args.tail(), opts).unwrap();
-
- if opt_present(&matches, "h") || opt_present(&matches, "help") {
- println(usage(args[0], opts));
- return;
- }
-
- let libs = Cell::new(opt_strs(&matches, "L").map(|s| Path(*s)));
-
- let mut passes = if opt_present(&matches, "n") {
- ~[]
- } else {
- ~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
- };
-
- opt_strs(&matches, "a").map(|x| passes.push(x.clone()));
-
- if matches.free.len() != 1 {
- println(usage(args[0], opts));
- return;
- }
-
- let cr = Cell::new(Path(matches.free[0]));
-
- let crate = std::task::try(|| {let cr = cr.take(); core::run_core(libs.take(), &cr)}).unwrap();
-
- // { "schema": version, "crate": { parsed crate ... }, "plugins": { output of plugins ... }}
- let mut json = ~extra::treemap::TreeMap::new();
- json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
-
- let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
-
- for pass in passes.iter() {
- pm.add_plugin(match pass.as_slice() {
- "strip-hidden" => passes::strip_hidden,
- "clean-comments" => passes::clean_comments,
- "collapse-docs" => passes::collapse_docs,
- "collapse-privacy" => passes::collapse_privacy,
- s => { error!("unknown pass %s, skipping", s); passes::noop },
- })
- }
-
- for pname in opt_strs(&matches, "p").move_iter() {
- pm.load_plugin(pname);
- }
-
- let (crate, res) = pm.run_plugins(crate);
- let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
-
- // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
- // straight to the Rust JSON representation.
- let crate_json_str = do std::io::with_str_writer |w| {
- crate.encode(&mut extra::json::Encoder(w));
- };
- let crate_json = match extra::json::from_str(crate_json_str) {
- Ok(j) => j,
- Err(_) => fail!("Rust generated JSON is invalid??")
- };
-
- json.insert(~"crate", crate_json);
- json.insert(~"plugins", extra::json::Object(plugins_json));
-
- println(extra::json::Object(json).to_str());
-}
--- /dev/null
+// Copyright 2012-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.
+
+#[link(name = "rustdoc_ng",
+ vers = "0.8-pre",
+ uuid = "8c6e4598-1596-4aa5-a24c-b811914bbbc6",
+ url = "https://github.com/mozilla/rust/tree/master/src/rustdoc_ng")];
+
+#[desc = "rustdoc, the Rust documentation extractor"];
+#[license = "MIT/ASL2"];
+#[crate_type = "lib"];
+
+extern mod syntax;
+extern mod rustc;
+extern mod extra;
+
+use extra::serialize::Encodable;
+use std::cell::Cell;
+
+pub mod core;
+pub mod doctree;
+pub mod clean;
+pub mod visit_ast;
+pub mod fold;
+pub mod plugins;
+pub mod passes;
+
+pub static SCHEMA_VERSION: &'static str = "0.8.0";
+
+local_data_key!(pub ctxtkey: @core::DocContext)
+
+pub fn main() {
+ main_args(std::os::args());
+}
+
+pub fn main_args(args: &[~str]) {
+ use extra::getopts::groups::*;
+
+ let opts = ~[
+ optmulti("L", "library-path", "directory to add to crate search path", "DIR"),
+ optmulti("p", "plugin", "plugin to load and run", "NAME"),
+ optmulti("", "plugin-path", "directory to load plugins from", "DIR"),
+ // auxillary pass (defaults to hidden_strip
+ optmulti("a", "pass", "auxillary pass to run", "NAME"),
+ optflag("n", "no-defult-passes", "do not run the default passes"),
+ optflag("h", "help", "show this help message"),
+ ];
+
+ let matches = getopts(args.tail(), opts).unwrap();
+
+ if matches.opt_present("h") || matches.opt_present("help") {
+ println(usage(args[0], opts));
+ return;
+ }
+
+ let libs = Cell::new(matches.opt_strs("L").map(|s| Path(*s)));
+
+ let mut passes = if matches.opt_present("n") {
+ ~[]
+ } else {
+ ~[~"collapse-docs", ~"clean-comments", ~"collapse-privacy" ]
+ };
+
+ matches.opt_strs("a").map(|x| passes.push(x.clone()));
+
+ if matches.free.len() != 1 {
+ println(usage(args[0], opts));
+ return;
+ }
+
+ let cr = Cell::new(Path(matches.free[0]));
+
+ let crate = do std::task::try {
+ let cr = cr.take();
+ core::run_core(libs.take(), &cr)
+ }.unwrap();
+
+ // { "schema": version, "crate": { parsed crate ... }, "plugins": { output of plugins ... }}
+ let mut json = ~extra::treemap::TreeMap::new();
+ json.insert(~"schema", extra::json::String(SCHEMA_VERSION.to_owned()));
+
+ let mut pm = plugins::PluginManager::new(Path("/tmp/rustdoc_ng/plugins"));
+
+ for pass in passes.iter() {
+ pm.add_plugin(match pass.as_slice() {
+ "strip-hidden" => passes::strip_hidden,
+ "clean-comments" => passes::clean_comments,
+ "collapse-docs" => passes::collapse_docs,
+ "collapse-privacy" => passes::collapse_privacy,
+ s => { error!("unknown pass %s, skipping", s); passes::noop },
+ })
+ }
+
+ for pname in matches.opt_strs("p").move_iter() {
+ pm.load_plugin(pname);
+ }
+
+ let (crate, res) = pm.run_plugins(crate);
+ let plugins_json = ~res.move_iter().filter_map(|opt| opt).collect();
+
+ // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
+ // straight to the Rust JSON representation.
+ let crate_json_str = do std::io::with_str_writer |w| {
+ crate.encode(&mut extra::json::Encoder(w));
+ };
+ let crate_json = match extra::json::from_str(crate_json_str) {
+ Ok(j) => j,
+ Err(_) => fail!("Rust generated JSON is invalid??")
+ };
+
+ json.insert(~"crate", crate_json);
+ json.insert(~"plugins", extra::json::Object(plugins_json));
+
+ println(extra::json::Object(json).to_str());
+}
+S 2013-09-17 cbd1eef
+ freebsd-x86_64 9166867a8859076343cb3e57da918b5c0eea720b
+ linux-i386 38347b579312ff30c36d257a1161660eb0ae8422
+ linux-x86_64 0c169bba5d6729d0c0f096d61d9274fb082b4b34
+ macos-i386 1eb229510dd12b91800674566b8dad401a3f80d3
+ macos-x86_64 1c5d8e29b9671af93963e1b5fa9fcca081124a39
+ winnt-i386 56baa04a1f02235ebc5a75be05aa65fdc822a4e6
+
S 2013-08-14 e7b5729
freebsd-x86_64 9de0b5583a5c4413f9e77df7071498385e936dd2
linux-i386 29119a9072f74c639c2bad998edc40e582da540e
#[unsafe_destructor]
impl<T:Freeze> Drop for arc_destruct<T> {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn arc_destruct<T:Freeze>(data: int) -> arc_destruct<T> {
}
impl Drop for context_res {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn context_res() -> context_res {
}
impl Drop for socket_handle {
- fn drop(&self) {
+ fn drop(&mut self) {
/* c::close(self.sockfd); */
}
}
--- /dev/null
+// 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.
+
+#[link(name = "numeric",
+ vers = "0.1")];
+#[crate_type = "lib"];
+
+pub trait Trig<T> {
+ fn sin(&self) -> T;
+}
+
+pub fn sin<T:Trig<R>, R>(theta: &T) -> R { theta.sin() }
+
+pub trait Angle<T>: Trig<T> {}
}
impl Drop for rsrc {
- fn drop(&self) {
+ fn drop(&mut self) {
foo(self.x);
}
}
}
impl Drop for S {
- fn drop(&self) {
+ fn drop(&mut self) {
println("goodbye");
}
}
--- /dev/null
+// 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.
+
+pub fn foo<T>() -> int {
+ #[address_insignificant]
+ static a: int = 3;
+ a
+}
+
+pub fn bar() -> int {
+ foo::<int>()
+}
pub static global: int = 3;
+static global0: int = 4;
+pub static global2: &'static int = &global0;
+
pub fn verify_same(a: &'static int) {
let a = a as *int as uint;
let b = &global as *int as uint;
assert_eq!(a, b);
}
+pub fn verify_same2(a: &'static int) {
+ let a = a as *int as uint;
+ let b = global2 as *int as uint;
+ assert_eq!(a, b);
+}
+
condition!{ pub test: int -> (); }
pub fn raise() {
match getopts::getopts(opt_args, opts) {
Ok(ref m) => {
- return Config {stress: getopts::opt_present(m, "stress")}
+ return Config {stress: m.opt_present("stress")}
}
Err(_) => { fail!(); }
}
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn r(l: @nillist) -> r {
struct X { x: () }
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("destructor runs");
}
}
struct X { x: (), }
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("destructor runs");
}
}
struct X { x: (), }
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("destructor runs");
}
}
struct X { x: (), }
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("destructor runs");
}
}
struct X { x: (), }
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("destructor runs");
}
}
struct r;
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
true
}
}
#[unsafe_destructor]
impl<'self> Drop for defer<'self> {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
error!("%?", self.x);
}
struct S {f:~str}
impl Drop for S {
- fn drop(&self) { println(self.f); }
+ fn drop(&mut self) { println(self.f); }
}
fn move_in_match() {
struct S(~str);
impl Drop for S {
- fn drop(&self) { println(**self); }
+ fn drop(&mut self) { println(**self); }
}
fn move_in_match() {
}
impl Drop for foo {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn foo(i:int) -> foo {
}
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("value: %s", self.x);
}
}
}
impl Drop for X {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("value: %s", self.x);
}
}
impl Drop for Foo { //~ ERROR the Drop trait may only be implemented
//~^ ERROR cannot provide an extension implementation
- fn drop(&self) {
+ fn drop(&mut self) {
println("kaboom");
}
}
}
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
println("kaboom");
}
}
}
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
println("kaboom");
}
}
struct A { y: Arc<int>, x: Arc<int> }
impl Drop for A {
- fn drop(&self) { println(fmt!("x=%?", self.x.get())); }
+ fn drop(&mut self) { println(fmt!("x=%?", self.x.get())); }
}
fn main() {
let a = A { y: Arc::new(1), x: Arc::new(2) };
#[unsafe_destructor]
impl Drop for foo {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
println("Goodbye, World!");
*self.x += 1;
}
impl Drop for C {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("dropping: %?", self.x);
}
}
}
impl<T> Drop for foo<T> {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
}
fn main() { }
}
impl Drop for Foo { //~ ERROR cannot implement a destructor on a structure that does not satisfy Send
- fn drop(&self) {
+ fn drop(&mut self) {
*self.f = 10;
}
}
#[unsafe_destructor]
impl Drop for foo {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn foo(x: Port<()>) -> foo {
}
impl Drop for bar {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn bar(x:int) -> bar {
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
*(self.i) = *(self.i) + 1;
}
}
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
println("Goodbye!");
}
}
}
impl Drop for Bar {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
impl Foo for Bar {
}
impl Drop for r {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
*(self.i) = *(self.i) + 1;
}
}
impl Drop for S {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
impl S {
fn r(i:int) -> r { r { i: i } }
impl Drop for r {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {
}
impl Drop for StructWithDestructor {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {
}
impl Drop for StructWithDrop {
- fn drop(&self) {()}
+ fn drop(&mut self) {()}
}
fn main() {
}
impl Drop for Packed {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
#[packed]
}
impl Drop for Unpacked {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
#[packed]
}
impl Drop for PackedInPackedWithDrop {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
struct PackedInUnpackedWithDrop {
}
impl Drop for PackedInUnpackedWithDrop {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
#[packed]
}
impl Drop for UnpackedInPackedWithDrop {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
struct DeeplyNested {
}
impl Drop for WithDestructor {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
struct NoDestructorGuarded {
}
impl Drop for NestedInner {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
struct NestedOuter {
--- /dev/null
+// pp-exact
+
+trait Tr { }
+impl Tr for int;
+
+fn foo(x: ~Tr: Freeze) -> ~Tr: Freeze { x }
+
+fn main() {
+ let x: ~Tr: Freeze;
+
+ ~1 as ~Tr: Freeze;
+}
+
}
impl Drop for R {
- fn drop(&self) {
+ fn drop(&mut self) {
let _y = R { b: self.b };
}
}
}
impl Drop for and_then_get_big_again {
- fn drop(&self) {
+ fn drop(&mut self) {
fn getbig(i: int) {
if i != 0 {
getbig(i - 1);
}
impl Drop for and_then_get_big_again {
- fn drop(&self) {
+ fn drop(&mut self) {
fn getbig(i: int) {
if i != 0 {
getbig(i - 1);
}
impl Drop for and_then_get_big_again {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn and_then_get_big_again(x:int) -> and_then_get_big_again {
// failed has no effect and the process exits with the
// runtime's exit code
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
os::set_exit_status(50);
}
}
}
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
if !*(self.recursed) {
*(self.recursed) = true;
}
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
let _v2: ~int = cast::transmute(self.v);
}
}
impl Drop for r {
- fn drop(&self) { fail!("squirrel") }
+ fn drop(&mut self) { fail!("squirrel") }
}
fn r(i: int) -> r { r { i: i } }
}
impl Drop for r {
- fn drop(&self) { fail!("wombat") }
+ fn drop(&mut self) { fail!("wombat") }
}
fn r(i: int) -> r { r { i: i } }
#[unsafe_destructor]
impl Drop for faily_box {
- fn drop(&self) {
+ fn drop(&mut self) {
fail!("quux");
}
}
#[unsafe_destructor]
impl<T> Drop for Test<T> {
- fn drop(&self) { }
+ fn drop(&mut self) { }
}
fn main() {
}
impl Drop for noncopyable {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("dropped");
}
}
impl Drop for cat {
#[cat_dropper]
- fn drop(&self) { error!("%s landed on hir feet" , self . name); }
+ fn drop(&mut self) { error!("%s landed on hir feet" , self . name); }
}
/**
Actually, cats don't always land on their feet when you drop them.
*/
- fn drop(&self) {
+ fn drop(&mut self) {
error!("%s landed on hir feet", self.name);
}
}
}
impl Drop for cat {
- fn drop(&self) {
+ fn drop(&mut self) {
(self.done)(self.meows);
}
}
+++ /dev/null
-// 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.
-
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
- cond!(
- (x > mx) { return mx; }
- (x < mn) { return mn; }
- )
- return x;
-}
-
-fn main() {
- assert_eq!(clamp(1, 2, 4), 2);
- assert_eq!(clamp(8, 2, 4), 4);
- assert_eq!(clamp(3, 2, 4), 3);
-}
+++ /dev/null
-// 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.
-
-fn clamp<T:Ord + Signed>(x: T, mn: T, mx: T) -> T {
- cond!(
- (x > mx) { mx }
- (x < mn) { mn }
- _ { x }
- )
-}
-
-fn main() {
- assert_eq!(clamp(1, 2, 4), 2);
- assert_eq!(clamp(8, 2, 4), 4);
- assert_eq!(clamp(3, 2, 4), 3);
-}
#[unsafe_destructor]
impl<T> ::std::ops::Drop for S<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
println("bye");
}
}
}
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
println("bye");
}
}
// except according to those terms.
// Test that we ignore modes when calling extern functions.
+// xfail-fast #9205
#[deriving(Eq)]
struct TwoU64s {
// xfail-fast This works standalone on windows but not with check-fast.
// possibly because there is another test that uses this extern fn but gives it
// a different signature
+// xfail-fast #9205
#[deriving(Eq)]
struct TwoU64s {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-fast #9205
+
struct TwoU64s {
one: u64, two: u64
}
match getopts(args, opts) {
Ok(ref m) =>
- assert!(!opt_present(m, "b")),
- Err(ref f) => fail!(fail_str((*f).clone()))
+ assert!(!m.opt_present("b")),
+ Err(ref f) => fail!((*f).clone().to_err_msg())
};
}
}
test_format_args();
+
+ // test that trailing commas are acceptable
+ format!("{}", "test",);
+ format!("{foo}", foo="test",);
}
// Basic test to make sure that we can invoke the `write!` macro with an
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
*(self.i) = *(self.i) + 1;
}
}
}
impl Drop for socket {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
impl socket {
}
impl Drop for Font {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn Font() -> Font {
#[unsafe_destructor]
impl<T:Send> Drop for send_packet<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
if self.p != None {
let self_p: &mut Option<*packet<T>> =
#[unsafe_destructor]
impl<T:Send> Drop for recv_packet<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
if self.p != None {
let self_p: &mut Option<*packet<T>> =
#[unsafe_destructor]
impl Drop for defer {
- fn drop(&self) {
+ fn drop(&mut self) {
*self.b = true;
}
}
#[unsafe_destructor]
impl Drop for defer {
- fn drop(&self) {
+ fn drop(&mut self) {
*self.b = true;
}
}
}
impl Drop for Kitty {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
#[cfg(target_arch = "x86_64")]
struct thing { x: int, }
impl Drop for thing {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn thing() -> thing {
}
impl Drop for AsciiArt {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
// It's common to define a constructor sort of function to create struct instances.
--- /dev/null
+// 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.
+
+// aux-build:issue-4208-cc.rs
+// xfail-fast - Windows hates cross-crate tests
+
+extern mod numeric;
+use numeric::*;
+
+fn foo<T, A:Angle<T>>(theta: A) -> T { sin(&theta) }
+
+fn main() {}
}
impl<T: X> Drop for Z<T> {
- fn drop(&self) {
+ fn drop(&mut self) {
self.x.call(); // Adding this statement causes an ICE.
}
}
struct NonCopyable(*c_void);
impl Drop for NonCopyable {
- fn drop(&self) {
+ fn drop(&mut self) {
let p = **self;
let _v = unsafe { transmute::<*c_void, ~int>(p) };
}
--- /dev/null
+// 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.
+
+/*
+
+#5008 cast to &Trait causes code to segfault on method call
+
+It fixes itself if the &Trait is changed to @Trait.
+*/
+
+trait Debuggable {
+ fn debug_name(&self) -> ~str;
+}
+
+#[deriving(Clone)]
+struct Thing {
+name: ~str,
+}
+
+impl Thing {
+ fn new() -> Thing { Thing { name: ~"dummy" } }
+}
+
+impl Debuggable for Thing {
+ fn debug_name(&self) -> ~str { self.name.clone() }
+}
+
+fn print_name(x: &Debuggable)
+{
+ println(fmt!("debug_name = %s", x.debug_name()));
+}
+
+fn main() {
+ let thing = Thing::new();
+ print_name(&thing as &Debuggable);
+}
struct A { x: uint }
impl Drop for A {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {}
\ No newline at end of file
struct A { x: uint }
impl Drop for A {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {
struct A { x: uint }
impl Drop for A {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn main() {
--- /dev/null
+// 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.
+
+/*
+#7519 ICE pattern matching unit in function argument
+*/
+
+fn foo(():()) { }
+
+fn main() {
+ foo(());
+}
--- /dev/null
+// 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.
+
+/*
+
+#7673 Polymorphically creating traits barely works
+
+*/
+
+fn main() {}
+
+trait A {}
+impl<T: 'static> A for T {}
+
+fn owned1<T: 'static>(a: T) { ~a as ~A:; } /* note `:` */
+fn owned2<T: 'static>(a: ~T) { a as ~A:; }
+fn owned3<T: 'static>(a: ~T) { ~a as ~A:; }
+
+fn managed1<T: 'static>(a: T) { @a as @A; }
+fn managed2<T: 'static>(a: @T) { a as @A; }
+fn managed3<T: 'static>(a: @T) { @a as @A; }
--- /dev/null
+// 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.
+
+/*
+
+#8171 Self is not recognised as implementing kinds in default method implementations
+
+*/
+
+fn require_send<T: Send>(_: T){}
+
+trait TragicallySelfIsNotSend: Send {
+ fn x(self) {
+ require_send(self);
+ }
+}
+
+fn main(){}
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
*(self.b) += 1;
}
}
--- /dev/null
+// 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.
+
+/*
+
+#7770 ICE with sibling methods containing same-name-enum containing
+ same-name-member
+
+If you have two methods in an impl block, each containing an enum
+(with the same name), each containing at least one value with the same
+name, rustc gives the same LLVM symbol for the two of them and fails,
+as it does not include the method name in the symbol name.
+
+*/
+
+pub struct Foo;
+impl Foo {
+ pub fn foo() {
+ enum Panic { Common };
+ }
+ pub fn bar() {
+ enum Panic { Common };
+ }
+}
+
+/*
+#2074 duplicate symbols with enum in boxed closure
+*/
+
+fn foo() {
+ let one: @fn() -> uint = || {
+ enum r { a }
+ a as uint
+ };
+ let two: @fn() -> uint = || {
+ enum r { a }
+ a as uint
+ };
+ one(); two();
+}
+
+fn main() {}
#[unsafe_destructor]
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
***self = 23;
}
}
impl Drop for Fd {
#[fixed_stack_segment] #[inline(never)]
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
libc::close(**self);
}
--- /dev/null
+// 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.
+
+pub fn main()
+{
+ let all_nuls1 = "\0\x00\u0000\U00000000";
+ let all_nuls2 = "\U00000000\u0000\x00\0";
+ let all_nuls3 = "\u0000\U00000000\x00\0";
+ let all_nuls4 = "\x00\u0000\0\U00000000";
+
+ // sizes for two should suffice
+ assert_eq!(all_nuls1.len(), 4);
+ assert_eq!(all_nuls2.len(), 4);
+
+ // string equality should pass between the strings
+ assert_eq!(all_nuls1, all_nuls2);
+ assert_eq!(all_nuls2, all_nuls3);
+ assert_eq!(all_nuls3, all_nuls4);
+
+ // all extracted characters in all_nuls are equivalent to each other
+ for c1 in all_nuls1.iter()
+ {
+ for c2 in all_nuls1.iter()
+ {
+ assert_eq!(c1,c2);
+ }
+ }
+
+ // testing equality between explicit character literals
+ assert_eq!('\0', '\x00');
+ assert_eq!('\u0000', '\x00');
+ assert_eq!('\u0000', '\U00000000');
+
+ // NUL characters should make a difference
+ assert!("Hello World" != "Hello \0World");
+ assert!("Hello World" != "Hello World\0");
+}
#[unsafe_destructor]
impl Drop for dtor {
- fn drop(&self) {
+ fn drop(&mut self) {
// abuse access to shared mutable state to write this code
*self.x -= 1;
}
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
*(self.i) += 1;
}
}
}
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
info!("r's dtor: self = %x, self.v = %x, self.v's value = %x",
- cast::transmute::<*r, uint>(self),
+ cast::transmute::<*mut r, uint>(self),
cast::transmute::<**int, uint>(&(self.v)),
cast::transmute::<*int, uint>(self.v));
let _v2: ~int = cast::transmute(self.v);
}
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
let _v2: ~int = cast::transmute(self.v.c);
}
}
impl Drop for R {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
let _v2: ~int = cast::transmute(self.v.c);
// let _v3: ~int = cast::transmute_copy(self.x);
#[unsafe_destructor]
impl Drop for shrinky_pointer {
- fn drop(&self) {
+ fn drop(&mut self) {
error!(~"Hello!"); **(self.i) -= 1;
}
}
#[unsafe_destructor]
impl Drop for close_res {
- fn drop(&self) {
+ fn drop(&mut self) {
*(self.i) = false;
}
}
}
impl Drop for test {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn test(f: int) -> test {
}
impl Drop for foo {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("%s", self.x);
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-fast #9205
+
pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
pub struct Floats { a: f64, b: u8, c: f64 }
#[unsafe_destructor]
impl Drop for notify {
- fn drop(&self) {
+ fn drop(&mut self) {
unsafe {
error!("notify: task=%? v=%x unwinding=%b b=%b",
0,
}
impl Drop for r {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn r(i:int) -> r {
#[unsafe_destructor]
impl Drop for r {
- fn drop(&self) {
+ fn drop(&mut self) {
*(self.i) = *(self.i) + 1;
}
}
struct Foo;
impl Drop for Foo {
- fn drop(&self) {
+ fn drop(&mut self) {
fail!("This failure should happen.");
}
}
}
impl Drop for complainer {
- fn drop(&self) {
+ fn drop(&mut self) {
error!("About to send!");
self.c.send(true);
error!("Sent!");
#[unsafe_destructor]
impl Drop for complainer {
- fn drop(&self) {}
+ fn drop(&mut self) {}
}
fn complainer(c: @int) -> complainer {
#[unsafe_destructor]
impl Drop for foo {
- fn drop(&self) {
+ fn drop(&mut self) {
*self.x += 1;
}
}
--- /dev/null
+// 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.
+
+// xfail-fast windows doesn't like aux-build
+// aux-build:xcrate_address_insignificant.rs
+
+extern mod foo(name = "xcrate_address_insignificant");
+
+fn main() {
+ assert_eq!(foo::foo::<float>(), foo::bar());
+}
pub fn main() {
other::verify_same(&other::global);
+ other::verify_same2(other::global2);
// Previously this fail'd because there were two addresses that were being
// used when declaring constants.