branch = master
[submodule "src/libuv"]
path = src/libuv
- url = https://github.com/alexcrichton/libuv.git
+ url = https://github.com/brson/libuv.git
branch = master
do
else enum extern
false fn for
-if impl
+if impl in
let loop
match mod mut
priv pub
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS)
@$$(call E, make: llvm)
- $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
+ $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV)
$$(Q)touch $$(LLVM_CONFIG_$(1))
endif
$(foreach t,$(CFG_TARGET_TRIPLES),$(eval $(call DEF_OSTYPE_VAR,$(t))))
$(foreach t,$(CFG_TARGET_TRIPLES),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
-CFG_GCCISH_CFLAGS += -DUSE_UTF8
+# FIXME: no-omit-frame-pointer is just so that task_start_wrapper
+# has a frame pointer and the stack walker can understand it. Turning off
+# frame pointers everywhere is overkill
+CFG_GCCISH_CFLAGS += -fno-omit-frame-pointer -DUSE_UTF8
# On Darwin, we need to run dsymutil so the debugging information ends
# up in the right place. On other platforms, it automatically gets
CFG_DEF_SUFFIX_x86_64-unknown-linux-gnu := .linux.def
CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
CFG_LIBUV_LINK_FLAGS_x86_64-unknown-linux-gnu =
+CFG_LLVM_BUILD_ENV_x86_64-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
CFG_UNIXY_x86_64-unknown-linux-gnu := 1
CFG_DEF_SUFFIX_i686-unknown-linux-gnu := .linux.def
CFG_INSTALL_NAME_i686-unknown-linux-gnu =
CFG_LIBUV_LINK_FLAGS_i686-unknown-linux-gnu =
+CFG_LLVM_BUILD_ENV_i686-unknown-linux-gnu="CXXFLAGS=-fno-omit-frame-pointer"
CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
CFG_WINDOWSY_i686-unknown-linux-gnu :=
CFG_UNIXY_i686-unknown-linux-gnu := 1
$$(S)src/libuv/*/*/*/*)
endif
-LIBUV_GYP := $$(S)src/libuv/build/gyp
-LIBUV_MAKEFILE_$(1)_$(2) := $$(CFG_BUILD_DIR)rt/$(1)/stage$(2)/libuv/Makefile
-LIBUV_NO_LOAD = run-benchmarks.target.mk run-tests.target.mk \
- uv_dtrace_header.target.mk uv_dtrace_provider.target.mk
-
-$$(LIBUV_MAKEFILE_$(1)_$(2)): $$(LIBUV_GYP)
- (cd $(S)src/libuv/ && \
- $$(CFG_PYTHON) ./gyp_uv -f make -Dtarget_arch=$$(LIBUV_ARCH_$(1)) -D ninja \
- -Goutput_dir=$$(@D) --generator-output $$(@D))
-
# XXX: Shouldn't need platform-specific conditions here
ifdef CFG_WINDOWSY_$(1)
$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
- $$(Q)rm -f $$(S)src/libuv/libuv.a
- $$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
- CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
- AR="$$(AR_$(1))" \
+ $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
+ builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+ OS=mingw \
V=$$(VERBOSE)
- $$(Q)cp $$(S)src/libuv/libuv.a $$@
else ifeq ($(OSTYPE_$(1)), linux-androideabi)
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
- $$(Q)$$(MAKE) -C $$(@D) \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
+ $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
+ LINK="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
- host=android OS=linux \
- builddir="." \
+ PLATFORM=android \
BUILDTYPE=Release \
- NO_LOAD="$$(LIBUV_NO_LOAD)" \
+ builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
+ host=android OS=linux \
V=$$(VERBOSE)
else
-$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS) $$(LIBUV_MAKEFILE_$(1)_$(2))
- $$(Q)$$(MAKE) -C $$(@D) \
+$$(LIBUV_LIB_$(1)_$(2)): $$(LIBUV_DEPS)
+ $$(Q)$$(MAKE) -C $$(S)src/libuv/ \
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \
CC="$$(CC_$(1))" \
CXX="$$(CXX_$(1))" \
AR="$$(AR_$(1))" \
- builddir="." \
- BUILDTYPE=Release \
- NO_LOAD="$$(LIBUV_NO_LOAD)" \
+ builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/stage$(2)/libuv" \
V=$$(VERBOSE)
endif
$(foreach stage,$(STAGES), \
$(foreach target,$(CFG_TARGET_TRIPLES), \
$(eval $(call DEF_RUNTIME_TARGETS,$(target),$(stage)))))
-
-$(LIBUV_GYP):
- mkdir -p $(S)src/libuv/build
- git clone https://git.chromium.org/external/gyp.git $(S)src/libuv/build/gyp
$(eval $(foreach target,$(CFG_TARGET_TRIPLES), \
$(eval $(call DEF_CHECK_FAST_FOR_T_H,,$(target),$(host))))))
-check-fast: tidy check-fast-H-$(CFG_BUILD_TRIPLE)
+check-fast: tidy check-fast-H-$(CFG_BUILD_TRIPLE) check-stage2-std check-stage2-extra
+ $(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
define DEF_CHECK_FAST_FOR_H
// Run tests using the JIT
jit: bool,
- // Run tests using the new runtime
- newrt: bool,
-
// Target system to be tested
target: ~str,
optopt("", "ratchet-noise-percent",
"percent change in metrics to consider noise", "N"),
optflag("", "jit", "run tests under the JIT"),
- optflag("", "newrt", "run tests on the new runtime / scheduler"),
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "adb-path", "path to the android debugger", "PATH"),
optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
runtool: getopts::opt_maybe_str(matches, "runtool"),
rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
jit: getopts::opt_present(matches, "jit"),
- newrt: getopts::opt_present(matches, "newrt"),
target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
adb_test_dir:
logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
logv(c, fmt!("jit: %b", config.jit));
- logv(c, fmt!("newrt: %b", config.newrt));
logv(c, fmt!("target: %s", config.target));
logv(c, fmt!("adb_path: %s", config.adb_path));
logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
in_fd: None,
out_fd: None,
err_fd: None
- }).unwrap();
+ });
for input in input.iter() {
- proc.input().write(input.as_bytes());
+ proc.input().write_str(*input);
}
let output = proc.finish_with_output();
use util;
use util::logv;
+use std::cell::Cell;
use std::io;
use std::os;
use std::str;
+use std::task::{spawn_sched, SingleThreaded};
use std::vec;
+use std::unstable::running_on_valgrind;
use extra::test::MetricMap;
pub fn run(config: config, testfile: ~str) {
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
+ let config = Cell::new(config);
+ let testfile = Cell::new(testfile);
+ // FIXME #6436: Creating another thread to run the test because this
+ // is going to call waitpid. The new scheduler has some strange
+ // interaction between the blocking tasks and 'friend' schedulers
+ // that destroys parallelism if we let normal schedulers block.
+ // It should be possible to remove this spawn once std::run is
+ // rewritten to be non-blocking.
+ //
+ // We do _not_ create another thread if we're running on V because
+ // it serializes all threads anyways.
+ if running_on_valgrind() {
+ let config = config.take();
+ let testfile = testfile.take();
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
+ } else {
+ do spawn_sched(SingleThreaded) {
+ let config = config.take();
+ let testfile = testfile.take();
+ let mut _mm = MetricMap::new();
+ run_metrics(config, testfile, &mut _mm);
+ }
+ }
}
pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
fn exec_compiled_test(config: &config, props: &TestProps,
testfile: &Path) -> ProcRes {
- // If testing the new runtime then set the RUST_NEWRT env var
let env = props.exec_env.clone();
- let env = if config.newrt { env + &[(~"RUST_NEWRT", ~"1")] } else { env };
match config.target {
~"arm-linux-androideabi" => {
if (config.adb_device_status) {
- _arm_exec_compiled_test(config, props, testfile)
+ _arm_exec_compiled_test(config, props, testfile, env)
} else {
_dummy_exec_compiled_test(config, props, testfile)
}
}
fn _arm_exec_compiled_test(config: &config, props: &TestProps,
- testfile: &Path) -> ProcRes {
+ testfile: &Path, env: ~[(~str, ~str)]) -> ProcRes {
let args = make_run_args(config, props, testfile);
let cmdline = make_cmdline("", args.prog, args.args);
// run test via adb_run_wrapper
runargs.push(~"shell");
+ for (key, val) in env.move_iter() {
+ runargs.push(fmt!("%s=%s", key, val));
+ }
runargs.push(fmt!("%s/adb_run_wrapper.sh", config.adb_test_dir));
runargs.push(fmt!("%s", config.adb_test_dir));
runargs.push(fmt!("%s", prog_short));
;; Url: https://github.com/mozilla/rust
(eval-when-compile (require 'cl))
+(eval-when-compile (require 'misc))
;; Syntax definitions and helpers
(defvar rust-mode-syntax-table
table))
-(defcustom rust-indent-offset default-tab-width
- "*Indent Rust code by this number of spaces.
-
-The initializer is `DEFAULT-TAB-WIDTH'.")
+(defcustom rust-indent-offset 4
+ "*Indent Rust code by this number of spaces.")
(defun rust-paren-level () (nth 0 (syntax-ppss)))
(defun rust-in-str-or-cmnt () (nth 8 (syntax-ppss)))
;; A closing brace is 1 level unindended
((looking-at "}") (* rust-indent-offset (- level 1)))
+ ; Doc comments in /** style with leading * indent to line up the *s
+ ((and (nth 4 (syntax-ppss)) (looking-at "*"))
+ (+ 1 (* rust-indent-offset level)))
+
;; If we're in any other token-tree / sexp, then:
;; - [ or ( means line up with the opening token
- ;; - { means indent to either nesting-level * tab width,
+ ;; - { means indent to either nesting-level * rust-indent-offset,
;; or one further indent from that if either current line
;; begins with 'else', or previous line didn't end in
- ;; semi, comma or brace, and wasn't an attribute. PHEW.
+ ;; semi, comma or brace (other than whitespace and line
+ ;; comments) , and wasn't an attribute. But if we have
+ ;; something after the open brace and ending with a comma,
+ ;; treat it as fields and align them. PHEW.
((> level 0)
(let ((pt (point)))
(rust-rewind-irrelevant)
(backward-up-list)
- (if (looking-at "[[(]")
- (+ 1 (current-column))
+ (cond
+ ((and
+ (looking-at "[[(]")
+ ; We don't want to indent out to the open bracket if the
+ ; open bracket ends the line
+ (save-excursion
+ (forward-char)
+ (not (looking-at "[[:space:]]*\\(?://.*\\)?$"))))
+ (+ 1 (current-column)))
+ ;; Check for fields on the same line as the open curly brace:
+ ((looking-at "{[[:blank:]]*[^}\n]*,[[:space:]]*$")
(progn
+ (forward-char)
+ (forward-to-word 1)
+ (current-column)))
+ (t (progn
(goto-char pt)
(back-to-indentation)
(if (looking-at "\\<else\\>")
(beginning-of-line)
(rust-rewind-irrelevant)
(end-of-line)
- (if (looking-back "[{};,]")
+ (if (looking-back "[,;{}(][[:space:]]*\\(?://.*\\)?")
(* rust-indent-offset level)
(back-to-indentation)
(if (looking-at "#")
(* rust-indent-offset level)
- (* rust-indent-offset (+ 1 level))))))))))
+ (* rust-indent-offset (+ 1 level)))))))))))
;; Otherwise we're in a column-zero definition
(t 0))))))
}
fn ne(&self, other: &DList<A>) -> bool {
- self.len() != other.len() &&
+ self.len() != other.len() ||
iterator::order::ne(self.iter(), other.iter())
}
}
assert!(n != m);
m.push_back(1);
assert_eq!(&n, &m);
+
+ let n = list_from([2,3,4]);
+ let m = list_from([1,2,3]);
+ assert!(n != m);
}
#[test]
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
//
}
}
}
- fn le(&self, other: &Json) -> bool { !(*other).lt(&(*self)) }
- fn ge(&self, other: &Json) -> bool { !(*self).lt(other) }
- fn gt(&self, other: &Json) -> bool { (*other).lt(&(*self)) }
}
/// A trait for converting values to JSON
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
//
(&AlphaNumeric(_), _) => false
}
}
- #[inline]
- fn le(&self, other: &Identifier) -> bool {
- ! (other < self)
- }
- #[inline]
- fn gt(&self, other: &Identifier) -> bool {
- other < self
- }
- #[inline]
- fn ge(&self, other: &Identifier) -> bool {
- ! (self < other)
- }
}
impl ToStr for Identifier {
have a substring match, only those tests are run.
By default, all tests are run in parallel. This can be altered with the
-RUST_THREADS environment variable when running tests (set it to 1).
+RUST_TEST_TASKS environment variable when running tests (set it to 1).
Test Attributes:
fn get_concurrency() -> uint {
use std::rt;
- let threads = rt::util::default_sched_threads();
- if threads == 1 { 1 }
- else { threads * SCHED_OVERCOMMIT }
+ match os::getenv("RUST_TEST_TASKS") {
+ Some(s) => {
+ let opt_n: Option<uint> = FromStr::from_str(s);
+ match opt_n {
+ Some(n) if n > 0 => n,
+ _ => fail!("RUST_TEST_TASKS is `%s`, should be a positive integer.", s)
+ }
+ }
+ None => {
+ let threads = rt::util::default_sched_threads();
+ if threads == 1 { 1 }
+ else { threads * SCHED_OVERCOMMIT }
+ }
+ }
}
pub fn filter_tests(
use lib;
use std::c_str::ToCStr;
- use std::libc::c_uint;
+ use std::libc::{c_uint, c_int};
use std::path::Path;
use std::run;
use std::str;
}
}
- // Copy what clan does by turning on loop vectorization at O2 and
- // slp vectorization at O3
- let vectorize_loop = !sess.no_vectorize_loops() &&
- (sess.opts.optimize == session::Default ||
- sess.opts.optimize == session::Aggressive);
- let vectorize_slp = !sess.no_vectorize_slp() &&
- sess.opts.optimize == session::Aggressive;
- llvm::LLVMRustSetLLVMOptions(sess.print_llvm_passes(),
- vectorize_loop,
- vectorize_slp,
- sess.time_llvm_passes());
+ configure_llvm(sess);
let OptLevel = match sess.opts.optimize {
session::No => lib::llvm::CodeGenLevelNone,
// Create the two optimizing pass managers. These mirror what clang
// does, and are by populated by LLVM's default PassManagerBuilder.
// Each manager has a different set of passes, but they also share
- // some common passes. Each one is initialized with the analyis
- // passes the target requires, and then further passes are added.
+ // some common passes.
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
let mpm = llvm::LLVMCreatePassManager();
- llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
- llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
// If we're verifying or linting, add them to the function pass
// manager.
if !sess.no_verify() { assert!(addpass("verify")); }
if sess.lint_llvm() { assert!(addpass("lint")); }
- // Create the PassManagerBuilder for LLVM. We configure it with
- // reasonable defaults and prepare it to actually populate the pass
- // manager.
- let builder = llvm::LLVMPassManagerBuilderCreate();
- match sess.opts.optimize {
- session::No => {
- // Don't add lifetime intrinsics add O0
- llvm::LLVMRustAddAlwaysInlinePass(builder, false);
- }
- // numeric values copied from clang
- session::Less => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
- 225);
- }
- session::Default | session::Aggressive => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
- 275);
- }
+ if !sess.no_prepopulate_passes() {
+ llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+ llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+ populate_llvm_passess(fpm, mpm, llmod, OptLevel);
}
- llvm::LLVMPassManagerBuilderSetOptLevel(builder, OptLevel as c_uint);
- llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
-
- // Use the builder to populate the function/module pass managers.
- llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
- llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
- llvm::LLVMPassManagerBuilderDispose(builder);
for pass in sess.opts.custom_passes.iter() {
do pass.with_c_str |s| {
sess.abort_if_errors();
}
}
+
+ unsafe fn configure_llvm(sess: Session) {
+ // Copy what clan does by turning on loop vectorization at O2 and
+ // slp vectorization at O3
+ let vectorize_loop = !sess.no_vectorize_loops() &&
+ (sess.opts.optimize == session::Default ||
+ sess.opts.optimize == session::Aggressive);
+ let vectorize_slp = !sess.no_vectorize_slp() &&
+ sess.opts.optimize == session::Aggressive;
+
+ let mut llvm_c_strs = ~[];
+ let mut llvm_args = ~[];
+ let add = |arg: &str| {
+ let s = arg.to_c_str();
+ llvm_args.push(s.with_ref(|p| p));
+ llvm_c_strs.push(s);
+ };
+ add("rustc"); // fake program name
+ add("-arm-enable-ehabi");
+ add("-arm-enable-ehabi-descriptors");
+ if vectorize_loop { add("-vectorize-loops"); }
+ if vectorize_slp { add("-vectorize-slp"); }
+ if sess.time_llvm_passes() { add("-time-passes"); }
+ if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
+
+ for arg in sess.opts.llvm_args.iter() {
+ add(*arg);
+ }
+
+ do llvm_args.as_imm_buf |p, len| {
+ llvm::LLVMRustSetLLVMOptions(len as c_int, p);
+ }
+ }
+
+ unsafe fn populate_llvm_passess(fpm: lib::llvm::PassManagerRef,
+ mpm: lib::llvm::PassManagerRef,
+ llmod: ModuleRef,
+ opt: lib::llvm::CodeGenOptLevel) {
+ // Create the PassManagerBuilder for LLVM. We configure it with
+ // reasonable defaults and prepare it to actually populate the pass
+ // manager.
+ let builder = llvm::LLVMPassManagerBuilderCreate();
+ match opt {
+ lib::llvm::CodeGenLevelNone => {
+ // Don't add lifetime intrinsics add O0
+ llvm::LLVMRustAddAlwaysInlinePass(builder, false);
+ }
+ lib::llvm::CodeGenLevelLess => {
+ llvm::LLVMRustAddAlwaysInlinePass(builder, true);
+ }
+ // numeric values copied from clang
+ lib::llvm::CodeGenLevelDefault => {
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+ 225);
+ }
+ lib::llvm::CodeGenLevelAggressive => {
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
+ 275);
+ }
+ }
+ llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
+ llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
+
+ // Use the builder to populate the function/module pass managers.
+ llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
+ llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+ llvm::LLVMPassManagerBuilderDispose(builder);
+ }
}
}).collect()
}
};
+ let llvm_args = match getopts::opt_maybe_str(matches, "llvm-args") {
+ None => ~[],
+ Some(s) => {
+ s.split_iter(|c: char| c == ' ' || c == ',').map(|s| {
+ s.trim().to_owned()
+ }).collect()
+ }
+ };
let sopts = @session::options {
crate_type: crate_type,
gc: gc,
optimize: opt_level,
custom_passes: custom_passes,
+ llvm_args: llvm_args,
debuginfo: debuginfo,
extra_debuginfo: extra_debuginfo,
lint_opts: lint_opts,
Appends to the default list of passes to run for the \
specified current optimization level. A value of \
\"list\" will list all of the available passes", "NAMES"),
+ optopt("", "llvm-args", "A list of arguments to pass to llvm, comma \
+ separated", "ARGS"),
optopt( "", "out-dir",
"Write output to compiler-chosen filename
in <dir>", "DIR"),
pub static print_llvm_passes: uint = 1 << 27;
pub static no_vectorize_loops: uint = 1 << 28;
pub static no_vectorize_slp: uint = 1 << 29;
+pub static no_prepopulate_passes: uint = 1 << 30;
pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"verbose", ~"in general, enable more debug printouts", verbose),
(~"print-llvm-passes",
~"Prints the llvm optimization passes being run",
print_llvm_passes),
+ (~"no-prepopulate-passes",
+ ~"Don't pre-populate the pass managers with a list of passes, only use \
+ the passes from --passes",
+ no_prepopulate_passes),
(~"no-vectorize-loops",
~"Don't run the loop vectorization optimization passes",
no_vectorize_loops),
gc: bool,
optimize: OptLevel,
custom_passes: ~[~str],
+ llvm_args: ~[~str],
debuginfo: bool,
extra_debuginfo: bool,
lint_opts: ~[(lint::lint, lint::level)],
pub fn print_llvm_passes(@self) -> bool {
self.debugging_opt(print_llvm_passes)
}
+ pub fn no_prepopulate_passes(@self) -> bool {
+ self.debugging_opt(no_prepopulate_passes)
+ }
pub fn no_vectorize_loops(@self) -> bool {
self.debugging_opt(no_vectorize_loops)
}
gc: false,
optimize: No,
custom_passes: ~[],
+ llvm_args: ~[],
debuginfo: false,
extra_debuginfo: false,
lint_opts: ~[],
AD_Intel = 1
}
+#[deriving(Eq)]
pub enum CodeGenOptLevel {
CodeGenLevelNone = 0,
CodeGenLevelLess = 1,
pub fn LLVMRustPrintModule(PM: PassManagerRef,
M: ModuleRef,
Output: *c_char);
- pub fn LLVMRustSetLLVMOptions(PrintPasses: bool,
- VectorizeLoops: bool,
- VectorizeSLP: bool,
- TimePasses: bool);
+ pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: **c_char);
pub fn LLVMRustPrintPasses();
pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *c_char);
pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef,
// If this trait has builtin-kind supertraits, meet them.
let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
- error!("checking impl with self type %?", ty::get(self_ty).sty);
+ debug!("checking impl with self type %?", ty::get(self_ty).sty);
do check_builtin_bounds(cx, self_ty, trait_def.bounds) |missing| {
cx.tcx.sess.span_err(self_type.span,
fmt!("the type `%s', which does not fulfill `%s`, cannot implement this \
debug!("(resolving glob import) ... for value target");
dest_import_resolution.value_target =
Some(Target(containing_module, name_bindings));
+ dest_import_resolution.value_id = id;
}
if name_bindings.defined_in_public_namespace(TypeNS) {
debug!("(resolving glob import) ... for type target");
dest_import_resolution.type_target =
Some(Target(containing_module, name_bindings));
+ dest_import_resolution.type_id = id;
}
};
use syntax::print::pprust::stmt_to_str;
use syntax::{ast, ast_util, codemap, ast_map};
use syntax::abi::{X86, X86_64, Arm, Mips};
+use syntax::visit::Visitor;
pub use middle::trans::context::task_llcx;
}
}
+pub struct TransItemVisitor;
+
+impl Visitor<@mut CrateContext> for TransItemVisitor {
+ fn visit_item(&mut self, i: @ast::item, ccx: @mut CrateContext) {
+ trans_item(ccx, i);
+ }
+}
+
pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
let _icx = push_ctxt("trans_item");
let path = match ccx.tcx.items.get_copy(&item.id) {
item.id,
item.attrs);
} else {
- for stmt in body.stmts.iter() {
- match stmt.node {
- ast::stmt_decl(@codemap::spanned { node: ast::decl_item(i),
- _ }, _) => {
- trans_item(ccx, i);
- }
- _ => ()
- }
- }
+ // Be sure to travel more than just one layer deep to catch nested
+ // items in blocks and such.
+ let mut v = TransItemVisitor;
+ v.visit_block(body, ccx);
}
}
ast::item_impl(ref generics, _, _, ref ms) => {
use syntax::ast_map::{path, path_mod, path_name};
use syntax::ast_util;
use syntax::{ast, ast_map};
+use syntax::visit;
/**
The main "translation" pass for methods. Generates code
debug!("trans_impl(path=%s, name=%s, id=%?)",
path.repr(tcx), name.repr(tcx), id);
- if !generics.ty_params.is_empty() { return; }
+ // Both here and below with generic methods, be sure to recurse and look for
+ // items that we need to translate.
+ if !generics.ty_params.is_empty() {
+ let mut v = TransItemVisitor;
+ for method in methods.iter() {
+ visit::walk_method_helper(&mut v, *method, ccx);
+ }
+ return;
+ }
let sub_path = vec::append_one(path, path_name(name));
for method in methods.iter() {
if method.generics.ty_params.len() == 0u {
*method,
None,
llfn);
+ } else {
+ let mut v = TransItemVisitor;
+ visit::walk_method_helper(&mut v, *method, ccx);
}
}
}
trait_ref.def_id,
trait_ref.substs.clone(),
RegionTraitStore(region),
- ast::m_imm,
+ ast::m_mutbl,
EmptyBuiltinBounds())))
}
/*!
* Conversion from AST representation of types to the ty.rs
* representation. The main routine here is `ast_ty_to_ty()`: each use
- * is parameterized by an instance of `AstConv` and a `region_scope`.
+ * is parameterized by an instance of `AstConv` and a `RegionScope`.
*
* The parameterization of `ast_ty_to_ty()` is because it behaves
* somewhat differently during the collect and check phases,
* In the check phase, when the @FnCtxt is used as the `AstConv`,
* `get_item_ty()` just looks up the item type in `tcx.tcache`.
*
- * The `region_scope` trait controls how region references are
+ * The `RegionScope` trait controls how region references are
* handled. It has two methods which are used to resolve anonymous
* region references (e.g., `&T`) and named region references (e.g.,
* `&a.T`). There are numerous region scopes that can be used, but most
- * commonly you want either `empty_rscope`, which permits only the static
- * region, or `type_rscope`, which permits the self region if the type in
+ * commonly you want either `EmptyRscope`, which permits only the static
+ * region, or `TypeRscope`, which permits the self region if the type in
* question is parameterized by a region.
*
* Unlike the `AstConv` trait, the region scope can change as we descend
use middle::ty::{ty_param_substs_and_ty};
use middle::ty;
use middle::typeck::rscope::in_binding_rscope;
-use middle::typeck::rscope::{region_scope, RegionError};
+use middle::typeck::rscope::{RegionScope, RegionError};
use middle::typeck::rscope::RegionParamNames;
use middle::typeck::lookup_def_tcx;
}
}
-pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ast_region_to_region<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
default_span: span,
get_region_reporting_err(this.tcx(), span, opt_lifetime, res)
}
-fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
+fn ast_path_substs<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
def_id: ast::def_id,
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,
- RS:region_scope + Clone + 'static>(
+ RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
did: ast::def_id,
ty_param_substs_and_ty { substs: substs, ty: ty }
}
-pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ast_path_to_trait_ref<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
trait_def_id: ast::def_id,
return trait_ref;
}
-pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
did: ast::def_id,
// Parses the programmer's textual representation of a type into our
// internal notion of a type. `getter` is a function that returns the type
// corresponding to a definition ID:
-pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
+pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope + Clone + 'static>(
this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t {
- fn ast_mt_to_mt<AC:AstConv, RS:region_scope + Clone + 'static>(
+ fn ast_mt_to_mt<AC:AstConv, RS:RegionScope + Clone + 'static>(
this: &AC, rscope: &RS, mt: &ast::mt) -> ty::mt {
ty::mt {ty: ast_ty_to_ty(this, rscope, mt.ty), mutbl: mt.mutbl}
// Handle @, ~, and & being able to mean estrs and evecs.
// If a_seq_ty is a str or a vec, make it an estr/evec.
// Also handle first-class trait types.
- fn mk_pointer<AC:AstConv,RS:region_scope + Clone + 'static>(
+ fn mk_pointer<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
a_seq_ty: &ast::mt,
}
pub fn ty_of_arg<AC:AstConv,
- RS:region_scope + Clone + 'static>(
+ RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
a: &ast::arg,
explicit_self: ast::explicit_self
}
-pub fn ty_of_method<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ty_of_method<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
purity: ast::purity,
(a.unwrap(), b)
}
-pub fn ty_of_bare_fn<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ty_of_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
purity: ast::purity,
b
}
-fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Clone + 'static>(
+fn ty_of_method_or_bare_fn<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
purity: ast::purity,
output: output_ty}
});
- fn transform_self_ty<AC:AstConv,RS:region_scope + Clone + 'static>(
+ fn transform_self_ty<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
self_info: &SelfInfo) -> Option<ty::t>
}
}
-pub fn ty_of_closure<AC:AstConv,RS:region_scope + Clone + 'static>(
+pub fn ty_of_closure<AC:AstConv,RS:RegionScope + Clone + 'static>(
this: &AC,
rscope: &RS,
sigil: ast::Sigil,
use middle::typeck::infer;
use middle::typeck::rscope::bound_self_region;
use middle::typeck::rscope::{RegionError};
-use middle::typeck::rscope::region_scope;
+use middle::typeck::rscope::RegionScope;
use middle::typeck::{isr_alist, lookup_def_ccx};
use middle::typeck::no_params;
use middle::typeck::{require_same_types, method_map, vtable_map};
}
}
-impl region_scope for FnCtxt {
+impl RegionScope for FnCtxt {
fn anon_region(&self, span: span) -> Result<ty::Region, RegionError> {
result::Ok(self.infcx().next_region_var(infer::MiscVariable(span)))
}
}
pub trait ToTy {
- fn to_ty<RS:region_scope + Clone + 'static>(
+ fn to_ty<RS:RegionScope + Clone + 'static>(
&self,
rs: &RS,
ast_ty: &ast::Ty)
}
impl ToTy for CrateCtxt {
- fn to_ty<RS:region_scope + Clone + 'static>(
+ fn to_ty<RS:RegionScope + Clone + 'static>(
&self,
rs: &RS,
ast_ty: &ast::Ty)
let result_ty;
match variant.node.kind {
ast::tuple_variant_kind(ref args) if args.len() > 0 => {
- let rs = type_rscope(region_parameterization);
+ let rs = TypeRscope(region_parameterization);
let input_tys = args.map(|va| ccx.to_ty(&rs, &va.ty));
result_ty = Some(ty::mk_ctor_fn(tcx, input_tys, enum_ty));
}
generics: &ast::Generics) {
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
- let tt = ccx.to_ty(&type_rscope(region_parameterization), &v.node.ty);
+ let tt = ccx.to_ty(&TypeRscope(region_parameterization), &v.node.ty);
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */
ccx.tcx.tcache.insert(local_def(v.node.id),
let i_ty_generics = ty_generics(ccx, rp, generics, 0);
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
- let selfty = ccx.to_ty(&type_rscope(region_parameterization), selfty);
+ let selfty = ccx.to_ty(&TypeRscope(region_parameterization), selfty);
write_ty_to_tcx(tcx, it.id, selfty);
tcx.tcache.insert(local_def(it.id),
ty_param_bounds_and_ty {
let rp = RegionParameterization::from_variance_and_generics(rp, generics);
- let rscope = type_rscope(rp);
+ let rscope = TypeRscope(rp);
match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) {
ast::def_trait(trait_did) => {
let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
match it.node {
ast::item_static(ref t, _, _) => {
- let typ = ccx.to_ty(&empty_rscope, t);
+ let typ = ccx.to_ty(&EmptyRscope, t);
let tpt = no_params(typ);
tcx.tcache.insert(local_def(it.id), tpt);
return tpt;
assert!(rp.is_none());
let ty_generics = ty_generics(ccx, None, generics, 0);
let tofd = astconv::ty_of_bare_fn(ccx,
- &empty_rscope,
+ &EmptyRscope,
purity,
abi,
&generics.lifetimes,
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
let tpt = {
- let ty = ccx.to_ty(&type_rscope(region_parameterization), t);
+ let ty = ccx.to_ty(&TypeRscope(region_parameterization), t);
ty_param_bounds_and_ty {
generics: ty_generics(ccx, rp, generics, 0),
ty: ty
type_param_defs: @~[],
region_param: None,
},
- ty: ast_ty_to_ty(ccx, &empty_rscope, t)
+ ty: ast_ty_to_ty(ccx, &EmptyRscope, t)
}
}
}
-> ty::ty_param_bounds_and_ty {
let ty_generics = ty_generics(ccx, None, ast_generics, 0);
let region_param_names = RegionParamNames::from_generics(ast_generics);
- let rb = in_binding_rscope(&empty_rscope, region_param_names);
+ let rb = in_binding_rscope(&EmptyRscope, region_param_names);
let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, a, None) );
let output_ty = ast_ty_to_ty(ccx, &rb, &decl.output);
replacement: ty::Region
}
-pub trait region_scope {
+pub trait RegionScope {
fn anon_region(&self, span: span) -> Result<ty::Region, RegionError>;
fn self_region(&self, span: span) -> Result<ty::Region, RegionError>;
fn named_region(&self, span: span, id: ast::ident)
}
#[deriving(Clone)]
-pub enum empty_rscope { empty_rscope }
-impl region_scope for empty_rscope {
+pub struct EmptyRscope;
+impl RegionScope for EmptyRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"only 'static is allowed here",
}
}
-impl region_scope for MethodRscope {
+impl RegionScope for MethodRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
if !self.region_param_names.has_ident(id) {
return RegionParamNames::undeclared_name(None);
}
- do empty_rscope.named_region(span, id).chain_err |_e| {
+ do EmptyRscope.named_region(span, id).chain_err |_e| {
result::Err(RegionError {
msg: ~"lifetime is not in scope",
replacement: ty::re_bound(ty::br_self)
}
#[deriving(Clone)]
-pub struct type_rscope(Option<RegionParameterization>);
+pub struct TypeRscope(Option<RegionParameterization>);
-impl type_rscope {
+impl TypeRscope {
fn replacement(&self) -> ty::Region {
if self.is_some() {
ty::re_bound(ty::br_self)
}
}
}
-impl region_scope for type_rscope {
+impl RegionScope for TypeRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
result::Err(RegionError {
msg: ~"anonymous lifetimes are not permitted here",
}
fn named_region(&self, span: span, id: ast::ident)
-> Result<ty::Region, RegionError> {
- do empty_rscope.named_region(span, id).chain_err |_e| {
+ do EmptyRscope.named_region(span, id).chain_err |_e| {
result::Err(RegionError {
msg: ~"only 'self is allowed as part of a type declaration",
replacement: self.replacement()
}
}
-pub struct binding_rscope {
- base: @region_scope,
+pub struct BindingRscope {
+ base: @RegionScope,
anon_bindings: @mut uint,
region_param_names: RegionParamNames,
}
-impl Clone for binding_rscope {
- fn clone(&self) -> binding_rscope {
- binding_rscope {
+impl Clone for BindingRscope {
+ fn clone(&self) -> BindingRscope {
+ BindingRscope {
base: self.base,
anon_bindings: self.anon_bindings,
region_param_names: self.region_param_names.clone(),
}
}
-pub fn in_binding_rscope<RS:region_scope + Clone + 'static>(
+pub fn in_binding_rscope<RS:RegionScope + Clone + 'static>(
this: &RS,
region_param_names: RegionParamNames)
- -> binding_rscope {
+ -> BindingRscope {
let base = @(*this).clone();
- let base = base as @region_scope;
- binding_rscope {
+ let base = base as @RegionScope;
+ BindingRscope {
base: base,
anon_bindings: @mut 0,
region_param_names: region_param_names,
}
}
-impl region_scope for binding_rscope {
+impl RegionScope for BindingRscope {
fn anon_region(&self, _span: span) -> Result<ty::Region, RegionError> {
let idx = *self.anon_bindings;
*self.anon_bindings += 1;
];
do generic_writer |markdown| {
+ use std::io::WriterUtil;
+
debug!("pandoc cmd: %s", pandoc_cmd);
debug!("pandoc args: %s", pandoc_args.connect(" "));
- let proc = run::Process::new(pandoc_cmd, pandoc_args,
- run::ProcessOptions::new());
- let mut proc = proc.unwrap();
+ let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
- proc.input().write(markdown.as_bytes());
+ proc.input().write_str(markdown);
let output = proc.finish_with_output();
debug!("pandoc result: %i", output.status);
/// Convenience functions intended for calling from pkg.rs
fn default_ctxt(p: @Path) -> Ctx {
- Ctx { sysroot_opt: Some(p), json: false, dep_cache: @mut HashMap::new() }
+ Ctx {
+ use_rust_path_hack: false,
+ sysroot_opt: Some(p),
+ json: false,
+ dep_cache: @mut HashMap::new()
+ }
}
pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version,
condition! {
no_rust_path: (~str) -> super::Path;
}
+
+condition! {
+ not_a_workspace: (~str) -> super::Path;
+}
+
+condition! {
+ failed_to_create_temp_dir: (~str) -> super::Path;
+}
use std::os;
pub struct Ctx {
+ // If use_rust_path_hack is true, rustpkg searches for sources
+ // in *package* directories that are in the RUST_PATH (for example,
+ // FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
+ // rustpkg stores build artifacts.
+ use_rust_path_hack: bool,
// Sysroot -- if this is None, uses rustc filesearch's
// idea of the default
sysroot_opt: Option<@Path>,
}
impl Eq for PkgId {
- fn eq(&self, p: &PkgId) -> bool {
- p.path == self.path && p.version == self.version
- }
- fn ne(&self, p: &PkgId) -> bool {
- !(self.eq(p))
+ fn eq(&self, other: &PkgId) -> bool {
+ self.path == other.path && self.version == other.version
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+extern mod extra;
+
use target::*;
use package_id::PkgId;
use std::path::Path;
use crate::Crate;
use messages::*;
use source_control::{git_clone, git_clone_general};
-use path_util::pkgid_src_in_workspace;
+use path_util::{pkgid_src_in_workspace, find_dir_using_rust_path_hack, default_workspace};
use util::compile_crate;
+use workspace::is_workspace;
// An enumeration of the unpacked source of a package workspace.
// This contains a list of files found in the source workspace.
}
- fn check_dir(&self) -> Path {
+ fn check_dir(&self, cx: &Ctx) -> Path {
use conditions::nonexistent_package::cond;
debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str());
let dir = match path {
Some(d) => (*d).clone(),
- None => match self.fetch_git() {
- Some(d) => d,
- None => cond.raise((self.id.clone(), ~"supplied path for package dir does not \
- exist, and couldn't interpret it as a URL fragment"))
+ None => {
+ match self.fetch_git() {
+ Some(d) => d,
+ None => {
+ match find_dir_using_rust_path_hack(cx, &self.id) {
+ Some(d) => d,
+ None => cond.raise((self.id.clone(),
+ ~"supplied path for package dir does not \
+ exist, and couldn't interpret it as a URL fragment"))
+ }
+ }
+ }
}
};
+ debug!("For package id %s, returning %s", self.id.to_str(), dir.to_str());
if !os::path_is_dir(&dir) {
cond.raise((self.id.clone(), ~"supplied path for package dir is a \
non-directory"));
/// refers to a git repo on the local version, also check it out.
/// (right now we only support git)
pub fn fetch_git(&self) -> Option<Path> {
+ use conditions::failed_to_create_temp_dir::cond;
+
+ // We use a temporary directory because if the git clone fails,
+ // it creates the target directory anyway and doesn't delete it
+
+ let scratch_dir = extra::tempfile::mkdtemp(&os::tmpdir(), "rustpkg");
+ let clone_target = match scratch_dir {
+ Some(d) => d.push("rustpkg_temp"),
+ None => cond.raise(~"Failed to create temporary directory for fetching git sources")
+ };
let mut local = self.root.push("src");
local = local.push(self.id.to_str());
- // Git can't clone into a non-empty directory
- os::remove_dir_recursive(&local);
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
self.id.path.to_str(),
if os::path_exists(&self.id.path) {
debug!("%s exists locally! Cloning it into %s",
self.id.path.to_str(), local.to_str());
+ // Ok to use local here; we know it will succeed
git_clone(&self.id.path, &local, &self.id.version);
return Some(local);
}
+ if (self.id.path.clone()).components().len() < 2 {
+ // If a non-URL, don't bother trying to fetch
+ return None;
+ }
+
let url = fmt!("https://%s", self.id.path.to_str());
note(fmt!("Fetching package: git clone %s %s [version=%s]",
- url, local.to_str(), self.id.version.to_str()));
- if git_clone_general(url, &local, &self.id.version) {
- Some(local)
+ url, clone_target.to_str(), self.id.version.to_str()));
+
+ if git_clone_general(url, &clone_target, &self.id.version) {
+ // since the operation succeeded, move clone_target to local
+ if !os::rename_file(&clone_target, &local) {
+ None
+ }
+ else {
+ Some(local)
+ }
}
else {
None
/// Infers crates to build. Called only in the case where there
/// is no custom build logic
- pub fn find_crates(&mut self) {
+ pub fn find_crates(&mut self, cx: &Ctx) {
use conditions::missing_pkg_files::cond;
- let dir = self.check_dir();
+ let dir = self.check_dir(cx);
debug!("Called check_dir, I'm in %s", dir.to_str());
let prefix = dir.components.len();
debug!("Matching against %?", self.id.short_name);
fn build_crates(&self,
ctx: &Ctx,
src_dir: &Path,
+ destination_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
what: OutputType) {
let result = compile_crate(ctx,
&self.id,
path,
- // compile_crate wants the workspace
- &self.root,
+ // compile_crate wants the destination workspace
+ destination_dir,
crate.flags,
crate.cfgs + cfgs,
false,
}
}
- pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) {
- let dir = self.check_dir();
- debug!("Building libs in %s", dir.to_str());
- self.build_crates(ctx, &dir, self.libs, cfgs, Lib);
+ pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) -> Path {
+ use conditions::not_a_workspace::cond;
+
+ // Determine the destination workspace (which depends on whether
+ // we're using the rust_path_hack)
+ let destination_workspace = if is_workspace(&self.root) {
+ debug!("%s is indeed a workspace", self.root.to_str());
+ self.root.clone()
+ }
+ else {
+ // It would be nice to have only one place in the code that checks
+ // for the use_rust_path_hack flag...
+ if ctx.use_rust_path_hack {
+ let rs = default_workspace();
+ debug!("Using hack: %s", rs.to_str());
+ rs
+ }
+ else {
+ cond.raise(fmt!("Package root %s is not a workspace; pass in --rust_path_hack \
+ if you want to treat it as a package source", self.root.to_str()))
+ }
+ };
+
+ let dir = self.check_dir(ctx);
+ debug!("Building libs in %s, destination = %s", dir.to_str(),
+ destination_workspace.to_str());
+ self.build_crates(ctx, &dir, &destination_workspace, self.libs, cfgs, Lib);
debug!("Building mains");
- self.build_crates(ctx, &dir, self.mains, cfgs, Main);
+ self.build_crates(ctx, &dir, &destination_workspace, self.mains, cfgs, Main);
debug!("Building tests");
- self.build_crates(ctx, &dir, self.tests, cfgs, Test);
+ self.build_crates(ctx, &dir, &destination_workspace, self.tests, cfgs, Test);
debug!("Building benches");
- self.build_crates(ctx, &dir, self.benchs, cfgs, Bench);
+ self.build_crates(ctx, &dir, &destination_workspace, self.benchs, cfgs, Bench);
+ destination_workspace
}
}
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
pub use rustc::metadata::filesearch::rust_path;
+use context::Ctx;
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os::mkdir_recursive;
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
debug!("Checking in src dir of %s for %s",
workspace.to_str(), pkgid.to_str());
+ workspace_contains_package_id_(pkgid, workspace, |p| { p.push("src") }).is_some()
+}
- let src_dir = workspace.push("src");
+pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
+// Returns the directory it was actually found in
+ workspace_to_src_dir: &fn(&Path) -> Path) -> Option<Path> {
+ let src_dir = workspace_to_src_dir(workspace);
- let mut found = false;
+ let mut found = None;
do os::walk_dir(&src_dir) |p| {
debug!("=> p = %s", p.to_str());
- let was_found = os::path_is_dir(p) && {
+ if os::path_is_dir(p) {
debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(),
src_dir.push_rel(&pkgid.path).to_str());
- *p == src_dir.push_rel(&pkgid.path) || {
+ if *p == src_dir.push_rel(&pkgid.path) || {
let pf = p.filename();
do pf.iter().any |pf| {
let g = pf.to_str();
}
}
}
+ } {
+ found = Some(p.clone());
}
- };
- if was_found {
- found = true
- }
+ };
true
};
- debug!(if found { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
+ debug!(if found.is_some() { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
found
}
Some(result)
}
else {
- // This is not an error, but it's worth logging it
- error!(fmt!("built_executable_in_workspace: %s does not exist", result.to_str()));
+ debug!("built_executable_in_workspace: %s does not exist", result.to_str());
None
}
}
/// Does the actual searching stuff
pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
- // NOTE: this could break once we're handling multiple versions better... want a test for it
+ // This could break once we're handling multiple versions better -- I should add a test for it
library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
}
} // for
if result_filename.is_none() {
- warn(fmt!("library_in_workspace didn't find a library in %s for %s",
- dir_to_search.to_str(), short_name));
+ debug!("warning: library_in_workspace didn't find a library in %s for %s",
+ dir_to_search.to_str(), short_name);
}
// Return the filename that matches, which we now know exists
}
}
+
+fn dir_has_file(dir: &Path, file: &str) -> bool {
+ assert!(dir.is_absolute());
+ os::path_exists(&dir.push(file))
+}
+
+pub fn find_dir_using_rust_path_hack(cx: &Ctx, p: &PkgId) -> Option<Path> {
+ if !cx.use_rust_path_hack {
+ return None;
+ }
+ let rp = rust_path();
+ for dir in rp.iter() {
+ debug!("In find_dir_using_rust_path_hack: checking dir %s", dir.to_str());
+ if dir_has_file(dir, "lib.rs") || dir_has_file(dir, "main.rs")
+ || dir_has_file(dir, "test.rs") || dir_has_file(dir, "bench.rs") {
+ debug!("Did find id %s in dir %s", p.to_str(), dir.to_str());
+ return Some(dir.clone());
+ }
+ debug!("Didn't find id %s in dir %s", p.to_str(), dir.to_str())
+ }
+ None
+}
extern mod rustc;
extern mod syntax;
-use std::result;
-use std::io;
-use std::os;
-use std::run;
-use std::str;
-
+use std::{io, os, result, run, str};
pub use std::path::Path;
use std::hashmap::HashMap;
pub trait CtxMethods {
fn run(&self, cmd: &str, args: ~[~str]);
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
- fn build(&self, workspace: &Path, pkgid: &PkgId);
+ /// Returns the destination workspace
+ fn build(&self, workspace: &Path, pkgid: &PkgId) -> Path;
fn clean(&self, workspace: &Path, id: &PkgId);
fn info(&self);
fn install(&self, workspace: &Path, id: &PkgId);
"build" => {
if args.len() < 1 {
match cwd_to_workspace() {
- None => { usage::build(); return }
- Some((ws, pkgid)) => self.build(&ws, &pkgid)
+ None if self.use_rust_path_hack => {
+ let cwd = os::getcwd();
+ self.build(&cwd, &PkgId::new(cwd.components[cwd.components.len() - 1]));
+ }
+ None => { usage::build(); return; }
+ Some((ws, pkgid)) => { self.build(&ws, &pkgid); }
}
}
else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0].clone());
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
debug!("found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());
self.build(workspace, &pkgid);
"install" => {
if args.len() < 1 {
match cwd_to_workspace() {
- None => { usage::install(); return }
- Some((ws, pkgid)) => self.install(&ws, &pkgid)
- }
+ None if self.use_rust_path_hack => {
+ let cwd = os::getcwd();
+ self.install(&cwd,
+ &PkgId::new(cwd.components[cwd.components.len() - 1]));
+ }
+ None => { usage::install(); return; }
+ Some((ws, pkgid)) => self.install(&ws, &pkgid),
+ }
}
else {
// The package id is presumed to be the first command-line
// argument
let pkgid = PkgId::new(args[0]);
- let workspaces = pkg_parent_workspaces(&pkgid);
+ let workspaces = pkg_parent_workspaces(self, &pkgid);
debug!("package ID = %s, found it in %? workspaces",
pkgid.to_str(), workspaces.len());
if workspaces.is_empty() {
self.install(&rp[0], &pkgid);
}
else {
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
self.install(workspace, &pkgid);
true
};
else {
let rp = rust_path();
assert!(!rp.is_empty());
- do each_pkg_parent_workspace(&pkgid) |workspace| {
+ do each_pkg_parent_workspace(self, &pkgid) |workspace| {
path_util::uninstall_package_from(workspace, &pkgid);
note(fmt!("Uninstalled package %s (was installed in %s)",
pkgid.to_str(), workspace.to_str()));
fail!("`do` not yet implemented");
}
- fn build(&self, workspace: &Path, pkgid: &PkgId) {
+ /// 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, workspace: &Path, pkgid: &PkgId) -> Path {
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
pkgid = %s", workspace.to_str(),
in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)),
// the build already. Otherwise...
if !custom {
// Find crates inside the workspace
- src.find_crates();
+ src.find_crates(self);
// Build it!
- src.build(self, cfgs);
+ src.build(self, cfgs)
+ }
+ else {
+ // Just return the source workspace
+ workspace.clone()
}
}
}
fn install(&self, workspace: &Path, id: &PkgId) {
- // FIXME #7402: Use RUST_PATH to determine target dir
// Also should use workcache to not build if not necessary.
- self.build(workspace, id);
- debug!("install: workspace = %s, id = %s", workspace.to_str(),
- id.to_str());
- self.install_no_build(workspace, id);
+ let destination_workspace = self.build(workspace, id);
+ // 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.
+ debug!("install: destination workspace = %s, id = %s",
+ destination_workspace.to_str(), id.to_str());
+ self.install_no_build(&destination_workspace, id);
}
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
getopts::optflag("j"), getopts::optflag("json"),
getopts::optmulti("c"), getopts::optmulti("cfg"),
- getopts::optflag("v"), getopts::optflag("version")];
+ getopts::optflag("v"), getopts::optflag("version"),
+ getopts::optflag("r"), getopts::optflag("rust-path-hack")];
let matches = &match getopts::getopts(args, opts) {
result::Ok(m) => m,
result::Err(f) => {
return;
}
+ let use_rust_path_hack = getopts::opt_present(matches, "r") ||
+ getopts::opt_present(matches, "rust-path-hack");
+
let mut args = matches.free.clone();
args.shift();
return usage::general();
}
- let cmd = args.shift();
-
- if !util::is_cmd(cmd) {
- return usage::general();
- } else if help {
- return match cmd {
- ~"build" => usage::build(),
- ~"clean" => usage::clean(),
- ~"do" => usage::do_cmd(),
- ~"info" => usage::info(),
- ~"install" => usage::install(),
- ~"list" => usage::list(),
- ~"prefer" => usage::prefer(),
- ~"test" => usage::test(),
- ~"uninstall" => usage::uninstall(),
- ~"unprefer" => usage::unprefer(),
- _ => usage::general()
- };
+ let mut cmd_opt = None;
+ for a in args.iter() {
+ if util::is_cmd(*a) {
+ cmd_opt = Some(a);
+ break;
+ }
}
+ let cmd = match cmd_opt {
+ None => return usage::general(),
+ Some(cmd) => if help {
+ return match *cmd {
+ ~"build" => usage::build(),
+ ~"clean" => usage::clean(),
+ ~"do" => usage::do_cmd(),
+ ~"info" => usage::info(),
+ ~"install" => usage::install(),
+ ~"list" => usage::list(),
+ ~"prefer" => usage::prefer(),
+ ~"test" => usage::test(),
+ ~"uninstall" => usage::uninstall(),
+ ~"unprefer" => usage::unprefer(),
+ _ => usage::general()
+ };
+ }
+ else {
+ cmd
+ }
+ };
+ // Pop off all flags, plus the command
+ let remaining_args = args.iter().skip_while(|s| !util::is_cmd(**s));
+ // I had to add this type annotation to get the code to typecheck
+ let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
+ remaining_args.shift();
let sroot = Some(@filesearch::get_or_default_sysroot());
debug!("Using sysroot: %?", sroot);
Ctx {
+ use_rust_path_hack: use_rust_path_hack,
sysroot_opt: sroot, // Currently, only tests override this
json: json,
dep_cache: @mut HashMap::new()
- }.run(cmd, args);
+ }.run(*cmd, remaining_args)
}
/**
fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> ProcessOutput {
let mut prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
- ,..ProcessOptions::new()}).unwrap();
+ ,..ProcessOptions::new()});
prog.finish_with_output()
}
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
Ctx {
+ use_rust_path_hack: false,
sysroot_opt: sysroot_opt,
json: false,
dep_cache: @mut HashMap::new()
out.write_line(contents);
}
-fn mk_empty_workspace(short_name: &Path, version: &Version) -> Path {
- let workspace_dir = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
+fn mk_empty_workspace(short_name: &Path, version: &Version, tag: &str) -> Path {
+ let workspace_dir = mkdtemp(&os::tmpdir(), tag).expect("couldn't create temp dir");
mk_workspace(&workspace_dir, short_name, version);
workspace_dir
}
fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
let package_dir = mk_empty_workspace(short_name,
- version).push("src").push(fmt!("%s-%s",
+ version, "temp_workspace").push("src").push(fmt!("%s-%s",
short_name.to_str(),
version.to_str()));
fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &str) {
let cwd = (*cwd).clone();
- let prog = run::Process::new("git", args, run::ProcessOptions {
+ let mut prog = run::Process::new("git", args, run::ProcessOptions {
env: env,
dir: Some(&cwd),
in_fd: None,
out_fd: None,
err_fd: None
});
- let mut prog = prog.unwrap();
let rslt = prog.finish_with_output();
if rslt.status != 0 {
fail!("%s [git returned %?, output = %s, error = %s]", err_msg,
in_fd: None,
out_fd: None,
err_fd: None
- }).unwrap();
+ });
let output = prog.finish_with_output();
debug!("Output from command %s with args %? was %s {%s}[%?]",
cmd, args, str::from_bytes(output.output),
}
-fn assert_lib_exists(repo: &Path, short_name: &str, _v: Version) { // ??? version?
+fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) {
+ assert!(lib_exists(repo, short_name, v));
+}
+
+fn lib_exists(repo: &Path, short_name: &str, _v: Version) -> bool { // ??? version?
debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
let lib = installed_library_in_workspace(short_name, repo);
debug!("assert_lib_exists: checking whether %? exists", lib);
- assert!(lib.is_some());
- let libname = lib.get_ref();
- assert!(os::path_exists(libname));
- assert!(is_rwx(libname));
+ lib.is_some() && {
+ let libname = lib.get_ref();
+ os::path_exists(libname) && is_rwx(libname)
+ }
}
fn assert_executable_exists(repo: &Path, short_name: &str) {
+ assert!(executable_exists(repo, short_name));
+}
+
+fn executable_exists(repo: &Path, short_name: &str) -> bool {
debug!("assert_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
let exec = target_executable_in_workspace(&PkgId::new(short_name), repo);
- assert!(os::path_exists(&exec));
- assert!(is_rwx(&exec));
+ os::path_exists(&exec) && is_rwx(&exec)
}
fn assert_built_executable_exists(repo: &Path, short_name: &str) {
+ assert!(built_executable_exists(repo, short_name));
+}
+
+fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
debug!("assert_built_executable_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
- let exec = built_executable_in_workspace(&PkgId::new(short_name),
- repo).expect("assert_built_executable_exists failed");
- assert!(os::path_exists(&exec));
- assert!(is_rwx(&exec));
+ let exec = built_executable_in_workspace(&PkgId::new(short_name), repo);
+ exec.is_some() && {
+ let execname = exec.get_ref();
+ os::path_exists(execname) && is_rwx(execname)
+ }
+}
+
+fn assert_built_library_exists(repo: &Path, short_name: &str) {
+ assert!(built_library_exists(repo, short_name));
+}
+
+fn built_library_exists(repo: &Path, short_name: &str) -> bool {
+ debug!("assert_built_library_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
+ let lib = built_library_in_workspace(&PkgId::new(short_name), repo);
+ lib.is_some() && {
+ let libname = lib.get_ref();
+ os::path_exists(libname) && is_rwx(libname)
+ }
}
fn command_line_test_output(args: &[~str]) -> ~[~str] {
fn test_install_invalid() {
use conditions::nonexistent_package::cond;
use cond1 = conditions::missing_pkg_files::cond;
+ use cond2 = conditions::not_a_workspace::cond;
let ctxt = fake_ctxt(None);
let pkgid = fake_pkg();
let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
let mut error_occurred = false;
let mut error1_occurred = false;
+ let mut error2_occurred = false;
do cond1.trap(|_| {
error1_occurred = true;
}).inside {
error_occurred = true;
temp_workspace.clone()
}).inside {
- ctxt.install(&temp_workspace, &pkgid);
+ do cond2.trap(|_| {
+ error2_occurred = true;
+ temp_workspace.clone()
+ }).inside {
+ ctxt.install(&temp_workspace, &pkgid);
+ }
}
}
- assert!(error_occurred && error1_occurred);
+ assert!(error_occurred && error1_occurred && error2_occurred);
}
// Tests above should (maybe) be converted to shell out to rustpkg, too
test_sysroot().to_str(),
exec_file.to_str());
- let prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
- ~"--sysroot", test_sysroot().to_str(),
- ~"-o", exec_file.to_str()],
- run::ProcessOptions {
+ let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+ ~"--sysroot", test_sysroot().to_str(),
+ ~"-o", exec_file.to_str()],
+ run::ProcessOptions {
env: env,
dir: Some(&dir),
in_fd: None,
out_fd: None,
err_fd: None
});
- let mut prog = prog.unwrap();
let outp = prog.finish_with_output();
if outp.status != 0 {
fail!("output was %s, error was %s",
command_line_test_with_env([~"install", ~"bar"], &c_loc, env);
}
+fn rust_path_hack_test(hack_flag: bool) {
+/*
+ Make a workspace containing a pkg foo [A]
+ Make a second, empty workspace [B]
+ Set RUST_PATH to B:A
+ rustpkg install foo
+ make sure built files for foo are in B
+ make sure nothing gets built into A or A/../build[lib,bin]
+*/
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH",
+ fmt!("%s:%s", dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str()))]);
+ debug!("declare -x RUST_PATH=%s:%s",
+ dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str());
+ command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
+ ~[~"foo"], &dest_workspace, rust_path);
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_executable_exists(&dest_workspace, "foo");
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert_built_executable_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&workspace, "foo", NoVersion));
+ assert!(!executable_exists(&workspace, "foo"));
+ assert!(!built_library_exists(&workspace, "foo"));
+ assert!(!built_executable_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_rust_path_can_contain_package_dirs_with_flag() {
+/*
+ Test that the temporary hack added for bootstrapping Servo builds
+ works. That is: if you add $FOO/src/some_pkg to the RUST_PATH,
+ it will find the sources in some_pkg, build them, and install them
+ into the first entry in the RUST_PATH.
+
+ When the hack is removed, we should change this to a should_fail test.
+*/
+ rust_path_hack_test(true);
+}
+
+#[test]
+#[should_fail]
+fn test_rust_path_can_contain_package_dirs_without_flag() {
+ rust_path_hack_test(false);
+}
+
+#[test]
+fn rust_path_hack_cwd() {
+ // Same as rust_path_hack_test, but the CWD is the dir to build out of
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_cwd");
+ writeFile(&cwd.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&cwd, "foo", NoVersion));
+ assert!(!built_library_exists(&cwd, "foo"));
+}
+
+#[test]
+fn rust_path_hack_multi_path() {
+ // Same as rust_path_hack_test, but with a more complex package ID
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_cwd");
+ let subdir = cwd.push_many([~"foo", ~"bar", ~"quux"]);
+ assert!(os::mkdir_recursive(&subdir, U_RWX));
+ writeFile(&subdir.push("lib.rs"), "pub fn f() { }");
+ let name = ~"foo/bar/quux";
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
+ debug!("Checking that %s exists in %s", name, dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "quux", NoVersion);
+ assert_built_library_exists(&dest_workspace, name);
+ assert!(!lib_exists(&subdir, "quux", NoVersion));
+ assert!(!built_library_exists(&subdir, name));
+}
+
+#[test]
+fn rust_path_hack_install_no_arg() {
+ // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_install_no_arg");
+ let source_dir = cwd.push("foo");
+ assert!(make_dir_rwx(&source_dir));
+ writeFile(&source_dir.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!lib_exists(&source_dir, "foo", NoVersion));
+ assert!(!built_library_exists(&cwd, "foo"));
+}
+
+#[test]
+fn rust_path_hack_build_no_arg() {
+ // Same as rust_path_hack_install_no_arg, but building instead of installing
+ let cwd = mkdtemp(&os::tmpdir(), "pkg_files").expect("rust_path_hack_build_no_arg");
+ let source_dir = cwd.push("foo");
+ assert!(make_dir_rwx(&source_dir));
+ writeFile(&source_dir.push("lib.rs"), "pub fn f() { }");
+
+ let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
+ let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
+ debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
+ command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
+ debug!("Checking that foo exists in %s", dest_workspace.to_str());
+ assert_built_library_exists(&dest_workspace, "foo");
+ assert!(!built_library_exists(&source_dir, "foo"));
+}
+
+#[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 dir = mk_workspace(&dir_for_path, &Path("foo"), &NoVersion);
+ debug!("dir = %s", dir.to_str());
+ writeFile(&dir.push("main.rs"), "fn main() { let _x = (); }");
+ let dir_to_install_to = mkdtemp(&os::tmpdir(),
+ "dest_workspace").expect("rust_path_install_target failed");
+ let dir = dir.pop().pop();
+
+ let rust_path = Some(~[(~"RUST_PATH", fmt!("%s:%s", dir_to_install_to.to_str(),
+ dir.to_str()))]);
+ let cwd = os::getcwd();
+
+ debug!("RUST_PATH=%s:%s", dir_to_install_to.to_str(), dir.to_str());
+ command_line_test_with_env([~"install", ~"foo"],
+ &cwd,
+ rust_path);
+
+ assert_executable_exists(&dir_to_install_to, "foo");
+
+}
+
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
}
+pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
+ match x {
+ Some(y) => ~[y],
+ None => ~[]
+ }
+}
+
// tjc: cheesy
fn debug_flags() -> ~[~str] { ~[] }
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
_ => false
}
}
- fn ne(&self, other: &Version) -> bool {
- !self.eq(other)
- }
}
impl Ord for Version {
use std::{os,util};
use std::path::Path;
-use path_util::workspace_contains_package_id;
+use context::Ctx;
+use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack};
+use util::option_to_vec;
use package_id::PkgId;
use path_util::rust_path;
-pub fn each_pkg_parent_workspace(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
+pub fn each_pkg_parent_workspace(cx: &Ctx, pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
// Using the RUST_PATH, find workspaces that contain
// this package ID
- let workspaces = pkg_parent_workspaces(pkgid);
+ let workspaces = pkg_parent_workspaces(cx, pkgid);
if workspaces.is_empty() {
// tjc: make this a condition
fail!("Package %s not found in any of \
return true;
}
-pub fn pkg_parent_workspaces(pkgid: &PkgId) -> ~[Path] {
- rust_path().move_iter()
+pub fn pkg_parent_workspaces(cx: &Ctx, pkgid: &PkgId) -> ~[Path] {
+ let rs: ~[Path] = rust_path().move_iter()
.filter(|ws| workspace_contains_package_id(pkgid, ws))
- .collect()
+ .collect();
+ if cx.use_rust_path_hack {
+ rs + option_to_vec(find_dir_using_rust_path_hack(cx, pkgid))
+ }
+ else {
+ rs
+ }
+}
+
+pub fn is_workspace(p: &Path) -> bool {
+ os::path_is_dir(&p.push("src"))
}
/// Construct a workspace and package-ID name based on the current directory.
impl Eq for bool {
#[inline]
fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
- #[inline]
- fn ne(&self, other: &bool) -> bool { (*self) != (*other) }
}
#[cfg(not(test))]
impl Eq for char {
#[inline]
fn eq(&self, other: &char) -> bool { (*self) == (*other) }
- #[inline]
- fn ne(&self, other: &char) -> bool { (*self) != (*other) }
}
#[cfg(not(test))]
#[lang="eq"]
pub trait Eq {
fn eq(&self, other: &Self) -> bool;
+
+ #[inline]
fn ne(&self, other: &Self) -> bool { !self.eq(other) }
}
mod tests {
use super::*;
use prelude::*;
- use realstd::fmt::{String};
fn same(fmt: &'static str, p: ~[Piece<'static>]) {
let mut parser = Parser::new(fmt);
impl<T:Reader> ReaderUtil for T {
- fn read_bytes(&self,len: uint) -> ~[u8] {
+ fn read_bytes(&self, len: uint) -> ~[u8] {
let mut bytes = vec::with_capacity(len);
unsafe { vec::raw::set_len(&mut bytes, len); }
+++ /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.
-
-/*! Times trait
-
-~~~ {.rust}
-use iter::Times;
-let ten = 10 as uint;
-let mut accum = 0;
-do ten.times { accum += 1; }
-~~~
-
-*/
-
-#[allow(missing_doc)]
-pub trait Times {
- fn times(&self, it: &fn());
-}
-
#[lang="log_type"]
#[allow(missing_doc)]
pub fn log_type<T>(_level: u32, object: &T) {
- use io;
- use repr;
- use str;
-
- let bytes = do io::with_bytes_writer |writer| {
- repr::write_repr(writer, object);
- };
+ use sys;
// XXX: Bad allocation
- let msg = str::from_bytes(bytes);
+ let msg = sys::log_str(object);
newsched_log_str(msg);
}
impl Eq for f32 {
#[inline]
fn eq(&self, other: &f32) -> bool { (*self) == (*other) }
- #[inline]
- fn ne(&self, other: &f32) -> bool { (*self) != (*other) }
}
#[cfg(not(test))]
assert_eq!(infinity.abs_sub(&1f32), infinity);
assert_eq!(0f32.abs_sub(&neg_infinity), infinity);
assert_eq!(0f32.abs_sub(&infinity), 0f32);
+ }
+
+ #[test] #[ignore(cfg(windows))] // FIXME #8663
+ fn test_abs_sub_nowin() {
assert!(NaN.abs_sub(&-1f32).is_NaN());
assert!(1f32.abs_sub(&NaN).is_NaN());
}
assert_eq!(0f32.frexp(), (0f32, 0));
assert_eq!((-0f32).frexp(), (-0f32, 0));
+ }
+ #[test] #[ignore(cfg(windows))] // FIXME #8755
+ fn test_frexp_nowin() {
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let nan: f32 = Float::NaN();
impl Eq for f64 {
#[inline]
fn eq(&self, other: &f64) -> bool { (*self) == (*other) }
- #[inline]
- fn ne(&self, other: &f64) -> bool { (*self) != (*other) }
}
#[cfg(not(test))]
assert_eq!(infinity.abs_sub(&1f64), infinity);
assert_eq!(0f64.abs_sub(&neg_infinity), infinity);
assert_eq!(0f64.abs_sub(&infinity), 0f64);
+ }
+
+ #[test] #[ignore(cfg(windows))] // FIXME #8663
+ fn test_abs_sub_nowin() {
assert!(NaN.abs_sub(&-1f64).is_NaN());
assert!(1f64.abs_sub(&NaN).is_NaN());
}
assert_eq!(0f64.frexp(), (0f64, 0));
assert_eq!((-0f64).frexp(), (-0f64, 0));
+ }
+ #[test] #[ignore(cfg(windows))] // FIXME #8755
+ fn test_frexp_nowin() {
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
impl Eq for float {
#[inline]
fn eq(&self, other: &float) -> bool { (*self) == (*other) }
- #[inline]
- fn ne(&self, other: &float) -> bool { (*self) != (*other) }
}
#[cfg(not(test))]
assert_eq!(infinity.abs_sub(&1f), infinity);
assert_eq!(0f.abs_sub(&neg_infinity), infinity);
assert_eq!(0f.abs_sub(&infinity), 0f);
+ }
+
+ #[test] #[ignore(cfg(windows))] // FIXME #8663
+ fn test_abs_sub_nowin() {
assert!(NaN.abs_sub(&-1f).is_NaN());
assert!(1f.abs_sub(&NaN).is_NaN());
}
assert_eq!(0f.frexp(), (0f, 0));
assert_eq!((-0f).frexp(), (-0f, 0));
+ }
+ #[test] #[ignore(cfg(windows))] // FIXME #8755
+ fn test_frexp_nowin() {
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let nan: float = Float::NaN();
impl Eq for $T {
#[inline]
fn eq(&self, other: &$T) -> bool { return (*self) == (*other); }
- #[inline]
- fn ne(&self, other: &$T) -> bool { return (*self) != (*other); }
}
impl Orderable for $T {
pub trait Unsigned: Num {}
+/// Times trait
+///
+/// ~~~ {.rust}
+/// use num::Times;
+/// let ten = 10 as uint;
+/// let mut accum = 0;
+/// do ten.times { accum += 1; }
+/// ~~~
+///
+pub trait Times {
+ fn times(&self, it: &fn());
+}
+
pub trait Integer: Num
+ Orderable
+ Div<Self,Self>
+ Div<Self,Self>
+ Rem<Self,Self> {
// FIXME (#5527): These should be associated constants
+ // FIXME (#8888): Removing `unused_self` requires #8888 to be fixed.
fn bits(unused_self: Option<Self>) -> uint;
fn bytes(unused_self: Option<Self>) -> uint;
}
fn is_normal(&self) -> bool;
fn classify(&self) -> FPCategory;
+ // FIXME (#8888): Removing `unused_self` requires #8888 to be fixed.
fn mantissa_digits(unused_self: Option<Self>) -> uint;
fn digits(unused_self: Option<Self>) -> uint;
fn epsilon() -> Self;
//! Operations and constants for `uint`
-use iter;
+use num;
use sys;
pub use self::generated::*;
///
pub fn div_floor(x: uint, y: uint) -> uint { return x / y; }
-impl iter::Times for uint {
+impl num::Times for uint {
#[inline]
///
/// A convenience form for basic repetition. Given a uint `x`,
#[test]
pub fn test_times() {
- use iter::Times;
+ use num::Times;
let ten = 10 as uint;
let mut accum = 0;
do ten.times { accum += 1; }
impl Eq for $T {
#[inline]
fn eq(&self, other: &$T) -> bool { return (*self) == (*other); }
- #[inline]
- fn ne(&self, other: &$T) -> bool { return (*self) != (*other); }
}
impl Orderable for $T {
}
}
+/// Renames an existing file or directory
+pub fn rename_file(old: &Path, new: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe {
+ do old.with_c_str |old_buf| {
+ do new.with_c_str |new_buf| {
+ libc::rename(old_buf, new_buf) == (0 as c_int)
+ }
+ }
+ }
+}
+
#[cfg(unix)]
/// Returns the platform-specific value of errno
pub fn errno() -> int {
pub fn page_size() -> uint {
#[fixed_stack_segment]; #[inline(never)];
- unsafe {
- let mut info = libc::SYSTEM_INFO::new();
- libc::GetSystemInfo(&mut info);
+ unsafe {
+ let mut info = libc::SYSTEM_INFO::new();
+ libc::GetSystemInfo(&mut info);
- return info.dwPageSize as uint;
- }
+ return info.dwPageSize as uint;
+ }
}
pub struct MemoryMap {
// Windows-specific errors
ErrUnsupProt,
ErrUnsupOffset,
- ErrNeedRW,
ErrAlreadyExists,
ErrVirtualAlloc(uint),
ErrCreateFileMappingW(uint),
ErrUnknown(code) => fmt!("Unknown error=%?", code),
ErrUnsupProt => ~"Protection mode unsupported",
ErrUnsupOffset => ~"Offset in virtual memory mode is unsupported",
- ErrNeedRW => ~"File mapping should be at least readable/writable",
ErrAlreadyExists => ~"File mapping for specified file already exists",
ErrVirtualAlloc(code) => fmt!("VirtualAlloc failure=%?", code),
ErrCreateFileMappingW(code) => fmt!("CreateFileMappingW failure=%?", code),
})
}
}
+
+ pub fn granularity() -> uint {
+ page_size()
+ }
}
#[cfg(unix)]
})
}
} else {
- let dwDesiredAccess = match (readable, writable) {
- (true, true) => libc::FILE_MAP_ALL_ACCESS,
- (true, false) => libc::FILE_MAP_READ,
- (false, true) => libc::FILE_MAP_WRITE,
- _ => {
- return Err(ErrNeedRW);
- }
+ let dwDesiredAccess = match (executable, readable, writable) {
+ (false, true, false) => libc::FILE_MAP_READ,
+ (false, true, true) => libc::FILE_MAP_WRITE,
+ (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
+ (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
+ _ => return Err(ErrUnsupProt) // Actually, because of the check above,
+ // we should never get here.
};
unsafe {
let hFile = libc::get_osfhandle(fd) as HANDLE;
let mapping = libc::CreateFileMappingW(hFile,
ptr::mut_null(),
flProtect,
- (len >> 32) as DWORD,
- (len & 0xffff_ffff) as DWORD,
+ 0,
+ 0,
ptr::null());
if mapping == ptr::mut_null() {
return Err(ErrCreateFileMappingW(errno()));
}
let r = libc::MapViewOfFile(mapping,
dwDesiredAccess,
- (offset >> 32) as DWORD,
+ ((len as u64) >> 32) as DWORD,
(offset & 0xffff_ffff) as DWORD,
0);
match r as uint {
}
}
}
+
+ /// Granularity of MapAddr() and MapOffset() parameter values.
+ /// This may be greater than the value returned by page_size().
+ pub fn granularity() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe {
+ let mut info = libc::SYSTEM_INFO::new();
+ libc::GetSystemInfo(&mut info);
+
+ return info.dwAllocationGranularity as uint;
+ }
+ }
}
#[cfg(windows)]
#[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
+ use libc::consts::os::extra::FALSE;
unsafe {
match self.kind {
- MapVirtual => match libc::VirtualFree(self.data as *mut c_void,
- self.len,
- libc::MEM_RELEASE) {
- 0 => error!(fmt!("VirtualFree failed: %?", errno())),
- _ => ()
+ MapVirtual => {
+ if libc::VirtualFree(self.data as *mut c_void,
+ self.len,
+ libc::MEM_RELEASE) == FALSE {
+ error!(fmt!("VirtualFree failed: %?", errno()));
+ }
},
MapFile(mapping) => {
- if libc::UnmapViewOfFile(self.data as LPCVOID) != 0 {
+ if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
error!(fmt!("UnmapViewOfFile failed: %?", errno()));
}
- if libc::CloseHandle(mapping as HANDLE) != 0 {
+ if libc::CloseHandle(mapping as HANDLE) == FALSE {
error!(fmt!("CloseHandle failed: %?", errno()));
}
}
}
let path = tmpdir().push("mmap_file.tmp");
- let size = page_size() * 2;
+ let size = MemoryMap::granularity() * 2;
remove_file(&path);
let fd = unsafe {
pub use char::Char;
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use hash::Hash;
-pub use iter::Times;
+pub use num::Times;
pub use iterator::{FromIterator, Extendable};
pub use iterator::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator};
pub use iterator::{OrdIterator, MutableDoubleEndedIterator};
use cast;
use clone::Clone;
+#[cfg(not(test))]
use cmp::Equiv;
use iterator::{range, Iterator};
use option::{Option, Some, None};
* 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);
+ fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void);
+ fn push_ptr(&mut self);
+ fn pop_ptr(&mut self);
}
/// Helper function for alignment calculation.
impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
#[inline]
- pub fn bump(&self, sz: uint) {
+ pub fn bump(&mut self, sz: uint) {
do self.inner.move_ptr() |p| {
((p as uint) + sz) as *c_void
};
}
#[inline]
- pub fn align(&self, a: uint) {
+ pub fn align(&mut self, a: uint) {
do self.inner.move_ptr() |p| {
align(p as uint, a) as *c_void
};
}
#[inline]
- pub fn align_to<T>(&self) {
+ pub fn align_to<T>(&mut self) {
self.align(sys::min_align_of::<T>());
}
#[inline]
- pub fn bump_past<T>(&self) {
+ pub fn bump_past<T>(&mut 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 {
+ fn visit_bot(&mut self) -> bool {
self.align_to::<()>();
if ! self.inner.visit_bot() { return false; }
self.bump_past::<()>();
true
}
- fn visit_nil(&self) -> bool {
+ fn visit_nil(&mut self) -> bool {
self.align_to::<()>();
if ! self.inner.visit_nil() { return false; }
self.bump_past::<()>();
true
}
- fn visit_bool(&self) -> bool {
+ fn visit_bool(&mut self) -> bool {
self.align_to::<bool>();
if ! self.inner.visit_bool() { return false; }
self.bump_past::<bool>();
true
}
- fn visit_int(&self) -> bool {
+ fn visit_int(&mut self) -> bool {
self.align_to::<int>();
if ! self.inner.visit_int() { return false; }
self.bump_past::<int>();
true
}
- fn visit_i8(&self) -> bool {
+ fn visit_i8(&mut self) -> bool {
self.align_to::<i8>();
if ! self.inner.visit_i8() { return false; }
self.bump_past::<i8>();
true
}
- fn visit_i16(&self) -> bool {
+ fn visit_i16(&mut self) -> bool {
self.align_to::<i16>();
if ! self.inner.visit_i16() { return false; }
self.bump_past::<i16>();
true
}
- fn visit_i32(&self) -> bool {
+ fn visit_i32(&mut self) -> bool {
self.align_to::<i32>();
if ! self.inner.visit_i32() { return false; }
self.bump_past::<i32>();
true
}
- fn visit_i64(&self) -> bool {
+ fn visit_i64(&mut self) -> bool {
self.align_to::<i64>();
if ! self.inner.visit_i64() { return false; }
self.bump_past::<i64>();
true
}
- fn visit_uint(&self) -> bool {
+ fn visit_uint(&mut self) -> bool {
self.align_to::<uint>();
if ! self.inner.visit_uint() { return false; }
self.bump_past::<uint>();
true
}
- fn visit_u8(&self) -> bool {
+ fn visit_u8(&mut self) -> bool {
self.align_to::<u8>();
if ! self.inner.visit_u8() { return false; }
self.bump_past::<u8>();
true
}
- fn visit_u16(&self) -> bool {
+ fn visit_u16(&mut self) -> bool {
self.align_to::<u16>();
if ! self.inner.visit_u16() { return false; }
self.bump_past::<u16>();
true
}
- fn visit_u32(&self) -> bool {
+ fn visit_u32(&mut self) -> bool {
self.align_to::<u32>();
if ! self.inner.visit_u32() { return false; }
self.bump_past::<u32>();
true
}
- fn visit_u64(&self) -> bool {
+ fn visit_u64(&mut self) -> bool {
self.align_to::<u64>();
if ! self.inner.visit_u64() { return false; }
self.bump_past::<u64>();
true
}
- fn visit_float(&self) -> bool {
+ fn visit_float(&mut self) -> bool {
self.align_to::<float>();
if ! self.inner.visit_float() { return false; }
self.bump_past::<float>();
true
}
- fn visit_f32(&self) -> bool {
+ fn visit_f32(&mut self) -> bool {
self.align_to::<f32>();
if ! self.inner.visit_f32() { return false; }
self.bump_past::<f32>();
true
}
- fn visit_f64(&self) -> bool {
+ fn visit_f64(&mut self) -> bool {
self.align_to::<f64>();
if ! self.inner.visit_f64() { return false; }
self.bump_past::<f64>();
true
}
- fn visit_char(&self) -> bool {
+ fn visit_char(&mut self) -> bool {
self.align_to::<char>();
if ! self.inner.visit_char() { return false; }
self.bump_past::<char>();
true
}
- fn visit_estr_box(&self) -> bool {
+ fn visit_estr_box(&mut 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 {
+ fn visit_estr_uniq(&mut 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 {
+ fn visit_estr_slice(&mut 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,
+ fn visit_estr_fixed(&mut self, n: uint,
sz: uint,
align: uint) -> bool {
self.align(align);
true
}
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_box(&mut 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 {
+ fn visit_uniq(&mut 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 {
+ fn visit_uniq_managed(&mut 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 {
+ fn visit_ptr(&mut 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 {
+ fn visit_rptr(&mut 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 {
+ fn visit_unboxed_vec(&mut 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 {
+ fn visit_vec(&mut 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 {
+ fn visit_evec_box(&mut 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 {
+ fn visit_evec_uniq(&mut 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 {
+ fn visit_evec_uniq_managed(&mut 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 {
+ fn visit_evec_slice(&mut 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,
+ fn visit_evec_fixed(&mut 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) {
true
}
- fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+ fn visit_enter_rec(&mut 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,
+ fn visit_rec_field(&mut 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) {
true
}
- fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+ fn visit_leave_rec(&mut 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)
+ fn visit_enter_class(&mut self, n_fields: uint, sz: uint, align: uint)
-> bool {
self.align(align);
if ! self.inner.visit_enter_class(n_fields, sz, align) {
true
}
- fn visit_class_field(&self, i: uint, name: &str,
+ fn visit_class_field(&mut 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) {
true
}
- fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
+ fn visit_leave_class(&mut 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 {
+ fn visit_enter_tup(&mut 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 {
+ fn visit_tup_field(&mut 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 {
+ fn visit_leave_tup(&mut 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,
+ fn visit_enter_fn(&mut 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 {
+ fn visit_fn_input(&mut 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 {
+ fn visit_fn_output(&mut 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,
+ fn visit_leave_fn(&mut 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,
+ fn visit_enter_enum(&mut self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
true
}
- fn visit_enter_enum_variant(&self, variant: uint,
+ fn visit_enter_enum_variant(&mut self, variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
true
}
- fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+ fn visit_enum_variant_field(&mut 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; }
true
}
- fn visit_leave_enum_variant(&self, variant: uint,
+ fn visit_leave_enum_variant(&mut self, variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
true
}
- fn visit_leave_enum(&self, n_variants: uint,
+ fn visit_leave_enum(&mut 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) {
true
}
- fn visit_trait(&self) -> bool {
+ fn visit_trait(&mut 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 {
+ fn visit_param(&mut self, i: uint) -> bool {
if ! self.inner.visit_param(i) { return false; }
true
}
- fn visit_self(&self) -> bool {
+ fn visit_self(&mut 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 {
+ fn visit_type(&mut self) -> bool {
if ! self.inner.visit_type() { return false; }
true
}
- fn visit_opaque_box(&self) -> bool {
+ fn visit_opaque_box(&mut 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 {
+ fn visit_closure_ptr(&mut self, ck: uint) -> bool {
self.align_to::<@fn()>();
if ! self.inner.visit_closure_ptr(ck) { return false; }
self.bump_past::<@fn()>();
--- /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
+ }
+}
use cast::transmute;
use char;
use container::Container;
-use io::{Writer, WriterUtil};
+use rt::io;
use iterator::Iterator;
use libc::c_void;
use option::{Some, None};
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);
+ fn write_repr(&self, writer: &mut io::Writer);
}
impl Repr for () {
- fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
+ fn write_repr(&self, writer: &mut io::Writer) {
+ writer.write("()".as_bytes());
+ }
}
impl Repr for bool {
- fn write_repr(&self, writer: @Writer) {
- writer.write_str(if *self { "true" } else { "false" })
+ fn write_repr(&self, writer: &mut io::Writer) {
+ let s = if *self { "true" } else { "false" };
+ writer.write(s.as_bytes())
}
}
impl Repr for int {
- fn write_repr(&self, writer: @Writer) {
+ fn write_repr(&self, writer: &mut io::Writer) {
do ::int::to_str_bytes(*self, 10u) |bits| {
writer.write(bits);
}
}
macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
- fn write_repr(&self, writer: @Writer) {
+ fn write_repr(&self, writer: &mut io::Writer) {
do ::$ty::to_str_bytes(*self, 10u) |bits| {
writer.write(bits);
writer.write(bytes!($suffix));
int_repr!(u64, "u64")
impl Repr for float {
- fn write_repr(&self, writer: @Writer) {
+ fn write_repr(&self, writer: &mut io::Writer) {
let s = self.to_str();
writer.write(s.as_bytes());
}
}
macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
- fn write_repr(&self, writer: @Writer) {
+ fn write_repr(&self, writer: &mut io::Writer) {
let s = self.to_str();
writer.write(s.as_bytes());
writer.write(bytes!($suffix));
AlreadyFound
}
-pub struct ReprVisitor {
- ptr: @mut *c_void,
- ptr_stk: @mut ~[*c_void],
- var_stk: @mut ~[VariantState],
- writer: @Writer
+pub struct ReprVisitor<'self> {
+ ptr: *c_void,
+ ptr_stk: ~[*c_void],
+ var_stk: ~[VariantState],
+ writer: &'self mut io::Writer
}
-pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
+
+pub fn ReprVisitor<'a>(ptr: *c_void,
+ writer: &'a mut io::Writer) -> ReprVisitor<'a> {
ReprVisitor {
- ptr: @mut ptr,
- ptr_stk: @mut ~[],
- var_stk: @mut ~[],
+ ptr: ptr,
+ ptr_stk: ~[],
+ var_stk: ~[],
writer: writer,
}
}
-impl MovePtr for ReprVisitor {
+impl<'self> MovePtr for ReprVisitor<'self> {
#[inline]
- fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
- *self.ptr = adjustment(*self.ptr);
+ fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void) {
+ self.ptr = adjustment(self.ptr);
}
- fn push_ptr(&self) {
- self.ptr_stk.push(*self.ptr);
+ fn push_ptr(&mut self) {
+ self.ptr_stk.push(self.ptr);
}
- fn pop_ptr(&self) {
- *self.ptr = self.ptr_stk.pop();
+ fn pop_ptr(&mut self) {
+ self.ptr = self.ptr_stk.pop();
}
}
-impl ReprVisitor {
+impl<'self> ReprVisitor<'self> {
// Various helpers for the TyVisitor impl
#[inline]
- pub fn get<T>(&self, f: &fn(&T)) -> bool {
+ pub fn get<T>(&mut self, f: &fn(&mut ReprVisitor, &T)) -> bool {
unsafe {
- f(transmute::<*c_void,&T>(*self.ptr));
+ f(self, transmute::<*c_void,&T>(self.ptr));
}
true
}
#[inline]
- pub fn visit_inner(&self, inner: *TyDesc) -> bool {
- self.visit_ptr_inner(*self.ptr, inner)
+ pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
+ self.visit_ptr_inner(self.ptr, inner)
}
#[inline]
- pub fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
+ pub fn visit_ptr_inner(&mut 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);
+ // This should call the constructor up above, but due to limiting
+ // issues we have to recreate it here.
+ let u = ReprVisitor {
+ ptr: ptr,
+ ptr_stk: ~[],
+ var_stk: ~[],
+ writer: ::cast::transmute_copy(&self.writer),
+ };
+ let mut v = reflect::MovePtrAdaptor(u);
+ // Obviously this should not be a thing, but blame #8401 for now
+ visit_tydesc(inner, &mut v as &mut TyVisitor);
true
}
}
#[inline]
- pub fn write<T:Repr>(&self) -> bool {
- do self.get |v:&T| {
- v.write_repr(self.writer);
+ pub fn write<T:Repr>(&mut self) -> bool {
+ do self.get |this, v:&T| {
+ v.write_repr(unsafe { ::cast::transmute_copy(&this.writer) });
}
}
- pub fn write_escaped_slice(&self, slice: &str) {
- self.writer.write_char('"');
+ pub fn write_escaped_slice(&mut self, slice: &str) {
+ self.writer.write(['"' as u8]);
for ch in slice.iter() {
- self.writer.write_escaped_char(ch);
+ self.write_escaped_char(ch);
}
- self.writer.write_char('"');
+ self.writer.write(['"' as u8]);
}
- pub fn write_mut_qualifier(&self, mtbl: uint) {
+ pub fn write_mut_qualifier(&mut self, mtbl: uint) {
if mtbl == 0 {
- self.writer.write_str("mut ");
+ self.writer.write("mut ".as_bytes());
} else if mtbl == 1 {
// skip, this is ast::m_imm
} else {
assert_eq!(mtbl, 2);
- self.writer.write_str("const ");
+ self.writer.write("const ".as_bytes());
}
}
- pub fn write_vec_range(&self,
+ pub fn write_vec_range(&mut self,
_mtbl: uint,
ptr: *(),
len: uint,
-> bool {
let mut p = ptr as *u8;
let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
- self.writer.write_char('[');
+ self.writer.write(['[' as u8]);
let mut first = true;
let mut left = len;
// unit structs have 0 size, and don't loop forever.
if first {
first = false;
} else {
- self.writer.write_str(", ");
+ self.writer.write(", ".as_bytes());
}
self.visit_ptr_inner(p as *c_void, inner);
p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
left -= dec;
}
- self.writer.write_char(']');
+ self.writer.write([']' as u8]);
true
}
- pub fn write_unboxed_vec_repr(&self,
+ pub fn write_unboxed_vec_repr(&mut self,
mtbl: uint,
v: &raw::Vec<()>,
inner: *TyDesc)
self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
v.fill, inner)
}
+
+ fn write_escaped_char(&mut self, ch: char) {
+ match ch {
+ '\t' => self.writer.write("\\t".as_bytes()),
+ '\r' => self.writer.write("\\r".as_bytes()),
+ '\n' => self.writer.write("\\n".as_bytes()),
+ '\\' => self.writer.write("\\\\".as_bytes()),
+ '\'' => self.writer.write("\\'".as_bytes()),
+ '"' => self.writer.write("\\\"".as_bytes()),
+ '\x20'..'\x7e' => self.writer.write([ch as u8]),
+ _ => {
+ do char::escape_unicode(ch) |c| {
+ self.writer.write([c as u8]);
+ }
+ }
+ }
+ }
}
-impl TyVisitor for ReprVisitor {
- fn visit_bot(&self) -> bool {
- self.writer.write_str("!");
+impl<'self> TyVisitor for ReprVisitor<'self> {
+ fn visit_bot(&mut self) -> bool {
+ self.writer.write("!".as_bytes());
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_nil(&mut self) -> bool { self.write::<()>() }
+ fn visit_bool(&mut self) -> bool { self.write::<bool>() }
+ fn visit_int(&mut self) -> bool { self.write::<int>() }
+ fn visit_i8(&mut self) -> bool { self.write::<i8>() }
+ fn visit_i16(&mut self) -> bool { self.write::<i16>() }
+ fn visit_i32(&mut self) -> bool { self.write::<i32>() }
+ fn visit_i64(&mut 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_uint(&mut self) -> bool { self.write::<uint>() }
+ fn visit_u8(&mut self) -> bool { self.write::<u8>() }
+ fn visit_u16(&mut self) -> bool { self.write::<u16>() }
+ fn visit_u32(&mut self) -> bool { self.write::<u32>() }
+ fn visit_u64(&mut 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_float(&mut self) -> bool { self.write::<float>() }
+ fn visit_f32(&mut self) -> bool { self.write::<f32>() }
+ fn visit_f64(&mut 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_char(&mut self) -> bool {
+ do self.get::<char> |this, &ch| {
+ this.writer.write(['\'' as u8]);
+ this.write_escaped_char(ch);
+ this.writer.write(['\'' as u8]);
}
}
- fn visit_estr_box(&self) -> bool {
- do self.get::<@str> |s| {
- self.writer.write_char('@');
- self.write_escaped_slice(*s);
+ fn visit_estr_box(&mut self) -> bool {
+ do self.get::<@str> |this, s| {
+ this.writer.write(['@' as u8]);
+ this.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_uniq(&mut self) -> bool {
+ do self.get::<~str> |this, s| {
+ this.writer.write(['~' as u8]);
+ this.write_escaped_slice(*s);
}
}
- fn visit_estr_slice(&self) -> bool {
- do self.get::<&str> |s| {
- self.write_escaped_slice(*s);
+ fn visit_estr_slice(&mut self) -> bool {
+ do self.get::<&str> |this, s| {
+ this.write_escaped_slice(*s);
}
}
// Type no longer exists, vestigial function.
- fn visit_estr_fixed(&self, _n: uint, _sz: uint,
+ fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
_align: uint) -> bool { fail!(); }
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('@');
+ fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ self.writer.write(['@' as u8]);
self.write_mut_qualifier(mtbl);
- do self.get::<&raw::Box<()>> |b| {
+ do self.get::<&raw::Box<()>> |this, b| {
let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, inner);
+ this.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(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
+ self.writer.write(['~' as u8]);
+ do self.get::<*c_void> |this, b| {
+ this.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| {
+ fn visit_uniq_managed(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
+ self.writer.write(['~' as u8]);
+ do self.get::<&raw::Box<()>> |this, b| {
let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, inner);
+ this.visit_ptr_inner(p, inner);
}
}
- #[cfg(stage0)]
- 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_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool {
+ do self.get::<*c_void> |this, p| {
+ write!(this.writer, "({} as *", *p);
+ this.write_mut_qualifier(mtbl);
+ this.writer.write("())".as_bytes());
}
}
- #[cfg(not(stage0))]
- 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));
- self.write_mut_qualifier(mtbl);
- self.writer.write_str("())");
- }
- }
-
- fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
- self.writer.write_char('&');
+ fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ self.writer.write(['&' as u8]);
self.write_mut_qualifier(mtbl);
- do self.get::<*c_void> |p| {
- self.visit_ptr_inner(*p, inner);
+ do self.get::<*c_void> |this, p| {
+ this.visit_ptr_inner(*p, inner);
}
}
// Type no longer exists, vestigial function.
- fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
+ fn visit_vec(&mut 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_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ do self.get::<raw::Vec<()>> |this, b| {
+ this.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_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ do self.get::<&raw::Box<raw::Vec<()>>> |this, b| {
+ this.writer.write(['@' as u8]);
+ this.write_mut_qualifier(mtbl);
+ this.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(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ do self.get::<&raw::Vec<()>> |this, b| {
+ this.writer.write(['~' as u8]);
+ this.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_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ do self.get::<&raw::Box<raw::Vec<()>>> |this, b| {
+ this.writer.write(['~' as u8]);
+ this.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_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
+ do self.get::<raw::Slice<()>> |this, s| {
+ this.writer.write(['&' as u8]);
+ this.write_vec_range(mtbl, s.data, s.len, inner);
}
}
- fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
+ fn visit_evec_fixed(&mut 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);
+ do self.get::<()> |this, b| {
+ this.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
}
}
- fn visit_enter_rec(&self, _n_fields: uint,
+ fn visit_enter_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
- self.writer.write_char('{');
+ self.writer.write(['{' as u8]);
true
}
- fn visit_rec_field(&self, i: uint, name: &str,
+ fn visit_rec_field(&mut self, i: uint, name: &str,
mtbl: uint, inner: *TyDesc) -> bool {
if i != 0 {
- self.writer.write_str(", ");
+ self.writer.write(", ".as_bytes());
}
self.write_mut_qualifier(mtbl);
- self.writer.write_str(name);
- self.writer.write_str(": ");
+ self.writer.write(name.as_bytes());
+ self.writer.write(": ".as_bytes());
self.visit_inner(inner);
true
}
- fn visit_leave_rec(&self, _n_fields: uint,
+ fn visit_leave_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
- self.writer.write_char('}');
+ self.writer.write(['}' as u8]);
true
}
- fn visit_enter_class(&self, _n_fields: uint,
+ fn visit_enter_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
- self.writer.write_char('{');
+ self.writer.write(['{' as u8]);
true
}
- fn visit_class_field(&self, i: uint, name: &str,
+ fn visit_class_field(&mut self, i: uint, name: &str,
mtbl: uint, inner: *TyDesc) -> bool {
if i != 0 {
- self.writer.write_str(", ");
+ self.writer.write(", ".as_bytes());
}
self.write_mut_qualifier(mtbl);
- self.writer.write_str(name);
- self.writer.write_str(": ");
+ self.writer.write(name.as_bytes());
+ self.writer.write(": ".as_bytes());
self.visit_inner(inner);
true
}
- fn visit_leave_class(&self, _n_fields: uint,
+ fn visit_leave_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
- self.writer.write_char('}');
+ self.writer.write(['}' as u8]);
true
}
- fn visit_enter_tup(&self, _n_fields: uint,
+ fn visit_enter_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
- self.writer.write_char('(');
+ self.writer.write(['(' as u8]);
true
}
- fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
+ fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
if i != 0 {
- self.writer.write_str(", ");
+ self.writer.write(", ".as_bytes());
}
self.visit_inner(inner);
true
}
- fn visit_leave_tup(&self, _n_fields: uint,
+ fn visit_leave_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
if _n_fields == 1 {
- self.writer.write_char(',');
+ self.writer.write([',' as u8]);
}
- self.writer.write_char(')');
+ self.writer.write([')' as u8]);
true
}
- fn visit_enter_enum(&self,
+ fn visit_enter_enum(&mut 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))
+ get_disr(transmute(self.ptr))
};
- var_stk.push(SearchingFor(disr));
+ self.var_stk.push(SearchingFor(disr));
true
}
- fn visit_enter_enum_variant(&self, _variant: uint,
+ fn visit_enter_enum_variant(&mut self, _variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
}
if write {
- self.writer.write_str(name);
+ self.writer.write(name.as_bytes());
if n_fields > 0 {
- self.writer.write_char('(');
+ self.writer.write(['(' as u8]);
}
}
true
}
- fn visit_enum_variant_field(&self,
+ fn visit_enum_variant_field(&mut self,
i: uint,
_offset: uint,
inner: *TyDesc)
match self.var_stk[self.var_stk.len() - 1] {
Matched => {
if i != 0 {
- self.writer.write_str(", ");
+ self.writer.write(", ".as_bytes());
}
if ! self.visit_inner(inner) {
return false;
true
}
- fn visit_leave_enum_variant(&self, _variant: uint,
+ fn visit_leave_enum_variant(&mut 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(')');
+ self.writer.write([')' as u8]);
}
}
_ => ()
true
}
- fn visit_leave_enum(&self,
+ fn visit_leave_enum(&mut 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() {
+ match self.var_stk.pop() {
SearchingFor(*) => fail!("enum value matched no variant"),
_ => true
}
}
- fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+ fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
_n_inputs: uint, _retstyle: uint) -> bool { true }
- fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
+ fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
true
}
- fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
+ fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool {
true
}
- fn visit_leave_fn(&self, _purity: uint, _proto: uint,
+ fn visit_leave_fn(&mut 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_trait(&mut self) -> bool { true }
+ fn visit_param(&mut self, _i: uint) -> bool { true }
+ fn visit_self(&mut self) -> bool { true }
+ fn visit_type(&mut self) -> bool { true }
- fn visit_opaque_box(&self) -> bool {
- self.writer.write_char('@');
- do self.get::<&raw::Box<()>> |b| {
+ fn visit_opaque_box(&mut self) -> bool {
+ self.writer.write(['@' as u8]);
+ do self.get::<&raw::Box<()>> |this, b| {
let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- self.visit_ptr_inner(p, b.type_desc);
+ this.visit_ptr_inner(p, b.type_desc);
}
}
- fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+ fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
-pub fn write_repr<T>(writer: @Writer, object: &T) {
+pub fn write_repr<T>(writer: &mut io::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)
+ let mut v = reflect::MovePtrAdaptor(u);
+ visit_tydesc(tydesc, &mut v as &mut TyVisitor);
}
}
#[test]
fn test_repr() {
+ use str;
+ use str::Str;
+ use rt::io::Decorator;
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);
+ let mut m = io::mem::MemWriter::new();
+ write_repr(&mut m as &mut io::Writer, t);
+ let s = str::from_bytes_owned(m.inner());
+ assert_eq!(s.as_slice(), e);
}
exact_test(&10, "10");
--- /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 iterator::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]), "~[{}, {}, {}]");
+}
mod imp {
use libc;
use option::{Option, Some, None};
- use iterator::{Iterator, range};
+ use iterator::Iterator;
use str;
use unstable::finally::Finally;
use util;
+ use vec;
pub unsafe fn init(argc: int, argv: **u8) {
let args = load_argc_and_argv(argc, argv);
// Copied from `os`.
unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> ~[~str] {
- let mut args = ~[];
- for i in range(0u, argc as uint) {
- args.push(str::raw::from_c_str(*(argv as **libc::c_char).offset(i as int)));
+ do vec::from_fn(argc as uint) |i| {
+ str::raw::from_c_str(*(argv as **libc::c_char).offset(i as int))
}
- args
}
#[cfg(stage0)]
use option::*;
use rt::test::*;
use cell::Cell;
- use iter::Times;
+ use num::Times;
use rt::util;
#[test]
last_nread: int,
}
+impl FileStream {
+}
+
impl Reader for FileStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.fd.read(buf) {
}
#[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();
}
}
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_and_tell_smoke_test() {
file_test_io_seeking_impl();
}
}
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_and_write() {
file_test_io_seek_and_write_impl();
}
}
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8810
fn file_test_io_seek_shakedown() {
file_test_io_seek_shakedown_impl();
}
/// Synchronous, non-blocking file I/O.
pub mod file;
-/// Synchronous, in-memory I/O.
-pub mod pipe;
-
/// Synchronous, non-blocking network I/O.
pub mod net {
pub mod tcp;
use rt::rtio::{IoFactory, IoFactoryObject,
RtioSocket, RtioTcpListener,
RtioTcpListenerObject, RtioTcpStream,
- RtioTcpStreamObject, RtioStream};
+ RtioTcpStreamObject};
use rt::local::Local;
pub struct TcpStream(~RtioTcpStreamObject);
impl Reader for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- match (***self).read(buf) {
+ match (**self).read(buf) {
Ok(read) => Some(read),
Err(ioerr) => {
// EOF is indicated by returning None
impl Writer for TcpStream {
fn write(&mut self, buf: &[u8]) {
- match (***self).write(buf) {
+ match (**self).write(buf) {
Ok(_) => (),
Err(ioerr) => io_error::cond.raise(ioerr),
}
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8811
fn connect_error() {
do run_in_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
- assert_eq!(e.kind, ConnectionRefused);
+ assert!(e.kind == ConnectionRefused);
called = true;
}).inside {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8811
fn read_eof_twice_ip4() {
do run_in_newsched_task {
let addr = next_test_ip4();
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8811
fn read_eof_twice_ip6() {
do run_in_newsched_task {
let addr = next_test_ip6();
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8811
fn write_close_ip4() {
do run_in_newsched_task {
let addr = next_test_ip4();
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8811
fn write_close_ip6() {
do run_in_newsched_task {
let addr = next_test_ip6();
+++ /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::{RtioPipeObject, RtioStream, IoFactoryObject, IoFactory};
-use rt::uv::pipe;
-
-pub struct PipeStream(~RtioPipeObject);
-
-impl PipeStream {
- /// Creates a new pipe initialized, but not bound to any particular
- /// source/destination
- pub fn new() -> Option<PipeStream> {
- let pipe = unsafe {
- let io: *mut IoFactoryObject = Local::unsafe_borrow();
- (*io).pipe_init(false)
- };
- match pipe {
- Ok(p) => Some(PipeStream(p)),
- Err(ioerr) => {
- io_error::cond.raise(ioerr);
- None
- }
- }
- }
-
- /// Extracts the underlying libuv pipe to be bound to another source.
- pub fn uv_pipe(&self) -> pipe::Pipe {
- // Did someone say multiple layers of indirection?
- (**self).uv_pipe()
- }
-}
-
-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!() }
-}
use super::PathLike;
#[test]
+ #[ignore(cfg(windows))] // FIXME #8812
fn path_like_smoke_test() {
let expected = "/home";
let path = Path(expected);
/// For the Scheduler pointer to be aliased
pub unsafe fn unsafe_borrow<T>() -> *mut T {
let key = tls_key();
- let mut void_ptr: *mut c_void = tls::get(key);
+ let void_ptr = tls::get(key);
if void_ptr.is_null() {
rtabort!("thread-local pointer is null. bogus!");
}
- let ptr: *mut *mut c_void = &mut void_ptr;
- let ptr: *mut ~T = ptr as *mut ~T;
- let ptr: *mut T = &mut **ptr;
- return ptr;
+ void_ptr as *mut T
}
pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
let key = tls_key();
- let mut void_ptr: *mut c_void = tls::get(key);
+ let void_ptr = tls::get(key);
if void_ptr.is_null() {
- return None;
- }
- {
- let ptr: *mut *mut c_void = &mut void_ptr;
- let ptr: *mut ~T = ptr as *mut ~T;
- let ptr: *mut T = &mut **ptr;
- return Some(ptr);
+ None
+ } else {
+ Some(void_ptr as *mut T)
}
}
use cell::Cell;
use clone::Clone;
use container::Container;
-use iterator::{Iterator, range};
+use iterator::Iterator;
use option::{Option, None, Some};
use ptr::RawPtr;
use rt::local::Local;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
use unstable::sync::UnsafeArc;
-use vec::{OwnedVector, MutableVector};
+use vec;
+use vec::{OwnedVector, MutableVector, ImmutableVector};
/// The global (exchange) heap.
pub mod global_heap;
// Create a work queue for each scheduler, ntimes. Create an extra
// for the main thread if that flag is set. We won't steal from it.
- let mut work_queues = ~[];
- for _ in range(0u, nscheds) {
- let work_queue: WorkQueue<~Task> = WorkQueue::new();
- work_queues.push(work_queue);
- }
+ let work_queues: ~[WorkQueue<~Task>] = vec::from_fn(nscheds, |_| WorkQueue::new());
// The schedulers.
let mut scheds = ~[];
// sent the Shutdown message to terminate the schedulers.
let mut handles = ~[];
- for i in range(0u, nscheds) {
+ for work_queue in work_queues.iter() {
rtdebug!("inserting a regular scheduler");
// Every scheduler is driven by an I/O event loop.
let loop_ = ~UvEventLoop::new();
let mut sched = ~Scheduler::new(loop_,
- work_queues[i].clone(),
+ work_queue.clone(),
work_queues.clone(),
sleepers.clone());
let handle = sched.make_handle();
}
// Run each remaining scheduler in a thread.
- while !scheds.is_empty() {
+ for sched in scheds.move_rev_iter() {
rtdebug!("creating regular schedulers");
- let sched = scheds.pop();
let sched_cell = Cell::new(sched);
let thread = do Thread::start {
let mut sched = sched_cell.take();
// 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::net::ip::{IpAddr, SocketAddr};
-use rt::uv;
use rt::uv::uvio;
use path::Path;
use super::io::support::PathLike;
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
pub type RtioTimerObject = uvio::UvTimer;
pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback;
-pub type RtioPipeObject = uvio::UvPipeStream;
-pub type RtioProcessObject = uvio::UvProcess;
-pub type RtioProcessConfig<'self> = uv::process::Config<'self>;
pub trait EventLoop {
fn run(&mut self);
fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
-> Result<~RtioFileStream, IoError>;
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
- fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError>;
- fn spawn(&mut self, config: &RtioProcessConfig) -> Result<~RtioProcessObject, IoError>;
-}
-
-pub trait RtioStream {
- fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>;
}
-pub trait RtioTcpStream : RtioSocket + RtioStream {
+pub trait RtioTcpStream : RtioSocket {
+ fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>;
+ fn write(&mut self, buf: &[u8]) -> Result<(), IoError>;
fn peer_name(&mut self) -> Result<SocketAddr, IoError>;
fn control_congestion(&mut self) -> Result<(), IoError>;
fn nodelay(&mut self) -> Result<(), IoError>;
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;
-}
#[test]
fn multithreading() {
use rt::comm::*;
- use iter::Times;
+ use num::Times;
use vec::OwnedVector;
use container::Container;
use container::Container;
use from_str::FromStr;
use libc;
-use option::{Some, None};
+use option::{Some, None, Option};
use os;
use str::StrSlice;
use unstable::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
/// either `RUST_THREADS` or `num_cpus`.
pub fn default_sched_threads() -> uint {
match os::getenv("RUST_THREADS") {
- Some(nstr) => FromStr::from_str(nstr).unwrap(),
+ Some(nstr) => {
+ let opt_n: Option<uint> = FromStr::from_str(nstr);
+ match opt_n {
+ Some(n) if n > 0 => n,
+ _ => rtabort!("`RUST_THREADS` is `%s`, should be a positive integer", nstr)
+ }
+ }
None => {
if limit_thread_creation_due_to_osx_and_valgrind() {
1
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(watcher, status);
let data = watcher.get_watcher_data();
let cb = data.async_cb.get_ref();
(*cb)(watcher, status);
use prelude::*;
use ptr::null;
use libc::c_void;
-use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, UvError};
-use rt::uv::status_to_maybe_uv_error;
+use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
+ status_to_maybe_uv_error_with_loop, UvError};
use rt::uv::uvll;
use rt::uv::uvll::*;
use super::super::io::support::PathLike;
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)
+ sync_cleanup(loop_, result)
}
fn unlink_common<P: PathLike>(loop_: &Loop, path: &P, cb: Option<FsCallback>) -> int {
}
pub fn unlink<P: PathLike>(loop_: &Loop, path: &P, cb: FsCallback) {
let result = FsRequest::unlink_common(loop_, path, Some(cb));
- sync_cleanup(result);
+ sync_cleanup(loop_, result);
}
pub fn unlink_sync<P: PathLike>(loop_: &Loop, path: &P) -> Result<int, UvError> {
let result = FsRequest::unlink_common(loop_, path, None);
- sync_cleanup(result)
+ sync_cleanup(loop_, result)
}
pub fn install_req_data(&self, cb: Option<FsCallback>) {
match self { &FsRequest(ptr) => ptr }
}
}
- fn sync_cleanup(result: int) -> Result<int, UvError> {
- match status_to_maybe_uv_error(result as i32) {
+ fn sync_cleanup(loop_: &Loop, result: int)
+ -> Result<int, UvError> {
+ match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
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)
+ sync_cleanup(loop_, result)
}
fn read_common(&mut self, loop_: &Loop, buf: Buf,
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)
+ sync_cleanup(loop_, result)
}
fn close_common(self, loop_: &Loop, cb: Option<FsCallback>) -> int {
}
pub fn close_sync(self, loop_: &Loop) -> Result<int, UvError> {
let result = self.close_common(loop_, None);
- sync_cleanup(result)
+ sync_cleanup(loop_, result)
}
}
extern fn compl_cb(req: *uv_fs_t) {
let mut req: FsRequest = NativeHandle::from_native_handle(req);
+ let loop_ = req.get_loop();
// pull the user cb out of the req data
let cb = {
let data = req.get_req_data();
// in uv_fs_open calls, the result will be the fd in the
// case of success, otherwise it's -1 indicating an error
let result = req.get_result();
- let status = status_to_maybe_uv_error(result);
+ let status = status_to_maybe_uv_error_with_loop(
+ loop_.native_handle(), result);
// we have a req and status, call the user cb..
// only giving the user a ref to the FsRequest, as we
// have to clean it up, afterwards (and they aren't really
}
#[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();
}
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(idle_watcher, status);
(*cb)(idle_watcher, status);
}
}
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
let data = idle_watcher.get_watcher_data();
let cb: &IdleCallback = data.idle_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(idle_watcher, status);
(*cb)(idle_watcher, status);
}
}
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 idle;
pub mod timer;
pub mod async;
-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>,
- exit_cb: Option<ExitCallback>,
+ udp_send_cb: Option<UdpSendCallback>
}
pub trait WatcherInterop {
timer_cb: None,
async_cb: None,
udp_recv_cb: None,
- udp_send_cb: None,
- exit_cb: None,
+ udp_send_cb: None
};
let data = transmute::<~WatcherData, *c_void>(data);
uvll::set_data_for_uv_handle(self.native_handle(), data);
// XXX: Need to define the error constants like EOF so they can be
// compared to the UvError type
-pub struct UvError(c_int);
+pub struct UvError(uvll::uv_err_t);
impl UvError {
pub fn name(&self) -> ~str {
unsafe {
- let inner = match self { &UvError(a) => a };
+ let inner = match self { &UvError(ref a) => a };
let name_str = uvll::err_name(inner);
assert!(name_str.is_not_null());
from_c_str(name_str)
pub fn desc(&self) -> ~str {
unsafe {
- let inner = match self { &UvError(a) => a };
+ let inner = match self { &UvError(ref a) => a };
let desc_str = uvll::strerror(inner);
assert!(desc_str.is_not_null());
from_c_str(desc_str)
}
pub fn is_eof(&self) -> bool {
- **self == uvll::EOF
+ self.code == uvll::EOF
}
}
#[test]
fn error_smoke_test() {
- let err: UvError = UvError(uvll::EOF);
+ let err = uvll::uv_err_t { code: 1, sys_errno_: 1 };
+ let err: UvError = UvError(err);
assert_eq!(err.to_str(), ~"EOF: end of file");
}
+pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError {
+ unsafe {
+ let loop_ = watcher.event_loop();
+ UvError(uvll::last_error(loop_.native_handle()))
+ }
+}
+
pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
unsafe {
// Importing error constants
use rt::io::*;
// uv error descriptions are static
- let c_desc = uvll::strerror(*uverr);
+ let c_desc = uvll::strerror(&*uverr);
let desc = str::raw::c_str_to_static_slice(c_desc);
- let kind = match *uverr {
+ let kind = match uverr.code {
UNKNOWN => OtherIoError,
OK => OtherIoError,
EOF => EndOfFile,
ECONNREFUSED => ConnectionRefused,
ECONNRESET => ConnectionReset,
EPIPE => BrokenPipe,
- err => {
- rtdebug!("uverr.code %d", err as int);
+ _ => {
+ rtdebug!("uverr.code %u", uverr.code as uint);
// XXX: Need to map remaining uv error types
OtherIoError
}
}
}
-/// Convert a callback status to a UvError
-pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError> {
- if status >= 0 {
+/// Given a uv handle, convert a callback status to a UvError
+pub fn status_to_maybe_uv_error_with_loop(
+ loop_: *uvll::uv_loop_t,
+ status: c_int) -> Option<UvError> {
+ if status != -1 {
+ None
+ } else {
+ unsafe {
+ rtdebug!("loop: %x", loop_ as uint);
+ let err = uvll::last_error(loop_);
+ Some(UvError(err))
+ }
+ }
+}
+/// Given a uv handle, convert a callback status to a UvError
+pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
+ status: c_int) -> Option<UvError> {
+ if status != -1 {
None
} else {
- Some(UvError(status))
+ unsafe {
+ rtdebug!("handle: %x", handle.native_handle() as uint);
+ let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
+ status_to_maybe_uv_error_with_loop(loop_, status)
+ }
}
}
use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback,
status_to_maybe_uv_error};
use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use rt::uv::last_uv_error;
use vec;
use str;
use from_str::{FromStr};
rtdebug!("buf len: %d", buf.len as int);
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
- let status = status_to_maybe_uv_error(nread as c_int);
+ let status = status_to_maybe_uv_error(stream_watcher, nread as c_int);
(*cb)(stream_watcher, nread as int, buf, status);
}
}
let mut stream_watcher = write_request.stream();
write_request.delete();
let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(stream_watcher, status);
cb(stream_watcher, status);
}
}
};
match result {
0 => Ok(()),
- _ => Err(UvError(result)),
+ _ => Err(last_uv_error(self)),
}
}
}
let mut stream_watcher = connect_request.stream();
connect_request.delete();
let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(stream_watcher, status);
cb(stream_watcher, status);
}
}
rtdebug!("connection_cb");
let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(stream_watcher, status);
(*cb)(stream_watcher, status);
}
}
};
match result {
0 => Ok(()),
- _ => Err(UvError(result)),
+ _ => Err(last_uv_error(self)),
}
}
}
rtdebug!("buf len: %d", buf.len as int);
let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
- let status = status_to_maybe_uv_error(nread as c_int);
+ let status = status_to_maybe_uv_error(udp_watcher, nread as c_int);
let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
(*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
}
let mut udp_watcher = send_request.handle();
send_request.delete();
let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(udp_watcher, status);
cb(udp_watcher, status);
}
}
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8815
fn listen_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8815
fn listen_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8815
fn udp_recv_ip4() {
do run_in_bare_thread() {
static MAX: int = 10;
}
#[test]
+ #[ignore(cfg(windows))] // FIXME #8815
fn udp_recv_ip6() {
do run_in_bare_thread() {
static MAX: int = 10;
+++ /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 libc;
-use ptr;
-use vec;
-use cell::Cell;
-
-use rt::uv;
-use rt::uv::net;
-use rt::uv::pipe;
-use rt::uv::uvll;
-
-/// A process wraps the handle of the underlying uv_process_t.
-pub struct Process(*uvll::uv_process_t);
-
-/// This configuration describes how a new process should be spawned. This is
-/// translated to libuv's own configuration
-pub struct Config<'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: &'self [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),
-
- /// The specified libuv stream is inherited for the corresponding file
- /// descriptor it is assigned to.
- InheritStream(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(pipe::Pipe, bool /* readable */, bool /* writable */),
-}
-
-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, config: &Config,
- exit_cb: uv::ExitCallback) -> Result<(), 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 mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(
- config.io.len());
- unsafe {
- vec::raw::set_len(&mut stdio, config.io.len());
- for (slot, &other) in stdio.iter().zip(config.io.iter()) {
- set_stdio(slot as *uvll::uv_stdio_container_t, other);
- }
- }
-
- let exit_cb = Cell::new(exit_cb);
- 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(())
- }
- 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) {
- match io {
- Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); }
- InheritFd(fd) => {
- uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
- uvll::set_stdio_container_fd(dst, fd);
- }
- InheritStream(stream) => {
- uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_STREAM);
- uvll::set_stdio_container_stream(dst, stream.native_handle());
- }
- 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;
- }
- uvll::set_stdio_container_flags(dst, flags);
- uvll::set_stdio_container_stream(dst,
- pipe.as_stream().native_handle());
- }
- }
-}
-
-/// 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 }
- }
-}
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
let data = watcher.get_watcher_data();
let cb = data.timer_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
+ let status = status_to_maybe_uv_error(watcher, status);
(*cb)(watcher, status);
}
}
use cast;
use cell::Cell;
use clone::Clone;
-use libc::{c_int, c_uint, c_void, pid_t};
+use libc::{c_int, c_uint, c_void};
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::kill::BlockedTask;
use rt::local::Local;
use rt::rtio::*;
use rt::sched::{Scheduler, SchedHandle};
};
if r != 0 {
- let status = status_to_maybe_uv_error(r);
+ let status = status_to_maybe_uv_error(handle, r);
return Err(uv_error_to_io_error(status.unwrap()));
}
assert!(!result_cell.is_empty());
return result_cell.take();
}
-
- fn pipe_init(&mut self, ipc: bool) -> Result<~RtioPipeObject, IoError> {
- let home = get_handle_to_current_scheduler!();
- Ok(~UvPipeStream { pipe: Pipe::new(self.uv_loop(), ipc), home: home })
- }
-
- fn spawn(&mut self,
- config: &process::Config) -> Result<~RtioProcessObject, 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(()) => {
- // Only now do we actually get a handle to this scheduler.
- ret.home = Some(get_handle_to_current_scheduler!());
- Ok(ret)
- }
- 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 {
uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher(), r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::tcp_simultaneous_accepts(self_.watcher().native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher(), r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
}
-trait UvStream: HomingIO {
- fn as_stream(&mut self) -> StreamWatcher;
+pub struct UvTcpStream {
+ watcher: TcpWatcher,
+ home: SchedHandle,
+}
+
+impl HomingIO for UvTcpStream {
+ fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
}
-// FIXME(#3429) I would rather this be `impl<T: UvStream> RtioStream for T` but
-// that has conflicts with other traits that also have methods
-// called `read` and `write`
-macro_rules! rtiostream(($t:ident) => {
-impl RtioStream for $t {
+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| {
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self_.watcher.as_stream().close {
+ let scheduler: ~Scheduler = Local::take();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+ }
+}
+
+impl RtioSocket for UvTcpStream {
+ fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
+ do self.home_for_io |self_| {
+ socket_name(Tcp, self_.watcher)
+ }
+ }
+}
+
+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 alloc: AllocCallback = |_| unsafe {
slice_to_uv_buf(*buf_ptr)
};
- let mut watcher = self_.as_stream();
+ 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
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_.as_stream();
+ let mut watcher = self_.watcher.as_stream();
do watcher.write(buf) |_watcher, status| {
let result = if status.is_none() {
Ok(())
result_cell.take()
}
}
-}
-})
-
-rtiostream!(UvPipeStream)
-rtiostream!(UvTcpStream)
-
-pub struct UvPipeStream {
- pipe: Pipe,
- home: SchedHandle,
-}
-
-impl UvStream for UvPipeStream {
- fn as_stream(&mut self) -> StreamWatcher { self.pipe.as_stream() }
-}
-
-impl HomingIO for UvPipeStream {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvPipeStream {
- fn drop(&self) {
- // FIXME(#4330): should not need a transmute
- let this = unsafe { cast::transmute_mut(self) };
- do this.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 UvPipeStream {
- pub fn uv_pipe(&self) -> Pipe { self.pipe }
-}
-pub struct UvTcpStream {
- watcher: TcpWatcher,
- home: SchedHandle,
-}
-
-impl HomingIO for UvTcpStream {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTcpStream {
- fn drop(&self) {
- // FIXME(#4330): should not need a transmute
- let this = unsafe { cast::transmute_mut(self) };
- do this.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_.watcher.as_stream().close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-impl UvStream for UvTcpStream {
- fn as_stream(&mut self) -> StreamWatcher { self.watcher.as_stream() }
-}
-
-impl RtioSocket for UvTcpStream {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Tcp, self_.watcher)
- }
- }
-}
-
-impl RtioTcpStream for UvTcpStream {
fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
do self.home_for_io |self_| {
socket_name(TcpPeer, self_.watcher)
do self.home_for_io |self_| {
let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
do self.home_for_io |self_| {
let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
delay_in_seconds as c_uint)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
};
- match status_to_maybe_uv_error(r) {
+ match status_to_maybe_uv_error(self_.watcher, r) {
Some(err) => Err(uv_error_to_io_error(err)),
None => Ok(())
}
}
}
-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(&self) {
- // FIXME(#4330): should not need a transmute
- let this = unsafe { cast::transmute_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 this.home.is_none() {
- close(this)
- } else {
- this.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_newsched_task {
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8816
fn test_udp_twice() {
do run_in_newsched_task {
let server_addr = next_test_ip4();
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8816
fn file_test_uvio_full_simple() {
do run_in_newsched_task {
file_test_uvio_full_simple_impl();
use libc;
use prelude::*;
use ptr;
+use str;
use vec;
-pub use self::errors::*;
-
+pub static UNKNOWN: c_int = -1;
pub static OK: c_int = 0;
-pub static EOF: c_int = -4095;
-pub static UNKNOWN: c_int = -4094;
-
-// uv-errno.h redefines error codes for windows, but not for unix...
-
-#[cfg(windows)]
-pub mod errors {
- use libc::c_int;
+pub static EOF: c_int = 1;
+pub static EADDRINFO: c_int = 2;
+pub static EACCES: c_int = 3;
+pub static ECONNREFUSED: c_int = 12;
+pub static ECONNRESET: c_int = 13;
+pub static EPIPE: c_int = 36;
- pub static EACCES: c_int = -4093;
- pub static ECONNREFUSED: c_int = -4079;
- pub static ECONNRESET: c_int = -4078;
- pub static EPIPE: c_int = -4048;
+pub struct uv_err_t {
+ code: c_int,
+ sys_errno_: c_int
}
-#[cfg(not(windows))]
-pub mod errors {
- use libc;
- use libc::c_int;
-
- pub static EACCES: c_int = -libc::EACCES;
- pub static ECONNREFUSED: c_int = -libc::ECONNREFUSED;
- pub static ECONNRESET: c_int = -libc::ECONNRESET;
- 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;
pub struct uv_buf_t {
base: *u8,
len: libc::size_t,
}
-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_stream_t = c_void;
pub type uv_fs_t = c_void;
pub type uv_udp_send_t = c_void;
-pub type uv_process_t = c_void;
-pub type uv_pipe_t = c_void;
#[cfg(stage0)]
pub type uv_idle_cb = *u8;
pub type uv_timer_cb = *u8;
#[cfg(stage0)]
pub type uv_write_cb = *u8;
-#[cfg(stage0)]
-pub type uv_exit_cb = *u8;
#[cfg(not(stage0))]
pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
#[cfg(not(stage0))]
pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
status: c_int);
-#[cfg(not(stage0))]
-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;
pub type sockaddr_in6 = c_void;
pub type sockaddr_storage = c_void;
-#[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,
}
#[test]
+#[ignore(cfg(windows))] // FIXME #8817
#[fixed_stack_segment]
#[inline(never)]
fn request_sanity_check() {
return rust_uv_read_stop(stream as *c_void);
}
-pub unsafe fn strerror(err: c_int) -> *c_char {
+pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
#[fixed_stack_segment]; #[inline(never)];
+
+ return rust_uv_last_error(loop_handle);
+}
+
+pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_strerror(err);
}
-pub unsafe fn err_name(err: c_int) -> *c_char {
+pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
#[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_err_name(err);
}
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)];
return rust_uv_get_len_from_buf(buf);
}
+pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
+ let err = last_error(uv_loop);
+ let err_ptr = ptr::to_unsafe_ptr(&err);
+ let err_name = str::raw::from_c_str(err_name(err_ptr));
+ let err_msg = str::raw::from_c_str(strerror(err_ptr));
+ return fmt!("LIBUV ERROR: name: %s msg: %s",
+ err_name, err_msg);
+}
+
+pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data {
+ let err = last_error(uv_loop);
+ let err_ptr = ptr::to_unsafe_ptr(&err);
+ let err_name = str::raw::from_c_str(err_name(err_ptr));
+ let err_msg = str::raw::from_c_str(strerror(err_ptr));
+ uv_err_data { err_name: err_name, err_msg: err_msg }
+}
pub struct uv_err_data {
err_name: ~str,
cb: uv_async_cb) -> c_int;
fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
- fn rust_uv_strerror(err: c_int) -> *c_char;
- fn rust_uv_err_name(err: c_int) -> *c_char;
+ fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t;
+ fn rust_uv_strerror(err: *uv_err_t) -> *c_char;
+ fn rust_uv_err_name(err: *uv_err_t) -> *c_char;
fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in;
fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6;
fn rust_uv_free_ip4_addr(addr: *sockaddr_in);
fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
- 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;
}
//! Process spawning.
+#[allow(missing_doc)];
+
+use c_str::ToCStr;
use cast;
-use cell::Cell;
+use clone::Clone;
use comm::{stream, SharedChan, GenericChan, GenericPort};
-#[cfg(not(windows))]
+use io;
+use libc::{pid_t, c_void, c_int};
use libc;
-use libc::{pid_t, c_int};
+use option::{Some, None};
+use os;
use prelude::*;
+use ptr;
use task;
use vec::ImmutableVector;
-use rt::io;
-use rt::local::Local;
-use rt::rtio::{IoFactoryObject, RtioProcessObject, RtioProcess, IoFactory};
-use rt::uv::process;
-
/**
* A value representing a child process.
*
* for the process to terminate.
*/
pub struct Process {
+
/// The unique id of the process (this should never be negative).
priv pid: pid_t,
- /// The internal handle to the underlying libuv process.
- priv handle: ~RtioProcessObject,
+ /**
+ * A handle to the process - on unix this will always be NULL, but on
+ * windows it will be a HANDLE to the process, which will prevent the
+ * pid being re-used until the handle is closed.
+ */
+ priv handle: *(),
- /// Some(fd), or None when stdin is being redirected from a fd not created
- /// by Process::new.
- priv input: Option<~io::Writer>,
+ /// Some(fd), or None when stdin is being redirected from a fd not created by Process::new.
+ priv input: Option<c_int>,
- /// Some(file), or None when stdout is being redirected to a fd not created
- /// by Process::new.
- priv output: Option<~io::Reader>,
+ /// Some(file), or None when stdout is being redirected to a fd not created by Process::new.
+ priv output: Option<*libc::FILE>,
- /// Some(file), or None when stderr is being redirected to a fd not created
- /// by Process::new.
- priv error: Option<~io::Reader>,
+ /// Some(file), or None when stderr is being redirected to a fd not created by Process::new.
+ priv error: Option<*libc::FILE>,
+
+ /// None until finish() is called.
+ priv exit_code: Option<int>,
}
/// Options that can be given when starting a Process.
* If this is None then a new pipe will be created for the new program's
* output and Process.output() will provide a Reader to read from this pipe.
*
- * If this is Some(file-descriptor) then the new process will write its
- * output to the given file descriptor, Process.output_redirected() will
- * return true, and Process.output() will fail.
+ * If this is Some(file-descriptor) then the new process will write its output
+ * to the given file descriptor, Process.output_redirected() will return
+ * true, and Process.output() will fail.
*/
out_fd: Option<c_int>,
/**
- * If this is None then a new pipe will be created for the new progam's
- * error stream and Process.error() will provide a Reader to read from this
- * pipe.
+ * If this is None then a new pipe will be created for the new program's
+ * error stream and Process.error() will provide a Reader to read from this pipe.
*
- * If this is Some(file-descriptor) then the new process will write its
- * error output to the given file descriptor, Process.error_redirected()
- * will return true, and and Process.error() will fail.
+ * If this is Some(file-descriptor) then the new process will write its error output
+ * to the given file descriptor, Process.error_redirected() will return true, and
+ * and Process.error() will fail.
*/
err_fd: Option<c_int>,
}
-impl<'self> ProcessOptions<'self> {
+impl <'self> ProcessOptions<'self> {
/// Return a ProcessOptions that has None in every field.
- pub fn new() -> ProcessOptions {
+ pub fn new<'a>() -> ProcessOptions<'a> {
ProcessOptions {
env: None,
dir: None,
/// The output of a finished process.
pub struct ProcessOutput {
+
/// The status (exit code) of the process.
status: int,
* the working directory and the standard IO streams.
*/
pub fn new(prog: &str, args: &[~str],
- options: ProcessOptions) -> Option<Process> {
- // First, translate all the stdio options into their libuv equivalents
- let (uv_stdin, stdin) = match options.in_fd {
- Some(fd) => (process::InheritFd(fd), None),
+ options: ProcessOptions)
+ -> Process {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ let (in_pipe, in_fd) = match options.in_fd {
None => {
- let p = io::pipe::PipeStream::new().expect("need stdin pipe");
- (process::CreatePipe(p.uv_pipe(), true, false),
- Some(~p as ~io::Writer))
- }
+ let pipe = os::pipe();
+ (Some(pipe), pipe.input)
+ },
+ Some(fd) => (None, fd)
};
- let (uv_stdout, stdout) = match options.out_fd {
- Some(fd) => (process::InheritFd(fd), None),
+ let (out_pipe, out_fd) = match options.out_fd {
None => {
- let p = io::pipe::PipeStream::new().expect("need stdout pipe");
- (process::CreatePipe(p.uv_pipe(), false, true),
- Some(~p as ~io::Reader))
- }
+ let pipe = os::pipe();
+ (Some(pipe), pipe.out)
+ },
+ Some(fd) => (None, fd)
};
- let (uv_stderr, stderr) = match options.err_fd {
- Some(fd) => (process::InheritFd(fd), None),
+ let (err_pipe, err_fd) = match options.err_fd {
None => {
- let p = io::pipe::PipeStream::new().expect("need stderr pipe");
- (process::CreatePipe(p.uv_pipe(), false, true),
- Some(~p as ~io::Reader))
- }
+ let pipe = os::pipe();
+ (Some(pipe), pipe.out)
+ },
+ Some(fd) => (None, fd)
};
- // Next, massage our options into the libuv options
- let dir = options.dir.map(|d| d.to_str());
- let dir = dir.map(|d| d.as_slice());
- let config = process::Config {
- program: prog,
- args: args,
- env: options.env.map(|e| e.as_slice()),
- cwd: dir,
- io: [uv_stdin, uv_stdout, uv_stderr],
- };
+ let res = spawn_process_os(prog, args, options.env.clone(), options.dir,
+ in_fd, out_fd, err_fd);
- // Finally, actually spawn the process
unsafe {
- let io: *mut IoFactoryObject = Local::unsafe_borrow();
- match (*io).spawn(&config) {
- Ok(handle) => {
- Some(Process {
- pid: handle.id(),
- handle: handle,
- input: stdin,
- output: stdout,
- error: stderr,
- })
- }
- Err(*) => { None }
- }
+ for pipe in in_pipe.iter() { libc::close(pipe.input); }
+ for pipe in out_pipe.iter() { libc::close(pipe.out); }
+ for pipe in err_pipe.iter() { libc::close(pipe.out); }
+ }
+
+ Process {
+ pid: res.pid,
+ handle: res.handle,
+ input: in_pipe.map(|pipe| pipe.out),
+ output: out_pipe.map(|pipe| os::fdopen(pipe.input)),
+ error: err_pipe.map(|pipe| os::fdopen(pipe.input)),
+ exit_code: None,
}
}
/// Returns the unique id of the process
pub fn get_id(&self) -> pid_t { self.pid }
+ fn input_fd(&mut self) -> c_int {
+ match self.input {
+ Some(fd) => fd,
+ None => fail!("This Process's stdin was redirected to an \
+ existing file descriptor.")
+ }
+ }
+
+ fn output_file(&mut self) -> *libc::FILE {
+ match self.output {
+ Some(file) => file,
+ None => fail!("This Process's stdout was redirected to an \
+ existing file descriptor.")
+ }
+ }
+
+ fn error_file(&mut self) -> *libc::FILE {
+ match self.error {
+ Some(file) => file,
+ None => fail!("This Process's stderr was redirected to an \
+ existing file descriptor.")
+ }
+ }
+
/**
- * Returns a rt::io::Writer that can be used to write to this Process's
- * stdin.
+ * Returns whether this process is reading its stdin from an existing file
+ * descriptor rather than a pipe that was created specifically for this
+ * process.
*
- * Fails if this Process's stdin was redirected to an existing file
- * descriptor.
+ * If this method returns true then self.input() will fail.
*/
- pub fn input<'a>(&'a mut self) -> &'a mut io::Writer {
- let ret: &mut io::Writer = *self.input.get_mut_ref();
- return ret;
+ pub fn input_redirected(&self) -> bool {
+ self.input.is_none()
}
/**
- * Returns a rt::io::Reader that can be used to read from this Process's
- * stdout.
+ * Returns whether this process is writing its stdout to an existing file
+ * descriptor rather than a pipe that was created specifically for this
+ * process.
*
- * Fails if this Process's stdout was redirected to an existing file
- * descriptor.
+ * If this method returns true then self.output() will fail.
*/
- pub fn output<'a>(&'a mut self) -> &'a mut io::Reader {
- let ret: &mut io::Reader = *self.output.get_mut_ref();
- return ret;
+ pub fn output_redirected(&self) -> bool {
+ self.output.is_none()
}
/**
- * Returns a rt::io::Reader that can be used to read from this Process's
- * stderr.
+ * Returns whether this process is writing its stderr to an existing file
+ * descriptor rather than a pipe that was created specifically for this
+ * process.
*
- * Fails if this Process's stderr was redirected to an existing file
- * descriptor.
+ * If this method returns true then self.error() will fail.
*/
- pub fn error<'a>(&'a mut self) -> &'a mut io::Reader {
- let ret: &mut io::Reader = *self.error.get_mut_ref();
- return ret;
+ pub fn error_redirected(&self) -> bool {
+ self.error.is_none()
}
/**
- * Closes the handle to stdin, waits for the child process to terminate, and
- * returns the exit code.
+ * Returns an io::Writer that can be used to write to this Process's stdin.
*
- * If the child has already been finished then the exit code is returned.
+ * Fails if this Process's stdin was redirected to an existing file descriptor.
*/
- pub fn finish(&mut self) -> int {
- // We're not going to be giving any more input, so close the input by
- // destroying it. Also, if the output is desired, then
- // finish_with_output is called so we discard all the outputs here. Note
- // that the process may not terminate if we don't destroy stdio because
- // it'll be waiting in a write which we'll just never read.
- self.input.take();
- self.output.take();
- self.error.take();
+ pub fn input(&mut self) -> @io::Writer {
+ // FIXME: the Writer can still be used after self is destroyed: #2625
+ io::fd_writer(self.input_fd(), false)
+ }
- self.handle.wait()
+ /**
+ * Returns an io::Reader that can be used to read from this Process's stdout.
+ *
+ * Fails if this Process's stdout was redirected to an existing file descriptor.
+ */
+ pub fn output(&mut self) -> @io::Reader {
+ // FIXME: the Reader can still be used after self is destroyed: #2625
+ io::FILE_reader(self.output_file(), false)
}
/**
- * Closes the handle to stdin, waits for the child process to terminate,
- * and reads and returns all remaining output of stdout and stderr, along
- * with the exit code.
+ * Returns an io::Reader that can be used to read from this Process's stderr.
*
- * If the child has already been finished then the exit code and any
- * remaining unread output of stdout and stderr will be returned.
+ * Fails if this Process's stderr was redirected to an existing file descriptor.
+ */
+ pub fn error(&mut self) -> @io::Reader {
+ // FIXME: the Reader can still be used after self is destroyed: #2625
+ io::FILE_reader(self.error_file(), false)
+ }
+
+ /**
+ * Closes the handle to the child process's stdin.
*
- * This method will fail if the child process's stdout or stderr streams
- * were redirected to existing file descriptors, or if this method has
- * already been called.
+ * If this process is reading its stdin from an existing file descriptor, then this
+ * method does nothing.
*/
- pub fn finish_with_output(&mut self) -> ProcessOutput {
- // This should probably be a helper method in rt::io
- fn read_everything(input: &mut io::Reader) -> ~[u8] {
- let mut result = ~[];
- let mut buf = [0u8, ..1024];
- loop {
- match input.read(buf) {
- Some(i) => { result = result + buf.slice_to(i) }
- None => break
+ pub fn close_input(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
+ match self.input {
+ Some(-1) | None => (),
+ Some(fd) => {
+ unsafe {
+ libc::close(fd);
}
+ self.input = Some(-1);
}
- return result;
}
+ }
+
+ fn close_outputs(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
+ fclose_and_null(&mut self.output);
+ fclose_and_null(&mut self.error);
+
+ fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+ #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
+ match *f_opt {
+ Some(f) if !f.is_null() => {
+ unsafe {
+ libc::fclose(f);
+ *f_opt = Some(0 as *libc::FILE);
+ }
+ },
+ _ => ()
+ }
+ }
+ }
+
+ /**
+ * Closes the handle to stdin, waits for the child process to terminate,
+ * and returns the exit code.
+ *
+ * If the child has already been finished then the exit code is returned.
+ */
+ pub fn finish(&mut self) -> int {
+ for &code in self.exit_code.iter() {
+ return code;
+ }
+ self.close_input();
+ let code = waitpid(self.pid);
+ self.exit_code = Some(code);
+ return code;
+ }
+ /**
+ * Closes the handle to stdin, waits for the child process to terminate, and reads
+ * and returns all remaining output of stdout and stderr, along with the exit code.
+ *
+ * If the child has already been finished then the exit code and any remaining
+ * unread output of stdout and stderr will be returned.
+ *
+ * This method will fail if the child process's stdout or stderr streams were
+ * redirected to existing file descriptors.
+ */
+ pub fn finish_with_output(&mut self) -> ProcessOutput {
+ let output_file = self.output_file();
+ let error_file = self.error_file();
+
+ // Spawn two entire schedulers to read both stdout and sterr
+ // in parallel so we don't deadlock while blocking on one
+ // or the other. FIXME (#2625): Surely there's a much more
+ // clever way to do this.
let (p, ch) = stream();
let ch = SharedChan::new(ch);
let ch_clone = ch.clone();
-
- let stderr = Cell::new(self.error.take().unwrap());
- do task::spawn {
- let output = read_everything(stderr.take());
- ch.send((2, output));
+ do task::spawn_sched(task::SingleThreaded) {
+ let errput = io::FILE_reader(error_file, false);
+ ch.send((2, errput.read_whole_stream()));
}
- let stdout = Cell::new(self.output.take().unwrap());
- do task::spawn {
- let output = read_everything(stdout.take());
- ch_clone.send((1, output));
+ do task::spawn_sched(task::SingleThreaded) {
+ let output = io::FILE_reader(output_file, false);
+ ch_clone.send((1, output.read_whole_stream()));
}
let status = self.finish();
error: errs};
}
+ fn destroy_internal(&mut self, force: bool) {
+ // if the process has finished, and therefore had waitpid called,
+ // and we kill it, then on unix we might ending up killing a
+ // newer process that happens to have the same (re-used) id
+ if self.exit_code.is_none() {
+ killpid(self.pid, force);
+ self.finish();
+ }
+
+ #[cfg(windows)]
+ fn killpid(pid: pid_t, _force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe {
+ libc::funcs::extra::kernel32::TerminateProcess(
+ cast::transmute(pid), 1);
+ }
+ }
+
+ #[cfg(unix)]
+ fn killpid(pid: pid_t, force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ let signal = if force {
+ libc::consts::os::posix88::SIGKILL
+ } else {
+ libc::consts::os::posix88::SIGTERM
+ };
+
+ unsafe {
+ libc::funcs::posix88::signal::kill(pid, signal as c_int);
+ }
+ }
+ }
+
/**
* Terminates the process, giving it a chance to clean itself up if
* this is supported by the operating system.
* On Posix OSs SIGTERM will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
- pub fn destroy(&mut self) {
- #[cfg(windows)] fn sigterm() -> int { 15 }
- #[cfg(not(windows))] fn sigterm() -> int { libc::SIGTERM as int }
- self.handle.kill(sigterm());
- self.finish();
- }
+ pub fn destroy(&mut self) { self.destroy_internal(false); }
/**
* Terminates the process as soon as possible without giving it a
* On Posix OSs SIGKILL will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
- pub fn force_destroy(&mut self) {
- #[cfg(windows)] fn sigkill() -> int { 9 }
- #[cfg(not(windows))] fn sigkill() -> int { libc::SIGKILL as int }
- self.handle.kill(sigkill());
- self.finish();
- }
+ pub fn force_destroy(&mut self) { self.destroy_internal(true); }
}
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();
+ free_handle(self.handle);
+ }
+}
+
+struct SpawnProcessResult {
+ pid: pid_t,
+ handle: *(),
+}
+
+#[cfg(windows)]
+fn spawn_process_os(prog: &str, args: &[~str],
+ env: Option<~[(~str, ~str)]>,
+ dir: Option<&Path>,
+ in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
+ use libc::consts::os::extra::{
+ TRUE, FALSE,
+ STARTF_USESTDHANDLES,
+ INVALID_HANDLE_VALUE,
+ DUPLICATE_SAME_ACCESS
+ };
+ use libc::funcs::extra::kernel32::{
+ GetCurrentProcess,
+ DuplicateHandle,
+ CloseHandle,
+ CreateProcessA
+ };
+ use libc::funcs::extra::msvcrt::get_osfhandle;
+
+ use sys;
+
+ unsafe {
+
+ let mut si = zeroed_startupinfo();
+ si.cb = sys::size_of::<STARTUPINFO>() as DWORD;
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ let cur_proc = GetCurrentProcess();
+
+ let orig_std_in = get_osfhandle(in_fd) as HANDLE;
+ if orig_std_in == INVALID_HANDLE_VALUE as HANDLE {
+ fail!("failure in get_osfhandle: %s", os::last_os_error());
+ }
+ if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!("failure in DuplicateHandle: %s", os::last_os_error());
+ }
+
+ let orig_std_out = get_osfhandle(out_fd) as HANDLE;
+ if orig_std_out == INVALID_HANDLE_VALUE as HANDLE {
+ fail!("failure in get_osfhandle: %s", os::last_os_error());
+ }
+ if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!("failure in DuplicateHandle: %s", os::last_os_error());
+ }
+
+ let orig_std_err = get_osfhandle(err_fd) as HANDLE;
+ if orig_std_err == INVALID_HANDLE_VALUE as HANDLE {
+ fail!("failure in get_osfhandle: %s", os::last_os_error());
+ }
+ if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE {
+ fail!("failure in DuplicateHandle: %s", os::last_os_error());
+ }
+
+ let cmd = make_command_line(prog, args);
+ let mut pi = zeroed_process_information();
+ let mut create_err = None;
+
+ do with_envp(env) |envp| {
+ do with_dirp(dir) |dirp| {
+ do cmd.with_c_str |cmdp| {
+ let created = CreateProcessA(ptr::null(), cast::transmute(cmdp),
+ ptr::mut_null(), ptr::mut_null(), TRUE,
+ 0, envp, dirp, &mut si, &mut pi);
+ if created == FALSE {
+ create_err = Some(os::last_os_error());
+ }
+ }
+ }
+ }
+
+ CloseHandle(si.hStdInput);
+ CloseHandle(si.hStdOutput);
+ CloseHandle(si.hStdError);
+
+ for msg in create_err.iter() {
+ fail!("failure in CreateProcess: %s", *msg);
+ }
+
+ // We close the thread handle because we don't care about keeping the thread id valid,
+ // and we aren't keeping the thread handle around to be able to close it later. We don't
+ // close the process handle however because we want the process id to stay valid at least
+ // until the calling code closes the process handle.
+ CloseHandle(pi.hThread);
+
+ SpawnProcessResult {
+ pid: pi.dwProcessId as pid_t,
+ handle: pi.hProcess as *()
+ }
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO {
+ libc::types::os::arch::extra::STARTUPINFO {
+ cb: 0,
+ lpReserved: ptr::mut_null(),
+ lpDesktop: ptr::mut_null(),
+ lpTitle: ptr::mut_null(),
+ dwX: 0,
+ dwY: 0,
+ dwXSize: 0,
+ dwYSize: 0,
+ dwXCountChars: 0,
+ dwYCountCharts: 0,
+ dwFillAttribute: 0,
+ dwFlags: 0,
+ wShowWindow: 0,
+ cbReserved2: 0,
+ lpReserved2: ptr::mut_null(),
+ hStdInput: ptr::mut_null(),
+ hStdOutput: ptr::mut_null(),
+ hStdError: ptr::mut_null()
+ }
+}
+
+#[cfg(windows)]
+fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION {
+ libc::types::os::arch::extra::PROCESS_INFORMATION {
+ hProcess: ptr::mut_null(),
+ hThread: ptr::mut_null(),
+ dwProcessId: 0,
+ dwThreadId: 0
+ }
+}
+
+// FIXME: this is only pub so it can be tested (see issue #4536)
+#[cfg(windows)]
+pub fn make_command_line(prog: &str, args: &[~str]) -> ~str {
+ let mut cmd = ~"";
+ append_arg(&mut cmd, prog);
+ for arg in args.iter() {
+ cmd.push_char(' ');
+ append_arg(&mut cmd, *arg);
+ }
+ return cmd;
+
+ fn append_arg(cmd: &mut ~str, arg: &str) {
+ let quote = arg.iter().any(|c| c == ' ' || c == '\t');
+ if quote {
+ cmd.push_char('"');
+ }
+ for i in range(0u, arg.len()) {
+ append_char_at(cmd, arg, i);
+ }
+ if quote {
+ cmd.push_char('"');
+ }
+ }
+
+ fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) {
+ match arg[i] as char {
+ '"' => {
+ // Escape quotes.
+ cmd.push_str("\\\"");
+ }
+ '\\' => {
+ if backslash_run_ends_in_quote(arg, i) {
+ // Double all backslashes that are in runs before quotes.
+ cmd.push_str("\\\\");
+ } else {
+ // Pass other backslashes through unescaped.
+ cmd.push_char('\\');
+ }
+ }
+ c => {
+ cmd.push_char(c);
+ }
+ }
+ }
+
+ fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool {
+ while i < s.len() && s[i] as char == '\\' {
+ i += 1;
+ }
+ return i < s.len() && s[i] as char == '"';
+ }
+}
+
+#[cfg(unix)]
+fn spawn_process_os(prog: &str, args: &[~str],
+ env: Option<~[(~str, ~str)]>,
+ dir: Option<&Path>,
+ in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
+ 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);
+ }
+ }
+
+ unsafe {
+
+ let pid = fork();
+ if pid < 0 {
+ fail!("failure in fork: %s", os::last_os_error());
+ } else if pid > 0 {
+ return SpawnProcessResult {pid: pid, handle: ptr::null()};
+ }
+
+ rustrt::rust_unset_sigprocmask();
+
+ if dup2(in_fd, 0) == -1 {
+ fail!("failure in dup2(in_fd, 0): %s", os::last_os_error());
+ }
+ if dup2(out_fd, 1) == -1 {
+ fail!("failure in dup2(out_fd, 1): %s", os::last_os_error());
+ }
+ if dup2(err_fd, 2) == -1 {
+ fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
+ }
+ // close all other fds
+ for fd in range(3, getdtablesize()).invert() {
+ close(fd as c_int);
+ }
+
+ do with_dirp(dir) |dirp| {
+ if !dirp.is_null() && chdir(dirp) == -1 {
+ fail!("failure in chdir: %s", os::last_os_error());
+ }
+ }
+
+ do with_envp(env) |envp| {
+ if !envp.is_null() {
+ rustrt::rust_set_environ(envp);
+ }
+ do with_argv(prog, args) |argv| {
+ execvp(*argv, argv);
+ // execvp only returns if an error occurred
+ fail!("failure in execvp: %s", os::last_os_error());
+ }
+ }
+ }
+}
+
+#[cfg(unix)]
+fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
+ use vec;
+
+ // We can't directly convert `str`s into `*char`s, as someone needs to hold
+ // a reference to the intermediary byte buffers. So first build an array to
+ // hold all the ~[u8] byte strings.
+ let mut tmps = vec::with_capacity(args.len() + 1);
+
+ tmps.push(prog.to_c_str());
+
+ for arg in args.iter() {
+ tmps.push(arg.to_c_str());
+ }
+
+ // Next, convert each of the byte strings into a pointer. This is
+ // technically unsafe as the caller could leak these pointers out of our
+ // scope.
+ let mut ptrs = do tmps.map |tmp| {
+ tmp.with_ref(|buf| buf)
+ };
+
+ // Finally, make sure we add a null pointer.
+ ptrs.push(ptr::null());
+
+ ptrs.as_imm_buf(|buf, _| cb(buf))
+}
+
+#[cfg(unix)]
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
+ use vec;
+
+ // On posixy systems we can pass a char** for envp, which is a
+ // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
+ // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
+ match env {
+ Some(env) => {
+ 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());
+ }
+
+ // Once again, this is unsafe.
+ let mut ptrs = do tmps.map |tmp| {
+ tmp.with_ref(|buf| buf)
+ };
+ ptrs.push(ptr::null());
+
+ do ptrs.as_imm_buf |buf, _| {
+ unsafe { cb(cast::transmute(buf)) }
+ }
+ }
+ _ => cb(ptr::null())
+ }
+}
+
+#[cfg(windows)]
+fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
+ // On win32 we pass an "environment block" which is not a char**, but
+ // rather a concatenation of null-terminated k=v\0 sequences, with a final
+ // \0 to terminate.
+ match env {
+ Some(env) => {
+ let mut blk = ~[];
+
+ for pair in env.iter() {
+ let kv = fmt!("%s=%s", pair.first(), pair.second());
+ blk.push_all(kv.as_bytes());
+ blk.push(0);
+ }
+
+ blk.push(0);
+
+ do blk.as_imm_buf |p, _len| {
+ unsafe { cb(cast::transmute(p)) }
+ }
+ }
+ _ => cb(ptr::mut_null())
+ }
+}
+
+fn with_dirp<T>(d: Option<&Path>, cb: &fn(*libc::c_char) -> T) -> T {
+ match d {
+ Some(dir) => dir.with_c_str(|buf| cb(buf)),
+ None => cb(ptr::null())
+ }
+}
+
+#[cfg(windows)]
+fn free_handle(handle: *()) {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe {
+ libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
}
+#[cfg(unix)]
+fn free_handle(_handle: *()) {
+ // unix has no process handle object, just a pid
+}
+
/**
* Spawns a process and waits for it to terminate. The process will
* inherit the current stdin/stdout/stderr file descriptors.
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- }).unwrap();
+ });
prog.finish()
}
* The process's stdout/stderr output and exit code.
*/
pub fn process_output(prog: &str, args: &[~str]) -> ProcessOutput {
- let mut prog = Process::new(prog, args, ProcessOptions::new()).unwrap();
+ let mut prog = Process::new(prog, args, ProcessOptions::new());
prog.finish_with_output()
}
+/**
+ * Waits for a process to exit and returns the exit code, failing
+ * if there is no process with the specified id.
+ *
+ * Note that this is private to avoid race conditions on unix where if
+ * a user calls waitpid(some_process.get_id()) then some_process.finish()
+ * and some_process.destroy() and some_process.finalize() will then either
+ * operate on a none-existent process or, even worse, on a newer process
+ * with the same id.
+ */
+fn waitpid(pid: pid_t) -> int {
+ return waitpid_os(pid);
+
+ #[cfg(windows)]
+ fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ use libc::types::os::arch::extra::DWORD;
+ use libc::consts::os::extra::{
+ SYNCHRONIZE,
+ PROCESS_QUERY_INFORMATION,
+ FALSE,
+ STILL_ACTIVE,
+ INFINITE,
+ WAIT_FAILED
+ };
+ use libc::funcs::extra::kernel32::{
+ OpenProcess,
+ GetExitCodeProcess,
+ CloseHandle,
+ WaitForSingleObject
+ };
+
+ unsafe {
+
+ let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD);
+ if proc.is_null() {
+ fail!("failure in OpenProcess: %s", os::last_os_error());
+ }
+
+ loop {
+ let mut status = 0;
+ if GetExitCodeProcess(proc, &mut status) == FALSE {
+ CloseHandle(proc);
+ fail!("failure in GetExitCodeProcess: %s", os::last_os_error());
+ }
+ if status != STILL_ACTIVE {
+ CloseHandle(proc);
+ return status as int;
+ }
+ if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED {
+ CloseHandle(proc);
+ fail!("failure in WaitForSingleObject: %s", os::last_os_error());
+ }
+ }
+ }
+ }
+
+ #[cfg(unix)]
+ fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ use libc::funcs::posix01::wait::*;
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_os = "android")]
+ fn WIFEXITED(status: i32) -> bool {
+ (status & 0xffi32) == 0i32
+ }
+
+ #[cfg(target_os = "macos")]
+ #[cfg(target_os = "freebsd")]
+ fn WIFEXITED(status: i32) -> bool {
+ (status & 0x7fi32) == 0i32
+ }
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_os = "android")]
+ fn WEXITSTATUS(status: i32) -> i32 {
+ (status >> 8i32) & 0xffi32
+ }
+
+ #[cfg(target_os = "macos")]
+ #[cfg(target_os = "freebsd")]
+ fn WEXITSTATUS(status: i32) -> i32 {
+ status >> 8i32
+ }
+
+ let mut status = 0 as c_int;
+ if unsafe { waitpid(pid, &mut status, 0) } == -1 {
+ fail!("failure in waitpid: %s", os::last_os_error());
+ }
+
+ return if WIFEXITED(status) {
+ WEXITSTATUS(status) as int
+ } else {
+ 1
+ };
+ }
+}
+
#[cfg(test)]
mod tests {
+ use io;
+ use libc::c_int;
+ use option::{Option, None, Some};
use os;
use path::Path;
- use prelude::*;
+ use run;
use str;
- use super::*;
use unstable::running_on_valgrind;
+ #[test]
+ #[cfg(windows)]
+ fn test_make_command_line() {
+ assert_eq!(
+ run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]),
+ ~"prog aaa bbb ccc"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]),
+ ~"\"C:\\Program Files\\blah\\blah.exe\" aaa"
+ );
+ assert_eq!(
+ run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]),
+ ~"\"C:\\Program Files\\test\" aa\\\"bb"
+ );
+ assert_eq!(
+ run::make_command_line("echo", [~"a b c"]),
+ ~"echo \"a b c\""
+ );
+ }
+
#[test]
#[cfg(not(target_os="android"))]
fn test_process_status() {
- assert_eq!(process_status("false", []), 1);
- assert_eq!(process_status("true", []), 0);
+ assert_eq!(run::process_status("false", []), 1);
+ assert_eq!(run::process_status("true", []), 0);
}
#[test]
#[cfg(target_os="android")]
fn test_process_status() {
- assert_eq!(process_status("/system/bin/sh", [~"-c",~"false"]), 1);
- assert_eq!(process_status("/system/bin/sh", [~"-c",~"true"]), 0);
+ assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"false"]), 1);
+ assert_eq!(run::process_status("/system/bin/sh", [~"-c",~"true"]), 0);
}
#[test]
#[cfg(not(target_os="android"))]
fn test_process_output_output() {
- let ProcessOutput {status, output, error}
- = process_output("echo", [~"hello"]);
+ let run::ProcessOutput {status, output, error}
+ = run::process_output("echo", [~"hello"]);
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
#[cfg(target_os="android")]
fn test_process_output_output() {
- let ProcessOutput {status, output, error}
- = process_output("/system/bin/sh", [~"-c",~"echo hello"]);
+ let run::ProcessOutput {status, output, error}
+ = run::process_output("/system/bin/sh", [~"-c",~"echo hello"]);
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
#[cfg(not(target_os="android"))]
fn test_process_output_error() {
- let ProcessOutput {status, output, error}
- = process_output("mkdir", [~"."]);
+ let run::ProcessOutput {status, output, error}
+ = run::process_output("mkdir", [~"."]);
assert_eq!(status, 1);
assert_eq!(output, ~[]);
#[cfg(target_os="android")]
fn test_process_output_error() {
- let ProcessOutput {status, output, error}
- = process_output("/system/bin/mkdir", [~"."]);
+ let run::ProcessOutput {status, output, error}
+ = run::process_output("/system/bin/mkdir", [~"."]);
assert_eq!(status, 255);
assert_eq!(output, ~[]);
assert!(!error.is_empty());
}
+ #[test]
+ fn test_pipes() {
+
+ let pipe_in = os::pipe();
+ let pipe_out = os::pipe();
+ let pipe_err = os::pipe();
+
+ let mut proc = run::Process::new("cat", [], run::ProcessOptions {
+ dir: None,
+ env: None,
+ in_fd: Some(pipe_in.input),
+ out_fd: Some(pipe_out.out),
+ err_fd: Some(pipe_err.out)
+ });
+
+ assert!(proc.input_redirected());
+ assert!(proc.output_redirected());
+ assert!(proc.error_redirected());
+
+ os::close(pipe_in.input);
+ os::close(pipe_out.out);
+ os::close(pipe_err.out);
+
+ let expected = ~"test";
+ writeclose(pipe_in.out, expected);
+ let actual = readclose(pipe_out.input);
+ readclose(pipe_err.input);
+ proc.finish();
+
+ assert_eq!(expected, actual);
+ }
+
+ fn writeclose(fd: c_int, s: &str) {
+ let writer = io::fd_writer(fd, false);
+ writer.write_str(s);
+ os::close(fd);
+ }
+
+ fn readclose(fd: c_int) -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe {
+ let file = os::fdopen(fd);
+ let reader = io::FILE_reader(file, false);
+ let buf = reader.read_whole_stream();
+ os::fclose(file);
+ str::from_bytes(buf)
+ }
+ }
+
#[test]
#[cfg(not(target_os="android"))]
fn test_finish_once() {
- let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
+ let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(target_os="android")]
fn test_finish_once() {
- let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
- ProcessOptions::new()).unwrap();
+ let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
+ run::ProcessOptions::new());
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(not(target_os="android"))]
fn test_finish_twice() {
- let mut prog = Process::new("false", [], ProcessOptions::new()).unwrap();
+ let mut prog = run::Process::new("false", [], run::ProcessOptions::new());
assert_eq!(prog.finish(), 1);
assert_eq!(prog.finish(), 1);
}
#[test]
#[cfg(target_os="android")]
fn test_finish_twice() {
- let mut prog = Process::new("/system/bin/sh", [~"-c",~"false"],
- ProcessOptions::new()).unwrap();
+ let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"false"],
+ run::ProcessOptions::new());
assert_eq!(prog.finish(), 1);
assert_eq!(prog.finish(), 1);
}
#[cfg(not(target_os="android"))]
fn test_finish_with_output_once() {
- let prog = Process::new("echo", [~"hello"], ProcessOptions::new());
- let mut prog = prog.unwrap();
- let ProcessOutput {status, output, error}
+ let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+ let run::ProcessOutput {status, output, error}
= prog.finish_with_output();
let output_str = str::from_bytes(output);
#[cfg(target_os="android")]
fn test_finish_with_output_once() {
- let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
- ProcessOptions::new()).unwrap();
- let ProcessOutput {status, output, error}
+ let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+ run::ProcessOptions::new());
+ let run::ProcessOutput {status, output, error}
+ = prog.finish_with_output();
+ let output_str = str::from_bytes(output);
+
+ assert_eq!(status, 0);
+ assert_eq!(output_str.trim().to_owned(), ~"hello");
+ // FIXME #7224
+ if !running_on_valgrind() {
+ assert_eq!(error, ~[]);
+ }
+ }
+
+ #[test]
+ #[cfg(not(target_os="android"))]
+ fn test_finish_with_output_twice() {
+
+ let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new());
+ let run::ProcessOutput {status, output, error}
= prog.finish_with_output();
+
let output_str = str::from_bytes(output);
assert_eq!(status, 0);
if !running_on_valgrind() {
assert_eq!(error, ~[]);
}
+
+ let run::ProcessOutput {status, output, error}
+ = prog.finish_with_output();
+
+ assert_eq!(status, 0);
+ assert_eq!(output, ~[]);
+ // FIXME #7224
+ if !running_on_valgrind() {
+ assert_eq!(error, ~[]);
+ }
+ }
+ #[test]
+ #[cfg(target_os="android")]
+ fn test_finish_with_output_twice() {
+
+ let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+ run::ProcessOptions::new());
+ let run::ProcessOutput {status, output, error}
+ = prog.finish_with_output();
+
+ let output_str = str::from_bytes(output);
+
+ assert_eq!(status, 0);
+ assert_eq!(output_str.trim().to_owned(), ~"hello");
+ // FIXME #7224
+ if !running_on_valgrind() {
+ assert_eq!(error, ~[]);
+ }
+
+ let run::ProcessOutput {status, output, error}
+ = prog.finish_with_output();
+
+ assert_eq!(status, 0);
+ assert_eq!(output, ~[]);
+ // FIXME #7224
+ if !running_on_valgrind() {
+ assert_eq!(error, ~[]);
+ }
}
#[test]
#[should_fail]
#[cfg(not(windows),not(target_os="android"))]
fn test_finish_with_output_redirected() {
- let mut prog = Process::new("echo", [~"hello"], ProcessOptions {
+ let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions {
env: None,
dir: None,
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- }).unwrap();
- // this should fail because it is not valid to read the output when it
- // was redirected
+ });
+ // this should fail because it is not valid to read the output when it was redirected
prog.finish_with_output();
}
#[test]
#[should_fail]
#[cfg(not(windows),target_os="android")]
fn test_finish_with_output_redirected() {
- let mut prog = Process::new("/system/bin/sh", [~"-c",~"echo hello"],
- ProcessOptions {
+ let mut prog = run::Process::new("/system/bin/sh", [~"-c",~"echo hello"],
+ run::ProcessOptions {
env: None,
dir: None,
in_fd: Some(0),
out_fd: Some(1),
err_fd: Some(2)
- }).unwrap();
- // this should fail because it is not valid to read the output when it
- // was redirected
+ });
+ // this should fail because it is not valid to read the output when it was redirected
prog.finish_with_output();
}
#[cfg(unix,not(target_os="android"))]
- fn run_pwd(dir: Option<&Path>) -> Process {
- Process::new("pwd", [], ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> run::Process {
+ run::Process::new("pwd", [], run::ProcessOptions {
dir: dir,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[cfg(unix,target_os="android")]
- fn run_pwd(dir: Option<&Path>) -> Process {
- Process::new("/system/bin/sh", [~"-c",~"pwd"], ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> run::Process {
+ run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
dir: dir,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[cfg(windows)]
- fn run_pwd(dir: Option<&Path>) -> Process {
- Process::new("cmd", [~"/c", ~"cd"], ProcessOptions {
+ fn run_pwd(dir: Option<&Path>) -> run::Process {
+ run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
dir: dir,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[test]
}
#[cfg(unix,not(target_os="android"))]
- fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
- Process::new("env", [], ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+ run::Process::new("env", [], run::ProcessOptions {
env: env,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[cfg(unix,target_os="android")]
- fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
- Process::new("/system/bin/sh", [~"-c",~"set"], ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+ run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
env: env,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[cfg(windows)]
- fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
- Process::new("cmd", [~"/c", ~"set"], ProcessOptions {
+ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
+ run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
env: env,
- .. ProcessOptions::new()
- }).unwrap()
+ .. run::ProcessOptions::new()
+ })
}
#[test]
#[test]
fn test_add_to_env() {
+
let mut new_env = os::env();
new_env.push((~"RUN_TEST_NEW_ENV", ~"123"));
mod test {
use super::*;
use clone::Clone;
- use iter::Times;
+ use num::Times;
use option::*;
use rt::comm::*;
use rt::test::*;
pub mod from_str;
#[path = "num/num.rs"]
pub mod num;
-pub mod iter;
pub mod iterator;
pub mod to_str;
pub mod to_bytes;
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;
pub use fmt;
pub use to_bytes;
}
-
use char::Char;
use clone::{Clone, DeepClone};
use container::{Container, Mutable};
-use iter::Times;
+use num::Times;
use iterator::{Iterator, FromIterator, Extendable};
use iterator::{Filter, AdditiveIterator, Map};
use iterator::{Invert, DoubleEndedIterator};
#[deriving(Clone)]
struct NormalizationIterator<'self> {
priv kind: NormalizationForm,
- priv index: uint,
- priv string: &'self str,
+ priv iter: CharIterator<'self>,
priv buffer: ~[(char, u8)],
priv sorted: bool
}
NFKD => char::decompose_compatible
};
- while !self.sorted && self.index < self.string.len() {
- let CharRange {ch, next} = self.string.char_range_at(self.index);
- self.index = next;
- do decomposer(ch) |d| {
- let class = canonical_combining_class(d);
- if class == 0 && !self.sorted {
- canonical_sort(self.buffer);
- self.sorted = true;
+ if !self.sorted {
+ for ch in self.iter {
+ do decomposer(ch) |d| {
+ let class = canonical_combining_class(d);
+ if class == 0 && !self.sorted {
+ canonical_sort(self.buffer);
+ self.sorted = true;
+ }
+ self.buffer.push((d, class));
}
- self.buffer.push((d, class));
+ if self.sorted { break }
}
}
}
}
- fn size_hint(&self) -> (uint, Option<uint>) { (self.string.len(), None) }
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let (lower, _) = self.iter.size_hint();
+ (lower, None)
+ }
}
/// Replace all occurrences of one string with another
}
}
-/// As char_len but for a slice of a string
-///
-/// # Arguments
-///
-/// * s - A valid string
-/// * start - The position inside `s` where to start counting in bytes
-/// * end - The position where to stop counting
-///
-/// # Return value
-///
-/// The number of Unicode characters in `s` between the given indices.
-pub fn count_chars(s: &str, start: uint, end: uint) -> uint {
- assert!(s.is_char_boundary(start));
- assert!(s.is_char_boundary(end));
- let mut i = start;
- let mut len = 0u;
- while i < end {
- let next = s.char_range_at(i).next;
- len += 1u;
- i = next;
- }
- return len;
-}
-
-/// Counts the number of bytes taken by the first `n` chars in `s`
-/// starting from `start`.
-pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint {
- assert!(s.is_char_boundary(start));
- let mut end = start;
- let mut cnt = n;
- let l = s.len();
- while cnt > 0u {
- assert!(end < l);
- let next = s.char_range_at(end).next;
- cnt -= 1u;
- end = next;
- }
- end - start
-}
-
// https://tools.ietf.org/html/rfc3629
static UTF8_CHAR_WIDTH: [u8, ..256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
fn eq(&self, other: &~str) -> bool {
eq_slice((*self), (*other))
}
- #[inline]
- fn ne(&self, other: &~str) -> bool { !(*self).eq(other) }
}
impl Eq for @str {
fn eq(&self, other: &@str) -> bool {
eq_slice((*self), (*other))
}
- #[inline]
- fn ne(&self, other: &@str) -> bool { !(*self).eq(other) }
}
impl<'self> TotalEq for &'self str {
/// Returns the string in Unicode Normalization Form D (canonical decomposition)
fn nfd_iter(&self) -> NormalizationIterator<'self> {
NormalizationIterator {
- index: 0,
- string: *self,
+ iter: self.iter(),
buffer: ~[],
sorted: false,
kind: NFD
/// Returns the string in Unicode Normalization Form KD (compatibility decomposition)
fn nfkd_iter(&self) -> NormalizationIterator<'self> {
NormalizationIterator {
- index: 0,
- string: *self,
+ iter: self.iter(),
buffer: ~[],
sorted: false,
kind: NFKD
if count == end { end_byte = Some(idx); break; }
count += 1;
}
+ if begin_byte.is_none() && count == begin { begin_byte = Some(self.len()) }
if end_byte.is_none() && count == end { end_byte = Some(self.len()) }
match (begin_byte, end_byte) {
fn t(a: &str, b: &str, start: uint) {
assert_eq!(a.slice_chars(start, start + b.char_len()), b);
}
+ t("", "", 0);
t("hello", "llo", 2);
t("hello", "el", 1);
+ t("αβλ", "β", 1);
+ t("αβλ", "", 3);
assert_eq!("ะเทศไท", "ประเทศไทย中华Việt Nam".slice_chars(2, 8));
}
use c_str::ToCStr;
use cast;
+#[cfg(stage0)]
use io;
use libc;
use libc::{c_char, size_t};
}
}
+#[cfg(not(stage0))]
pub fn log_str<T>(t: &T) -> ~str {
- do io::with_str_writer |wr| {
- repr::write_repr(wr, t)
+ use rt::io;
+ use rt::io::Decorator;
+
+ let mut result = io::mem::MemWriter::new();
+ repr::write_repr(&mut result as &mut io::Writer, t);
+ str::from_bytes_owned(result.inner())
+}
+#[cfg(stage0)]
+pub fn log_str<T>(t: &T) -> ~str {
+ do io::with_str_writer |w| {
+ repr::write_repr(w, t)
}
}
use libc;
#[test]
+ #[ignore(cfg(windows))] // FIXME #8818
fn test_loading_cosine() {
// The math library does not need to be loaded since it is already
// statically linked in
pub enum Opaque { }
#[lang="ty_visitor"]
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
pub trait TyVisitor {
fn visit_bot(&self) -> bool;
fn visit_nil(&self) -> bool;
fn visit_closure_ptr(&self, ck: uint) -> bool;
}
+#[lang="ty_visitor"]
+#[cfg(not(test), not(stage0))]
+pub trait TyVisitor {
+ fn visit_bot(&mut self) -> bool;
+ fn visit_nil(&mut self) -> bool;
+ fn visit_bool(&mut self) -> bool;
+
+ fn visit_int(&mut self) -> bool;
+ fn visit_i8(&mut self) -> bool;
+ fn visit_i16(&mut self) -> bool;
+ fn visit_i32(&mut self) -> bool;
+ fn visit_i64(&mut self) -> bool;
+
+ fn visit_uint(&mut self) -> bool;
+ fn visit_u8(&mut self) -> bool;
+ fn visit_u16(&mut self) -> bool;
+ fn visit_u32(&mut self) -> bool;
+ fn visit_u64(&mut self) -> bool;
+
+ fn visit_float(&mut self) -> bool;
+ fn visit_f32(&mut self) -> bool;
+ fn visit_f64(&mut self) -> bool;
+
+ fn visit_char(&mut self) -> bool;
+
+ fn visit_estr_box(&mut self) -> bool;
+ fn visit_estr_uniq(&mut self) -> bool;
+ fn visit_estr_slice(&mut self) -> bool;
+ fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool;
+
+ fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_ptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+
+ fn visit_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_evec_uniq_managed(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
+ mtbl: uint, inner: *TyDesc) -> bool;
+
+ fn visit_enter_rec(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+ fn visit_rec_field(&mut self, i: uint, name: &str,
+ mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_leave_rec(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+
+ fn visit_enter_class(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+ fn visit_class_field(&mut self, i: uint, name: &str,
+ mtbl: uint, inner: *TyDesc) -> bool;
+ fn visit_leave_class(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+
+ fn visit_enter_tup(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+ fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool;
+ fn visit_leave_tup(&mut self, n_fields: uint,
+ sz: uint, align: uint) -> bool;
+
+ fn visit_enter_enum(&mut self, n_variants: uint,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ sz: uint, align: uint) -> bool;
+ fn visit_enter_enum_variant(&mut self, variant: uint,
+ disr_val: int,
+ n_fields: uint,
+ name: &str) -> bool;
+ fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool;
+ fn visit_leave_enum_variant(&mut self, variant: uint,
+ disr_val: int,
+ n_fields: uint,
+ name: &str) -> bool;
+ fn visit_leave_enum(&mut self, n_variants: uint,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ sz: uint, align: uint) -> bool;
+
+ fn visit_enter_fn(&mut self, purity: uint, proto: uint,
+ n_inputs: uint, retstyle: uint) -> bool;
+ fn visit_fn_input(&mut self, i: uint, mode: uint, inner: *TyDesc) -> bool;
+ fn visit_fn_output(&mut self, retstyle: uint, inner: *TyDesc) -> bool;
+ fn visit_leave_fn(&mut self, purity: uint, proto: uint,
+ n_inputs: uint, retstyle: uint) -> bool;
+
+ fn visit_trait(&mut self) -> bool;
+ fn visit_param(&mut self, i: uint) -> bool;
+ fn visit_self(&mut self) -> bool;
+ fn visit_type(&mut self) -> bool;
+ fn visit_opaque_box(&mut self) -> bool;
+ fn visit_closure_ptr(&mut self, ck: uint) -> bool;
+}
+
#[abi = "rust-intrinsic"]
extern "rust-intrinsic" {
/// 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));
/// An atomically reference counted pointer.
///
/// Enforces no shared-memory safety.
+#[unsafe_no_drop_flag]
pub struct UnsafeArc<T> {
data: *mut ArcData<T>,
}
impl<T> Drop for UnsafeArc<T>{
fn drop(&self) {
unsafe {
+ // Happens when destructing an unwrapper's handle and from `#[unsafe_no_drop_flag]`
if self.data.is_null() {
- return; // Happens when destructing an unwrapper's handle.
+ return
}
let mut data: ~ArcData<T> = cast::transmute(self.data);
// Must be acquire+release, not just release, to make sure this
use super::{Exclusive, UnsafeArc, atomically};
use task;
use util;
+ use sys::size_of;
+
+ #[test]
+ fn test_size() {
+ assert_eq!(size_of::<UnsafeArc<[int, ..10]>>(), size_of::<*[int, ..10]>());
+ }
#[test]
fn test_atomically() {
use parse::token::{str_to_ident};
use util::parser_testing::{string_to_tts_and_sess, string_to_parser};
use util::parser_testing::{string_to_expr, string_to_item};
- use util::parser_testing::{string_to_stmt, strs_to_idents};
+ use util::parser_testing::string_to_stmt;
// map a string to tts, return the tt without its parsesess
fn string_to_tts_only(source_str : @str) -> ~[ast::token_tree] {
-Subproject commit ef2bcd134164adcaa072dcb56e62b737fdcb075e
+Subproject commit dfae9c3e958dc086d9c0ab068cd76d196c95a433
-Subproject commit 0964c68ddf2c67ce455e7443a06f4bb3db9e92bb
+Subproject commit 08a3bd96ee6e1d141494f0014ede75d9871114c4
return buf.len;
}
+extern "C" uv_err_t
+rust_uv_last_error(uv_loop_t* loop) {
+ return uv_last_error(loop);
+}
+
extern "C" const char*
-rust_uv_strerror(int err) {
+rust_uv_strerror(uv_err_t* err_ptr) {
+ uv_err_t err = *err_ptr;
return uv_strerror(err);
}
extern "C" const char*
-rust_uv_err_name(int err) {
+rust_uv_err_name(uv_err_t* err_ptr) {
+ uv_err_t err = *err_ptr;
return uv_err_name(err);
}
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
return req->loop;
}
-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_uv_timer_stop
rust_uv_tcp_init
rust_uv_buf_init
+rust_uv_last_error
rust_uv_strerror
rust_uv_err_name
rust_uv_ip4_addr
rust_take_change_dir_lock
rust_drop_change_dir_lock
rust_get_test_int
-rust_get_task
-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
+rust_get_task
\ No newline at end of file
}
TargetOptions Options;
+ Options.NoFramePointerElim = true;
Options.EnableSegmentedStacks = EnableSegmentedStacks;
Options.FixedStackSegmentSize = 2 * 1024 * 1024; // XXX: This is too big.
Options.FloatABIType =
}
extern "C" void
-LLVMRustSetLLVMOptions(bool PrintPasses,
- bool VectorizeLoops,
- bool VectorizeSLP,
- bool TimePasses) {
+LLVMRustSetLLVMOptions(int Argc, char **Argv) {
// Initializing the command-line options more than once is not allowed. So,
// check if they've already been initialized. (This could happen if we're
// being called from rustpkg, for example). If the arguments change, then
// that's just kinda unfortunate.
static bool initialized = false;
if (initialized) return;
-
- int argc = 3;
- const char *argv[20] = {"rustc",
- "-arm-enable-ehabi",
- "-arm-enable-ehabi-descriptors"};
- if (PrintPasses) {
- argv[argc++] = "-debug-pass";
- argv[argc++] = "Structure";
- }
- if (VectorizeLoops) {
- argv[argc++] = "-vectorize-loops";
- }
- if (VectorizeSLP) {
- argv[argc++] = "-vectorize-slp";
- }
- if (TimePasses) {
- argv[argc++] = "-time-passes";
- }
- cl::ParseCommandLineOptions(argc, argv);
initialized = true;
+ cl::ParseCommandLineOptions(Argc, Argv);
}
extern "C" bool
std::string Err;
TargetOptions Options;
Options.JITEmitDebugInfo = true;
+ Options.NoFramePointerElim = true;
Options.EnableSegmentedStacks = EnableSegmentedStacks;
RustMCJITMemoryManager* MM = (RustMCJITMemoryManager*) mem;
assert(MM);
--- /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.
+
+// original problem
+fn foo<T>() -> int {
+ {
+ static foo: int = 2;
+ foo
+ }
+}
+
+// issue 8134
+struct Foo;
+impl<T> Foo {
+ pub fn foo(&self) {
+ static X: uint = 1;
+ }
+}
+
+// issue 8134
+pub struct Parser<T>;
+impl<T: std::iterator::Iterator<char>> Parser<T> {
+ fn in_doctype(&mut self) {
+ static DOCTYPEPattern: [char, ..6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
+ }
+}
+
+struct Bar;
+impl<T> Foo {
+ pub fn bar(&self) {
+ static X: uint = 1;
+ }
+}
use std::os;
use std::result::{Ok, Err};
use std::task;
-use std::u64;
use std::uint;
fn fib(n: int) -> int {
--- /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.
+
+#[deny(unused_imports)];
+
+mod A {
+ pub fn p() {}
+}
+mod B {
+ pub fn p() {}
+}
+
+mod C {
+ pub fn q() {}
+}
+mod D {
+ pub fn q() {}
+}
+
+mod E {
+ pub fn r() {}
+}
+mod F {
+ pub fn r() {}
+}
+
+mod G {
+ pub fn s() {}
+ pub fn t() {}
+}
+mod H {
+ pub fn s() {}
+}
+
+mod I {
+ pub fn u() {}
+ pub fn v() {}
+}
+mod J {
+ pub fn u() {}
+ pub fn v() {}
+}
+
+mod K {
+ pub fn w() {}
+}
+mod L {
+ pub fn w() {}
+}
+
+mod m {
+ use A::p; //~ ERROR: unused import
+ use B::p;
+ use C::q; //~ ERROR: unused import
+ use D::*;
+ use E::*; //~ ERROR: unused import
+ use F::r;
+ use G::*;
+ use H::*;
+ use I::*;
+ use J::v;
+ use K::*; //~ ERROR: unused import
+ use L::*;
+
+ #[main]
+ fn my_main() {
+ p();
+ q();
+ r();
+ s();
+ t();
+ u();
+ v();
+ w();
+ }
+}
+
--- /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.
+
+// This checks that RUST_TEST_TASKS not being 1, 2, ... is detected
+// properly.
+
+// error-pattern:should be a positive integer
+// compile-flags: --test
+// exec-env:RUST_TEST_TASKS=foo
+
+#[test]
+fn do_nothing() {}
extern mod cci_const;
use cci_const::bar;
-use std::cast::transmute;
static foo: extern "C" fn() = bar;
pub fn main() {
- unsafe {
- assert_eq!(foo, bar);
- }
+ assert_eq!(foo, bar);
}
}
pub fn main() {
- unsafe {
- assert_eq!(foopy, f);
- assert_eq!(f, s.f);
- }
+ assert_eq!(foopy, f);
+ assert_eq!(f, s.f);
}
#[test]
fn test_destroy_once() {
- let p = run::Process::new("echo", [], run::ProcessOptions::new());
- let mut p = p.unwrap();
+ let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
p.destroy(); // this shouldn't crash (and nor should the destructor)
}
#[test]
fn test_destroy_twice() {
- let p = run::Process::new("echo", [], run::ProcessOptions::new());
- let mut p = p.unwrap();
+ let mut p = run::Process::new("echo", [], run::ProcessOptions::new());
p.destroy(); // this shouldnt crash...
p.destroy(); // ...and nor should this (and nor should the destructor)
}
}
// this process will stay alive indefinitely trying to read from stdin
- let p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
- let mut p = p.unwrap();
+ let mut p = run::Process::new(BLOCK_COMMAND, [], run::ProcessOptions::new());
assert!(process_exists(p.get_id()));
extern fn uintret() -> uint { 22 }
-extern fn uintvoidret(x: uint) {}
+extern fn uintvoidret(_x: uint) {}
extern fn uintuintuintuintret(x: uint, y: uint, z: uint) -> uint { x+y+z }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::cast::transmute;
-
extern fn f() {
}
}
pub fn main() {
- unsafe {
- let a: extern "C" fn() = f;
- let b: extern "C" fn() = f;
- let c: extern "C" fn() = g;
+ let a: extern "C" fn() = f;
+ let b: extern "C" fn() = f;
+ let c: extern "C" fn() = g;
- assert_eq!(a, b);
- assert!(a != c);
- }
+ assert_eq!(a, b);
+ assert!(a != c);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::io;
-
struct T (&'static [int]);
static t : T = T (&'static [5, 4, 3]);
fn main () {
// xfail-fast
-use std::int;
-
trait vec_monad<A> {
fn bind<B>(&self, f: &fn(&A) -> ~[B]) -> ~[B];
}
--- /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:nested_item.rs
+// xfail-fast
+
+extern mod nested_item;
+
+pub fn main() {
+ assert_eq!(2, nested_item::foo::<()>());
+ assert_eq!(2, nested_item::foo::<int>());
+}
// xfail-fast
-use std::int;
use std::libc::c_void;
use std::ptr;
use std::sys;
/// Trait for visitor that wishes to reflect on data.
trait movable_ptr {
- fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void);
+ fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void);
}
/// Helper function for alignment calculation.
impl<V:TyVisitor + movable_ptr> ptr_visit_adaptor<V> {
#[inline(always)]
- pub fn bump(&self, sz: uint) {
+ pub fn bump(&mut self, sz: uint) {
do self.inner.move_ptr() |p| {
((p as uint) + sz) as *c_void
};
}
#[inline(always)]
- pub fn align(&self, a: uint) {
+ pub fn align(&mut self, a: uint) {
do self.inner.move_ptr() |p| {
align(p as uint, a) as *c_void
};
}
#[inline(always)]
- pub fn align_to<T>(&self) {
+ pub fn align_to<T>(&mut self) {
self.align(sys::min_align_of::<T>());
}
#[inline(always)]
- pub fn bump_past<T>(&self) {
+ pub fn bump_past<T>(&mut self) {
self.bump(sys::size_of::<T>());
}
impl<V:TyVisitor + movable_ptr> TyVisitor for ptr_visit_adaptor<V> {
- fn visit_bot(&self) -> bool {
+ fn visit_bot(&mut self) -> bool {
self.align_to::<()>();
if ! self.inner.visit_bot() { return false; }
self.bump_past::<()>();
true
}
- fn visit_nil(&self) -> bool {
+ fn visit_nil(&mut self) -> bool {
self.align_to::<()>();
if ! self.inner.visit_nil() { return false; }
self.bump_past::<()>();
true
}
- fn visit_bool(&self) -> bool {
+ fn visit_bool(&mut self) -> bool {
self.align_to::<bool>();
if ! self.inner.visit_bool() { return false; }
self.bump_past::<bool>();
true
}
- fn visit_int(&self) -> bool {
+ fn visit_int(&mut self) -> bool {
self.align_to::<int>();
if ! self.inner.visit_int() { return false; }
self.bump_past::<int>();
true
}
- fn visit_i8(&self) -> bool {
+ fn visit_i8(&mut self) -> bool {
self.align_to::<i8>();
if ! self.inner.visit_i8() { return false; }
self.bump_past::<i8>();
true
}
- fn visit_i16(&self) -> bool {
+ fn visit_i16(&mut self) -> bool {
self.align_to::<i16>();
if ! self.inner.visit_i16() { return false; }
self.bump_past::<i16>();
true
}
- fn visit_i32(&self) -> bool {
+ fn visit_i32(&mut self) -> bool {
self.align_to::<i32>();
if ! self.inner.visit_i32() { return false; }
self.bump_past::<i32>();
true
}
- fn visit_i64(&self) -> bool {
+ fn visit_i64(&mut self) -> bool {
self.align_to::<i64>();
if ! self.inner.visit_i64() { return false; }
self.bump_past::<i64>();
true
}
- fn visit_uint(&self) -> bool {
+ fn visit_uint(&mut self) -> bool {
self.align_to::<uint>();
if ! self.inner.visit_uint() { return false; }
self.bump_past::<uint>();
true
}
- fn visit_u8(&self) -> bool {
+ fn visit_u8(&mut self) -> bool {
self.align_to::<u8>();
if ! self.inner.visit_u8() { return false; }
self.bump_past::<u8>();
true
}
- fn visit_u16(&self) -> bool {
+ fn visit_u16(&mut self) -> bool {
self.align_to::<u16>();
if ! self.inner.visit_u16() { return false; }
self.bump_past::<u16>();
true
}
- fn visit_u32(&self) -> bool {
+ fn visit_u32(&mut self) -> bool {
self.align_to::<u32>();
if ! self.inner.visit_u32() { return false; }
self.bump_past::<u32>();
true
}
- fn visit_u64(&self) -> bool {
+ fn visit_u64(&mut self) -> bool {
self.align_to::<u64>();
if ! self.inner.visit_u64() { return false; }
self.bump_past::<u64>();
true
}
- fn visit_float(&self) -> bool {
+ fn visit_float(&mut self) -> bool {
self.align_to::<float>();
if ! self.inner.visit_float() { return false; }
self.bump_past::<float>();
true
}
- fn visit_f32(&self) -> bool {
+ fn visit_f32(&mut self) -> bool {
self.align_to::<f32>();
if ! self.inner.visit_f32() { return false; }
self.bump_past::<f32>();
true
}
- fn visit_f64(&self) -> bool {
+ fn visit_f64(&mut self) -> bool {
self.align_to::<f64>();
if ! self.inner.visit_f64() { return false; }
self.bump_past::<f64>();
true
}
- fn visit_char(&self) -> bool {
+ fn visit_char(&mut self) -> bool {
self.align_to::<char>();
if ! self.inner.visit_char() { return false; }
self.bump_past::<char>();
true
}
- fn visit_estr_box(&self) -> bool {
+ fn visit_estr_box(&mut 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 {
+ fn visit_estr_uniq(&mut 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 {
+ fn visit_estr_slice(&mut 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,
+ fn visit_estr_fixed(&mut self, n: uint,
sz: uint,
align: uint) -> bool {
self.align(align);
true
}
- fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_box(&mut 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 {
+ fn visit_uniq(&mut 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 {
+ fn visit_uniq_managed(&mut 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 {
+ fn visit_ptr(&mut 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 {
+ fn visit_rptr(&mut 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 {
+ fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<Vec<()>>();
// FIXME (#3732): Inner really has to move its own pointers on this one.
// or else possibly we could have some weird interface wherein we
true
}
- fn visit_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_vec(&mut 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 {
+ fn visit_evec_box(&mut 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 {
+ fn visit_evec_uniq(&mut 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 {
+ fn visit_evec_uniq_managed(&mut 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 {
+ fn visit_evec_slice(&mut 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,
+ fn visit_evec_fixed(&mut 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) {
true
}
- fn visit_enter_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+ fn visit_enter_rec(&mut 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,
+ fn visit_rec_field(&mut self, i: uint, name: &str,
mtbl: uint, inner: *TyDesc) -> bool {
if ! self.inner.visit_rec_field(i, name, mtbl, inner) { return false; }
true
}
- fn visit_leave_rec(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+ fn visit_leave_rec(&mut 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)
+ fn visit_enter_class(&mut self, n_fields: uint, sz: uint, align: uint)
-> bool {
self.align(align);
if ! self.inner.visit_enter_class(n_fields, sz, align) {
true
}
- fn visit_class_field(&self, i: uint, name: &str,
+ fn visit_class_field(&mut self, i: uint, name: &str,
mtbl: uint, inner: *TyDesc) -> bool {
if ! self.inner.visit_class_field(i, name, mtbl, inner) {
return false;
true
}
- fn visit_leave_class(&self, n_fields: uint, sz: uint, align: uint)
+ fn visit_leave_class(&mut 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 {
+ fn visit_enter_tup(&mut 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 {
+ fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
if ! self.inner.visit_tup_field(i, inner) { return false; }
true
}
- fn visit_leave_tup(&self, n_fields: uint, sz: uint, align: uint) -> bool {
+ fn visit_leave_tup(&mut 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,
+ fn visit_enter_fn(&mut 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 {
+ fn visit_fn_input(&mut 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 {
+ fn visit_fn_output(&mut 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,
+ fn visit_leave_fn(&mut 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,
+ fn visit_enter_enum(&mut self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
true
}
- fn visit_enter_enum_variant(&self, variant: uint,
+ fn visit_enter_enum_variant(&mut self, variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
true
}
- fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool {
+ fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool {
if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; }
true
}
- fn visit_leave_enum_variant(&self, variant: uint,
+ fn visit_leave_enum_variant(&mut self, variant: uint,
disr_val: int,
n_fields: uint,
name: &str) -> bool {
true
}
- fn visit_leave_enum(&self, n_variants: uint,
+ fn visit_leave_enum(&mut self, n_variants: uint,
get_disr: extern unsafe fn(ptr: *Opaque) -> int,
sz: uint, align: uint)
-> bool {
true
}
- fn visit_trait(&self) -> bool {
+ fn visit_trait(&mut 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 {
+ fn visit_param(&mut self, i: uint) -> bool {
if ! self.inner.visit_param(i) { return false; }
true
}
- fn visit_self(&self) -> bool {
+ fn visit_self(&mut 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 {
+ fn visit_type(&mut self) -> bool {
if ! self.inner.visit_type() { return false; }
true
}
- fn visit_opaque_box(&self) -> bool {
+ fn visit_opaque_box(&mut 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 {
+ fn visit_closure_ptr(&mut self, ck: uint) -> bool {
self.align_to::<@fn()>();
if ! self.inner.visit_closure_ptr(ck) { return false; }
self.bump_past::<@fn()>();
}
impl my_visitor {
- pub fn get<T:Clone>(&self, f: &fn(T)) {
+ pub fn get<T:Clone>(&mut self, f: &fn(T)) {
unsafe {
f((*(self.ptr1 as *T)).clone());
}
}
- pub fn visit_inner(&self, inner: *TyDesc) -> bool {
+ pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
unsafe {
let u = my_visitor(**self);
- let v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
- visit_tydesc(inner, &v as &TyVisitor);
+ let mut v = ptr_visit_adaptor::<my_visitor>(Inner {inner: u});
+ visit_tydesc(inner, &mut v as &mut TyVisitor);
true
}
}
struct Inner<V> { inner: V }
impl movable_ptr for my_visitor {
- fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
+ fn move_ptr(&mut self, adjustment: &fn(*c_void) -> *c_void) {
self.ptr1 = adjustment(self.ptr1);
self.ptr2 = adjustment(self.ptr2);
}
impl TyVisitor for my_visitor {
- fn visit_bot(&self) -> bool { true }
- fn visit_nil(&self) -> bool { true }
- fn visit_bool(&self) -> bool {
+ fn visit_bot(&mut self) -> bool { true }
+ fn visit_nil(&mut self) -> bool { true }
+ fn visit_bool(&mut self) -> bool {
do self.get::<bool>() |b| {
self.vals.push(b.to_str());
};
true
}
- fn visit_int(&self) -> bool {
+ fn visit_int(&mut self) -> bool {
do self.get::<int>() |i| {
self.vals.push(i.to_str());
};
true
}
- fn visit_i8(&self) -> bool { true }
- fn visit_i16(&self) -> bool { true }
- fn visit_i32(&self) -> bool { true }
- fn visit_i64(&self) -> bool { true }
+ fn visit_i8(&mut self) -> bool { true }
+ fn visit_i16(&mut self) -> bool { true }
+ fn visit_i32(&mut self) -> bool { true }
+ fn visit_i64(&mut self) -> bool { true }
- fn visit_uint(&self) -> bool { true }
- fn visit_u8(&self) -> bool { true }
- fn visit_u16(&self) -> bool { true }
- fn visit_u32(&self) -> bool { true }
- fn visit_u64(&self) -> bool { true }
+ fn visit_uint(&mut self) -> bool { true }
+ fn visit_u8(&mut self) -> bool { true }
+ fn visit_u16(&mut self) -> bool { true }
+ fn visit_u32(&mut self) -> bool { true }
+ fn visit_u64(&mut self) -> bool { true }
- fn visit_float(&self) -> bool { true }
- fn visit_f32(&self) -> bool { true }
- fn visit_f64(&self) -> bool { true }
+ fn visit_float(&mut self) -> bool { true }
+ fn visit_f32(&mut self) -> bool { true }
+ fn visit_f64(&mut self) -> bool { true }
- fn visit_char(&self) -> bool { true }
+ fn visit_char(&mut self) -> bool { true }
- fn visit_estr_box(&self) -> bool { true }
- fn visit_estr_uniq(&self) -> bool { true }
- fn visit_estr_slice(&self) -> bool { true }
- fn visit_estr_fixed(&self, _n: uint, _sz: uint,
+ fn visit_estr_box(&mut self) -> bool { true }
+ fn visit_estr_uniq(&mut self) -> bool { true }
+ fn visit_estr_slice(&mut self) -> bool { true }
+ fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
_align: uint) -> bool { true }
- fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
-
- fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint,
+ fn visit_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+
+ fn visit_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_unboxed_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
_mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_enter_rec(&self, _n_fields: uint,
+ fn visit_enter_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_rec_field(&self, _i: uint, _name: &str,
+ fn visit_rec_field(&mut self, _i: uint, _name: &str,
_mtbl: uint, inner: *TyDesc) -> bool {
error!("rec field!");
self.visit_inner(inner)
}
- fn visit_leave_rec(&self, _n_fields: uint,
+ fn visit_leave_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_class(&self, _n_fields: uint,
+ fn visit_enter_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_class_field(&self, _i: uint, _name: &str,
+ fn visit_class_field(&mut self, _i: uint, _name: &str,
_mtbl: uint, inner: *TyDesc) -> bool {
self.visit_inner(inner)
}
- fn visit_leave_class(&self, _n_fields: uint,
+ fn visit_leave_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_tup(&self, _n_fields: uint,
+ fn visit_enter_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_tup_field(&self, _i: uint, inner: *TyDesc) -> bool {
+ fn visit_tup_field(&mut self, _i: uint, inner: *TyDesc) -> bool {
error!("tup field!");
self.visit_inner(inner)
}
- fn visit_leave_tup(&self, _n_fields: uint,
+ fn visit_leave_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_enum(&self, _n_variants: uint,
+ fn visit_enter_enum(&mut self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool {
// FIXME (#3732): this needs to rewind between enum variants, or something.
true
}
- fn visit_enter_enum_variant(&self, _variant: uint,
+ fn visit_enter_enum_variant(&mut self, _variant: uint,
_disr_val: int,
_n_fields: uint,
_name: &str) -> bool { true }
- fn visit_enum_variant_field(&self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
+ fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
self.visit_inner(inner)
}
- fn visit_leave_enum_variant(&self, _variant: uint,
+ fn visit_leave_enum_variant(&mut self, _variant: uint,
_disr_val: int,
_n_fields: uint,
_name: &str) -> bool { true }
- fn visit_leave_enum(&self, _n_variants: uint,
+ fn visit_leave_enum(&mut self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+ fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
_n_inputs: uint, _retstyle: uint) -> bool { true }
- fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
+ fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
true
}
- fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
+ fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool {
true
}
- fn visit_leave_fn(&self, _purity: uint, _proto: uint,
+ fn visit_leave_fn(&mut 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 { true }
- fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+ fn visit_trait(&mut self) -> bool { true }
+ fn visit_param(&mut self, _i: uint) -> bool { true }
+ fn visit_self(&mut self) -> bool { true }
+ fn visit_type(&mut self) -> bool { true }
+ fn visit_opaque_box(&mut self) -> bool { true }
+ fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
fn get_tydesc_for<T>(_t: T) -> *TyDesc {
let u = my_visitor(@mut Stuff {ptr1: p,
ptr2: p,
vals: ~[]});
- let v = ptr_visit_adaptor(Inner {inner: u});
+ let mut v = ptr_visit_adaptor(Inner {inner: u});
let td = get_tydesc_for(r);
error!("tydesc sz: %u, align: %u",
(*td).size, (*td).align);
- let v = &v as &TyVisitor;
- visit_tydesc(td, v);
+ visit_tydesc(td, &mut v as &mut TyVisitor);
let r = u.vals.clone();
for s in r.iter() {
}
impl TyVisitor for MyVisitor {
- fn visit_bot(&self) -> bool {
+ fn visit_bot(&mut self) -> bool {
self.types.push(~"bot");
error!("visited bot type");
true
}
- fn visit_nil(&self) -> bool {
+ fn visit_nil(&mut self) -> bool {
self.types.push(~"nil");
error!("visited nil type");
true
}
- fn visit_bool(&self) -> bool {
+ fn visit_bool(&mut self) -> bool {
self.types.push(~"bool");
error!("visited bool type");
true
}
- fn visit_int(&self) -> bool {
+ fn visit_int(&mut self) -> bool {
self.types.push(~"int");
error!("visited int type");
true
}
- fn visit_i8(&self) -> bool {
+ fn visit_i8(&mut self) -> bool {
self.types.push(~"i8");
error!("visited i8 type");
true
}
- fn visit_i16(&self) -> bool {
+ fn visit_i16(&mut self) -> bool {
self.types.push(~"i16");
error!("visited i16 type");
true
}
- fn visit_i32(&self) -> bool { true }
- fn visit_i64(&self) -> bool { true }
+ fn visit_i32(&mut self) -> bool { true }
+ fn visit_i64(&mut self) -> bool { true }
- fn visit_uint(&self) -> bool { true }
- fn visit_u8(&self) -> bool { true }
- fn visit_u16(&self) -> bool { true }
- fn visit_u32(&self) -> bool { true }
- fn visit_u64(&self) -> bool { true }
+ fn visit_uint(&mut self) -> bool { true }
+ fn visit_u8(&mut self) -> bool { true }
+ fn visit_u16(&mut self) -> bool { true }
+ fn visit_u32(&mut self) -> bool { true }
+ fn visit_u64(&mut self) -> bool { true }
- fn visit_float(&self) -> bool { true }
- fn visit_f32(&self) -> bool { true }
- fn visit_f64(&self) -> bool { true }
+ fn visit_float(&mut self) -> bool { true }
+ fn visit_f32(&mut self) -> bool { true }
+ fn visit_f64(&mut self) -> bool { true }
- fn visit_char(&self) -> bool { true }
+ fn visit_char(&mut self) -> bool { true }
- fn visit_estr_box(&self) -> bool { true }
- fn visit_estr_uniq(&self) -> bool { true }
- fn visit_estr_slice(&self) -> bool { true }
- fn visit_estr_fixed(&self,
+ fn visit_estr_box(&mut self) -> bool { true }
+ fn visit_estr_uniq(&mut self) -> bool { true }
+ fn visit_estr_slice(&mut self) -> bool { true }
+ fn visit_estr_fixed(&mut self,
_sz: uint, _sz: uint,
_align: uint) -> bool { true }
- fn visit_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_uniq(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_uniq_managed(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_rptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_uniq(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_uniq_managed(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_ptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_rptr(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_unboxed_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_box(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_unboxed_vec(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_box(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
self.types.push(~"[");
- unsafe {
- visit_tydesc(inner, (&*self) as &TyVisitor);
- }
+ unsafe { visit_tydesc(inner, &mut *self as &mut TyVisitor); }
self.types.push(~"]");
true
}
- fn visit_evec_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
+ fn visit_evec_uniq_managed(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
self.types.push(~"[");
- unsafe {
- visit_tydesc(inner, (&*self) as &TyVisitor);
- }
+ unsafe { visit_tydesc(inner, &mut *self as &mut TyVisitor) };
self.types.push(~"]");
true
}
- fn visit_evec_slice(&self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_evec_fixed(&self, _n: uint, _sz: uint, _align: uint,
+ fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint,
_mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_enter_rec(&self, _n_fields: uint,
+ fn visit_enter_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_rec_field(&self, _i: uint, _name: &str,
+ fn visit_rec_field(&mut self, _i: uint, _name: &str,
_mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_leave_rec(&self, _n_fields: uint,
+ fn visit_leave_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_class(&self, _n_fields: uint,
+ fn visit_enter_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_class_field(&self, _i: uint, _name: &str,
+ fn visit_class_field(&mut self, _i: uint, _name: &str,
_mtbl: uint, _inner: *TyDesc) -> bool { true }
- fn visit_leave_class(&self, _n_fields: uint,
+ fn visit_leave_class(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_tup(&self, _n_fields: uint,
+ fn visit_enter_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_tup_field(&self, _i: uint, _inner: *TyDesc) -> bool { true }
- fn visit_leave_tup(&self, _n_fields: uint,
+ fn visit_tup_field(&mut self, _i: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_leave_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_enum(&self, _n_variants: uint,
+ fn visit_enter_enum(&mut self, _n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_enum_variant(&self,
+ fn visit_enter_enum_variant(&mut self,
_variant: uint,
_disr_val: int,
_n_fields: uint,
_name: &str) -> bool { true }
- fn visit_enum_variant_field(&self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true }
- fn visit_leave_enum_variant(&self,
+ fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_leave_enum_variant(&mut self,
_variant: uint,
_disr_val: int,
_n_fields: uint,
_name: &str) -> bool { true }
- fn visit_leave_enum(&self,
+ fn visit_leave_enum(&mut self,
_n_variants: uint,
_get_disr: extern unsafe fn(ptr: *Opaque) -> int,
_sz: uint, _align: uint) -> bool { true }
- fn visit_enter_fn(&self, _purity: uint, _proto: uint,
+ fn visit_enter_fn(&mut 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,
+ fn visit_fn_input(&mut self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_fn_output(&mut self, _retstyle: uint, _inner: *TyDesc) -> bool { true }
+ fn visit_leave_fn(&mut 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 { true }
- fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
+ fn visit_trait(&mut self) -> bool { true }
+ fn visit_param(&mut self, _i: uint) -> bool { true }
+ fn visit_self(&mut self) -> bool { true }
+ fn visit_type(&mut self) -> bool { true }
+ fn visit_opaque_box(&mut self) -> bool { true }
+ fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
-fn visit_ty<T>(v: &TyVisitor) {
- unsafe {
- visit_tydesc(get_tydesc::<T>(), v);
- }
+fn visit_ty<T>(v: &mut MyVisitor) {
+ unsafe { visit_tydesc(get_tydesc::<T>(), v as &mut TyVisitor) }
}
pub fn main() {
- let v = @MyVisitor {types: @mut ~[]};
- let vv = v as @TyVisitor;
-
- visit_ty::<bool>(vv);
- visit_ty::<int>(vv);
- visit_ty::<i8>(vv);
- visit_ty::<i16>(vv);
- visit_ty::<~[int]>(vv);
+ let mut v = MyVisitor {types: @mut ~[]};
+
+ visit_ty::<bool>(&mut v);
+ visit_ty::<int>(&mut v);
+ visit_ty::<i8>(&mut v);
+ visit_ty::<i16>(&mut v);
+ visit_ty::<~[int]>(&mut v);
for s in v.types.iter() {
printfln!("type: %s", (*s).clone());
--- /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.
+
+// This test can't be a unit test in std,
+// because it needs mkdtemp, which is in extra
+
+// xfail-fast
+extern mod extra;
+
+use extra::tempfile::mkdtemp;
+use std::os;
+use std::libc;
+use std::libc::*;
+
+fn rename_directory() {
+ #[fixed_stack_segment];
+ unsafe {
+ static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
+
+ let tmpdir = mkdtemp(&os::tmpdir(), "rename_directory").expect("rename_directory failed");
+ let old_path = tmpdir.push_many(["foo", "bar", "baz"]);
+ assert!(os::mkdir_recursive(&old_path, U_RWX));
+ let test_file = &old_path.push("temp.txt");
+
+ /* Write the temp input file */
+ let ostream = do test_file.to_str().with_c_str |fromp| {
+ do "w+b".with_c_str |modebuf| {
+ libc::fopen(fromp, modebuf)
+ }
+ };
+ assert!((ostream as uint != 0u));
+ let s = ~"hello";
+ do "hello".with_c_str |buf| {
+ let write_len = libc::fwrite(buf as *c_void,
+ 1u as size_t,
+ (s.len() + 1u) as size_t,
+ ostream);
+ assert_eq!(write_len, (s.len() + 1) as size_t)
+ }
+ assert_eq!(libc::fclose(ostream), (0u as c_int));
+
+ let new_path = tmpdir.push_many(["quux", "blat"]);
+ assert!(os::mkdir_recursive(&new_path, U_RWX));
+ assert!(os::rename_file(&old_path, &new_path.push("newdir")));
+ assert!(os::path_is_dir(&new_path.push("newdir")));
+ assert!(os::path_exists(&new_path.push_many(["newdir", "temp.txt"])));
+ }
+}
+
+fn main() { rename_directory() }
// xfail-fast
-use std::uint;
-
pub trait plus {
fn plus(&self) -> int;
}
// xfail-fast
-use std::int;
-
trait to_str {
fn to_string(&self) -> ~str;
}