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
}
~~~
-By default, the scheduler multiplexes tasks across the available cores, running
-in parallel. Thus, on a multicore machine, running the following code
-should interleave the output in vaguely random order.
-
-~~~
-# use std::io::print;
-# use std::task::spawn;
-
-for child_task_number in range(0, 20) {
- do spawn {
- print(fmt!("I am child number %d\n", child_task_number));
- }
-}
-~~~
-
## Communication
Now that we have spawned a new task, it would be nice if we could
$$(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
SNAP_DEFINES=-DRUST_SNAPSHOT
endif
+define DEF_LIBUV_ARCH_VAR
+ LIBUV_ARCH_$(1) = $$(subst i386,ia32,$$(subst x86_64,x64,$$(HOST_$(1))))
+endef
+$(foreach t,$(CFG_TARGET_TRIPLES),$(eval $(call DEF_LIBUV_ARCH_VAR,$(t))))
+
define DEF_RUNTIME_TARGETS
######################################################################
$$(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=$$(HOST_$(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))))))
syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained
" reserved
-syn keyword rustKeyword be
+syn keyword rustKeyword be yield typeof
syn keyword rustType int uint float char bool u8 u16 u32 u64 f32
syn keyword rustType f64 i8 i16 i32 i64 str Self
}
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]
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(
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) => {
&ccx.int_type);
// FIXME #4404 android JNI hacks
- let llfn = if *ccx.sess.building_library {
- decl_cdecl_fn(ccx.llmod, "amain", llfty)
+ let main_name = if *ccx.sess.building_library {
+ "amain"
} else {
- let main_name = match ccx.sess.targ_cfg.os {
- session::os_win32 => {
- match ccx.sess.targ_cfg.arch {
- X86 => ~"WinMain@16",
- _ => ~"WinMain",
- }
- },
- _ => ~"main",
- };
- decl_cdecl_fn(ccx.llmod, main_name, llfty)
+ "main"
};
+ let llfn = decl_cdecl_fn(ccx.llmod, main_name, llfty);
let llbb = do "top".with_c_str |buf| {
unsafe {
llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
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);
}
}
}
"visit_tydesc" | "forget" | "frame_address" |
"morestack_addr" => 0,
- "offset" | "offset_inbounds" |
+ "offset" |
"memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
"memset32" | "memset64" => use_repr,
trait_ref.def_id,
trait_ref.substs.clone(),
RegionTraitStore(region),
- ast::m_imm,
+ ast::m_mutbl,
EmptyBuiltinBounds())))
}
}
}
}
+ ast::ty_typeof(_e) => {
+ tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+ }
ast::ty_infer => {
// ty_infer should only appear as the type of arguments or return
// values in a fn_expr, or as the type of local variables. Both of
mutbl: ast::m_imm
}))
}
- "offset_inbounds" => {
- (1,
- ~[
- ty::mk_ptr(tcx, ty::mt {
- ty: param(ccx, 0),
- mutbl: ast::m_imm
- }),
- ty::mk_int()
- ],
- ty::mk_ptr(tcx, ty::mt {
- ty: param(ccx, 0),
- mutbl: ast::m_imm
- }))
- }
"memcpy32" => {
(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);
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 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),
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",
do cs.with_mut_ref |buf| {
for i in range(0, self.len()) {
unsafe {
- let p = buf.offset_inbounds(i as int);
+ let p = buf.offset(i as int);
if *p == 0 {
match null_byte::cond.raise(self.to_owned()) {
Truncate => break,
if ch == 0 {
None
} else {
- self.ptr = ptr::offset(self.ptr, 1);
+ self.ptr = unsafe { ptr::offset(self.ptr, 1) };
Some(ch)
}
}
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());
-}
-
*/
+use cast;
+use libc;
use prelude::*;
-
-use task::local_data_priv::*;
-
-#[cfg(test)] use task;
+use rt::task::{Task, LocalStorage};
+use util;
/**
* Indexes a task-local data slot. This pointer is used for comparison to
pub enum KeyValue<T> { Key }
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
- unsafe { local_pop(Handle::new(), key) }
-}
-
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
- unsafe { local_get(Handle::new(), key, f) }
-}
+trait LocalData {}
+impl<T: 'static> LocalData for T {}
-/**
- * Retrieve a mutable borrowed pointer to a task-local data value.
- */
-pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
- unsafe { local_get_mut(Handle::new(), key, f) }
+// The task-local-map stores all TLS information for the currently running task.
+// It is stored as an owned pointer into the runtime, and it's only allocated
+// when TLS is used for the first time. This map must be very carefully
+// constructed because it has many mutable loans unsoundly handed out on it to
+// the various invocations of TLS requests.
+//
+// One of the most important operations is loaning a value via `get` to a
+// caller. In doing so, the slot that the TLS entry is occupying cannot be
+// invalidated because upon returning it's loan state must be updated. Currently
+// the TLS map is a vector, but this is possibly dangerous because the vector
+// can be reallocated/moved when new values are pushed onto it.
+//
+// This problem currently isn't solved in a very elegant way. Inside the `get`
+// function, it internally "invalidates" all references after the loan is
+// finished and looks up into the vector again. In theory this will prevent
+// pointers from being moved under our feet so long as LLVM doesn't go too crazy
+// with the optimizations.
+//
+// n.b. If TLS is used heavily in future, this could be made more efficient with
+// a proper map.
+#[doc(hidden)]
+pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
+type TLSValue = ~LocalData;
+
+// Gets the map from the runtime. Lazily initialises if not done so already.
+unsafe fn get_local_map() -> &mut Map {
+ use rt::local::Local;
+
+ let task: *mut Task = Local::unsafe_borrow();
+ match &mut (*task).storage {
+ // If the at_exit function is already set, then we just need to take
+ // a loan out on the TLS map stored inside
+ &LocalStorage(Some(ref mut map_ptr)) => {
+ return map_ptr;
+ }
+ // If this is the first time we've accessed TLS, perform similar
+ // actions to the oldsched way of doing things.
+ &LocalStorage(ref mut slot) => {
+ *slot = Some(~[]);
+ match *slot {
+ Some(ref mut map_ptr) => { return map_ptr }
+ None => abort()
+ }
+ }
+ }
}
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-pub fn set<T: 'static>(key: Key<T>, data: T) {
- unsafe { local_set(Handle::new(), key, data) }
+#[deriving(Eq)]
+enum LoanState {
+ NoLoan, ImmLoan, MutLoan
}
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
- unsafe {
- match f(pop(::cast::unsafe_copy(&key))) {
- Some(next) => { set(key, next); }
- None => {}
+impl LoanState {
+ fn describe(&self) -> &'static str {
+ match *self {
+ NoLoan => "no loan",
+ ImmLoan => "immutable",
+ MutLoan => "mutable"
}
}
}
-#[test]
-fn test_tls_multitask() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"parent data");
- do task::spawn {
- // TLS shouldn't carry over.
- assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
- set(my_key, @~"child data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
- ~"child data");
- // should be cleaned up for us
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
+ unsafe { cast::transmute(key) }
+}
+
+/// Removes a task-local value from task-local storage. This will return
+/// Some(value) if the key was present in TLS, otherwise it will return None.
+///
+/// A runtime assertion will be triggered it removal of TLS value is attempted
+/// while the value is still loaned out via `get` or `get_mut`.
+pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
+ let map = unsafe { get_local_map() };
+ let key_value = key_to_key_value(key);
+
+ for entry in map.mut_iter() {
+ match *entry {
+ Some((k, _, loan)) if k == key_value => {
+ if loan != NoLoan {
+ fail!("TLS value cannot be removed because it is currently \
+ borrowed as %s", loan.describe());
+ }
+ // Move the data out of the `entry` slot via util::replace.
+ // This is guaranteed to succeed because we already matched
+ // on `Some` above.
+ let data = match util::replace(entry, None) {
+ Some((_, data, _)) => data,
+ None => abort()
+ };
+
+ // Move `data` into transmute to get out the memory that it
+ // owns, we must free it manually later.
+ let (_vtable, box): (uint, ~~T) = unsafe {
+ cast::transmute(data)
+ };
+
+ // Now that we own `box`, we can just move out of it as we would
+ // with any other data.
+ return Some(**box);
+ }
+ _ => {}
+ }
}
- // Must work multiple times
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ return None;
}
-#[test]
-fn test_tls_overwrite() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"first data");
- set(my_key, @~"next data"); // Shouldn't leak.
- assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+/// Retrieves a value from TLS. The closure provided is yielded `Some` of a
+/// reference to the value located in TLS if one exists, or `None` if the key
+/// provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via the `get_mut` method provided.
+pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
+ get_with(key, ImmLoan, f)
}
-#[test]
-fn test_tls_pop() {
- static my_key: Key<@~str> = &Key;
- set(my_key, @~"weasel");
- assert!(*(pop(my_key).unwrap()) == ~"weasel");
- // Pop must remove the data from the map.
- assert!(pop(my_key).is_none());
+/// Retrieves a mutable value from TLS. The closure provided is yielded `Some`
+/// of a reference to the mutable value located in TLS if one exists, or `None`
+/// if the key provided is not present in TLS currently.
+///
+/// It is considered a runtime error to attempt to get a value which is already
+/// on loan via this or the `get` methods. This is similar to how it's a runtime
+/// error to take two mutable loans on an `@mut` box.
+pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
+ do get_with(key, MutLoan) |x| {
+ match x {
+ None => f(None),
+ // We're violating a lot of compiler guarantees with this
+ // invocation of `transmute_mut`, but we're doing runtime checks to
+ // ensure that it's always valid (only one at a time).
+ //
+ // there is no need to be upset!
+ Some(x) => { f(Some(unsafe { cast::transmute_mut(x) })) }
+ }
+ }
}
-#[test]
-fn test_tls_modify() {
- static my_key: Key<@~str> = &Key;
- modify(my_key, |data| {
- match data {
- Some(@ref val) => fail!("unwelcome value: %s", *val),
- None => Some(@~"first data")
+fn get_with<T: 'static, U>(key: Key<T>,
+ state: LoanState,
+ f: &fn(Option<&T>) -> U) -> U {
+ // This function must be extremely careful. Because TLS can store owned
+ // values, and we must have some form of `get` function other than `pop`,
+ // this function has to give a `&` reference back to the caller.
+ //
+ // One option is to return the reference, but this cannot be sound because
+ // the actual lifetime of the object is not known. The slot in TLS could not
+ // be modified until the object goes out of scope, but the TLS code cannot
+ // know when this happens.
+ //
+ // For this reason, the reference is yielded to a specified closure. This
+ // way the TLS code knows exactly what the lifetime of the yielded pointer
+ // is, allowing callers to acquire references to owned data. This is also
+ // sound so long as measures are taken to ensure that while a TLS slot is
+ // loaned out to a caller, it's not modified recursively.
+ let map = unsafe { get_local_map() };
+ let key_value = key_to_key_value(key);
+
+ let pos = map.iter().position(|entry| {
+ match *entry {
+ Some((k, _, _)) if k == key_value => true, _ => false
}
});
- modify(my_key, |data| {
- match data {
- Some(@~"first data") => Some(@~"next data"),
- Some(@ref val) => fail!("wrong value: %s", *val),
- None => fail!("missing value")
+ match pos {
+ None => { return f(None); }
+ Some(i) => {
+ let ret;
+ let mut return_loan = false;
+ match map[i] {
+ Some((_, ref data, ref mut loan)) => {
+ match (state, *loan) {
+ (_, NoLoan) => {
+ *loan = state;
+ return_loan = true;
+ }
+ (ImmLoan, ImmLoan) => {}
+ (want, cur) => {
+ fail!("TLS slot cannot be borrowed as %s because \
+ it is already borrowed as %s",
+ want.describe(), cur.describe());
+ }
+ }
+ // data was created with `~~T as ~LocalData`, so we extract
+ // pointer part of the trait, (as ~~T), and then use
+ // compiler coercions to achieve a '&' pointer.
+ unsafe {
+ match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data){
+ (_vtable, ref box) => {
+ let value: &T = **box;
+ ret = f(Some(value));
+ }
+ }
+ }
+ }
+ _ => abort()
+ }
+
+ // n.b. 'data' and 'loans' are both invalid pointers at the point
+ // 'f' returned because `f` could have appended more TLS items which
+ // in turn relocated the vector. Hence we do another lookup here to
+ // fixup the loans.
+ if return_loan {
+ match map[i] {
+ Some((_, _, ref mut loan)) => { *loan = NoLoan; }
+ None => abort()
+ }
+ }
+ return ret;
}
- });
- assert!(*(pop(my_key).unwrap()) == ~"next data");
+ }
}
-#[test]
-fn test_tls_crust_automorestack_memorial_bug() {
- // This might result in a stack-canary clobber if the runtime fails to
- // set sp_limit to 0 when calling the cleanup extern - it might
- // automatically jump over to the rust stack, which causes next_c_sp
- // to get recorded as something within a rust stack segment. Then a
- // subsequent upcall (esp. for logging, think vsnprintf) would run on
- // a stack smaller than 1 MB.
- static my_key: Key<@~str> = &Key;
- do task::spawn {
- set(my_key, @~"hax");
- }
+fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::abort() }
}
-#[test]
-fn test_tls_multiple_types() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- do task::spawn {
- set(str_key, @~"string data");
- set(box_key, @@());
- set(int_key, @42);
+/// Inserts a value into task local storage. If the key is already present in
+/// TLS, then the previous value is removed and replaced with the provided data.
+///
+/// It is considered a runtime error to attempt to set a key which is currently
+/// on loan via the `get` or `get_mut` methods.
+pub fn set<T: 'static>(key: Key<T>, data: T) {
+ let map = unsafe { get_local_map() };
+ let keyval = key_to_key_value(key);
+
+ // When the task-local map is destroyed, all the data needs to be cleaned
+ // up. For this reason we can't do some clever tricks to store '~T' as a
+ // '*c_void' or something like that. To solve the problem, we cast
+ // everything to a trait (LocalData) which is then stored inside the map.
+ // Upon destruction of the map, all the objects will be destroyed and the
+ // traits have enough information about them to destroy themselves.
+ //
+ // FIXME(#7673): This should be "~data as ~LocalData" (only one sigil)
+ let data = ~~data as ~LocalData:;
+
+ fn insertion_position(map: &mut Map,
+ key: *libc::c_void) -> Option<uint> {
+ // First see if the map contains this key already
+ let curspot = map.iter().position(|entry| {
+ match *entry {
+ Some((ekey, _, loan)) if key == ekey => {
+ if loan != NoLoan {
+ fail!("TLS value cannot be overwritten because it is
+ already borrowed as %s", loan.describe())
+ }
+ true
+ }
+ _ => false,
+ }
+ });
+ // If it doesn't contain the key, just find a slot that's None
+ match curspot {
+ Some(i) => Some(i),
+ None => map.iter().position(|entry| entry.is_none())
+ }
+ }
+
+ // The type of the local data map must ascribe to Send, so we do the
+ // transmute here to add the Send bound back on. This doesn't actually
+ // matter because TLS will always own the data (until its moved out) and
+ // we're not actually sending it to other schedulers or anything.
+ let data: ~LocalData = unsafe { cast::transmute(data) };
+ match insertion_position(map, keyval) {
+ Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
+ None => { map.push(Some((keyval, data, NoLoan))); }
}
}
-#[test]
-fn test_tls_overwrite_multiple_types() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- do task::spawn {
- set(str_key, @~"string data");
- set(int_key, @42);
- // This could cause a segfault if overwriting-destruction is done
- // with the crazy polymorphic transmute rather than the provided
- // finaliser.
- set(int_key, @31337);
+/// Modifies a task-local value by temporarily removing it from task-local
+/// storage and then re-inserting if `Some` is returned from the closure.
+///
+/// This function will have the same runtime errors as generated from `pop` and
+/// `set` (the key must not currently be on loan
+pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
+ match f(pop(key)) {
+ Some(next) => { set(key, next); }
+ None => {}
}
}
-#[test]
-#[should_fail]
-fn test_tls_cleanup_on_failure() {
- static str_key: Key<@~str> = &Key;
- static box_key: Key<@@()> = &Key;
- static int_key: Key<@int> = &Key;
- set(str_key, @~"parent data");
- set(box_key, @@());
- do task::spawn {
- // spawn_linked
- set(str_key, @~"string data");
+#[cfg(test)]
+mod tests {
+ use prelude::*;
+ use super::*;
+ use task;
+
+ #[test]
+ fn test_tls_multitask() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"parent data");
+ do task::spawn {
+ // TLS shouldn't carry over.
+ assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
+ set(my_key, @~"child data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
+ ~"child data");
+ // should be cleaned up for us
+ }
+ // Must work multiple times
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ }
+
+ #[test]
+ fn test_tls_overwrite() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"first data");
+ set(my_key, @~"next data"); // Shouldn't leak.
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
+ }
+
+ #[test]
+ fn test_tls_pop() {
+ static my_key: Key<@~str> = &Key;
+ set(my_key, @~"weasel");
+ assert!(*(pop(my_key).unwrap()) == ~"weasel");
+ // Pop must remove the data from the map.
+ assert!(pop(my_key).is_none());
+ }
+
+ #[test]
+ fn test_tls_modify() {
+ static my_key: Key<@~str> = &Key;
+ modify(my_key, |data| {
+ match data {
+ Some(@ref val) => fail!("unwelcome value: %s", *val),
+ None => Some(@~"first data")
+ }
+ });
+ modify(my_key, |data| {
+ match data {
+ Some(@~"first data") => Some(@~"next data"),
+ Some(@ref val) => fail!("wrong value: %s", *val),
+ None => fail!("missing value")
+ }
+ });
+ assert!(*(pop(my_key).unwrap()) == ~"next data");
+ }
+
+ #[test]
+ fn test_tls_crust_automorestack_memorial_bug() {
+ // This might result in a stack-canary clobber if the runtime fails to
+ // set sp_limit to 0 when calling the cleanup extern - it might
+ // automatically jump over to the rust stack, which causes next_c_sp
+ // to get recorded as something within a rust stack segment. Then a
+ // subsequent upcall (esp. for logging, think vsnprintf) would run on
+ // a stack smaller than 1 MB.
+ static my_key: Key<@~str> = &Key;
+ do task::spawn {
+ set(my_key, @~"hax");
+ }
+ }
+
+ #[test]
+ fn test_tls_multiple_types() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ do task::spawn {
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
+ }
+ }
+
+ #[test]
+ fn test_tls_overwrite_multiple_types() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ do task::spawn {
+ set(str_key, @~"string data");
+ set(int_key, @42);
+ // This could cause a segfault if overwriting-destruction is done
+ // with the crazy polymorphic transmute rather than the provided
+ // finaliser.
+ set(int_key, @31337);
+ }
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_tls_cleanup_on_failure() {
+ static str_key: Key<@~str> = &Key;
+ static box_key: Key<@@()> = &Key;
+ static int_key: Key<@int> = &Key;
+ set(str_key, @~"parent data");
set(box_key, @@());
- set(int_key, @42);
+ do task::spawn {
+ // spawn_linked
+ set(str_key, @~"string data");
+ set(box_key, @@());
+ set(int_key, @42);
+ fail!();
+ }
+ // Not quite nondeterministic.
+ set(int_key, @31337);
fail!();
}
- // Not quite nondeterministic.
- set(int_key, @31337);
- fail!();
-}
-#[test]
-fn test_static_pointer() {
- static key: Key<@&'static int> = &Key;
- static VALUE: int = 0;
- let v: @&'static int = @&VALUE;
- set(key, v);
-}
+ #[test]
+ fn test_static_pointer() {
+ static key: Key<@&'static int> = &Key;
+ static VALUE: int = 0;
+ let v: @&'static int = @&VALUE;
+ set(key, v);
+ }
-#[test]
-fn test_owned() {
- static key: Key<~int> = &Key;
- set(key, ~1);
+ #[test]
+ fn test_owned() {
+ static key: Key<~int> = &Key;
+ set(key, ~1);
- do get(key) |v| {
do get(key) |v| {
do get(key) |v| {
+ do get(key) |v| {
+ assert_eq!(**v.unwrap(), 1);
+ }
assert_eq!(**v.unwrap(), 1);
}
assert_eq!(**v.unwrap(), 1);
}
- assert_eq!(**v.unwrap(), 1);
- }
- set(key, ~2);
- do get(key) |v| {
- assert_eq!(**v.unwrap(), 2);
+ set(key, ~2);
+ do get(key) |v| {
+ assert_eq!(**v.unwrap(), 2);
+ }
}
-}
-#[test]
-fn test_get_mut() {
- static key: Key<int> = &Key;
- set(key, 1);
+ #[test]
+ fn test_get_mut() {
+ static key: Key<int> = &Key;
+ set(key, 1);
- do get_mut(key) |v| {
- *v.unwrap() = 2;
- }
+ do get_mut(key) |v| {
+ *v.unwrap() = 2;
+ }
- do get(key) |v| {
- assert_eq!(*v.unwrap(), 2);
+ do get(key) |v| {
+ assert_eq!(*v.unwrap(), 2);
+ }
}
-}
-#[test]
-fn test_same_key_type() {
- static key1: Key<int> = &Key;
- static key2: Key<int> = &Key;
- static key3: Key<int> = &Key;
- static key4: Key<int> = &Key;
- static key5: Key<int> = &Key;
- set(key1, 1);
- set(key2, 2);
- set(key3, 3);
- set(key4, 4);
- set(key5, 5);
-
- get(key1, |x| assert_eq!(*x.unwrap(), 1));
- get(key2, |x| assert_eq!(*x.unwrap(), 2));
- get(key3, |x| assert_eq!(*x.unwrap(), 3));
- get(key4, |x| assert_eq!(*x.unwrap(), 4));
- get(key5, |x| assert_eq!(*x.unwrap(), 5));
-}
+ #[test]
+ fn test_same_key_type() {
+ static key1: Key<int> = &Key;
+ static key2: Key<int> = &Key;
+ static key3: Key<int> = &Key;
+ static key4: Key<int> = &Key;
+ static key5: Key<int> = &Key;
+ set(key1, 1);
+ set(key2, 2);
+ set(key3, 3);
+ set(key4, 4);
+ set(key5, 5);
+
+ get(key1, |x| assert_eq!(*x.unwrap(), 1));
+ get(key2, |x| assert_eq!(*x.unwrap(), 2));
+ get(key3, |x| assert_eq!(*x.unwrap(), 3));
+ get(key4, |x| assert_eq!(*x.unwrap(), 4));
+ get(key5, |x| assert_eq!(*x.unwrap(), 5));
+ }
-#[test]
-#[should_fail]
-fn test_nested_get_set1() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get(key) |_| {
+ #[test]
+ #[should_fail]
+ fn test_nested_get_set1() {
+ static key: Key<int> = &Key;
set(key, 4);
+ do get(key) |_| {
+ set(key, 4);
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut2() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get(key) |_| {
- get_mut(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut2() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get(key) |_| {
+ get_mut(key, |_| {})
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut3() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get_mut(key) |_| {
- get(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut3() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get_mut(key) |_| {
+ get(key, |_| {})
+ }
}
-}
-#[test]
-#[should_fail]
-fn test_nested_get_mut4() {
- static key: Key<int> = &Key;
- set(key, 4);
- do get_mut(key) |_| {
- get_mut(key, |_| {})
+ #[test]
+ #[should_fail]
+ fn test_nested_get_mut4() {
+ static key: Key<int> = &Key;
+ set(key, 4);
+ do get_mut(key) |_| {
+ get_mut(key, |_| {})
+ }
}
}
#[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);
}
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();
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();
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();
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>
//! 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; }
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 unstable::intrinsics;
use util::swap;
-#[cfg(not(test))] use ops::{Add,Sub};
-#[cfg(not(test))] use num::Int;
-
#[cfg(not(test))] use cmp::{Eq, Ord};
-/// Calculate the offset from a pointer
+/// Calculate the offset from a pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
#[inline]
#[cfg(stage0)]
-pub fn offset<T>(ptr: *T, count: int) -> *T {
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
(ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
}
/// Calculate the offset from a mut pointer
#[inline]
#[cfg(stage0)]
-pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
(ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
}
/// Calculate the offset from a pointer
#[inline]
#[cfg(not(stage0))]
-pub fn offset<T>(ptr: *T, count: int) -> *T {
- unsafe { intrinsics::offset(ptr, count) }
+pub unsafe fn offset<T>(ptr: *T, count: int) -> *T {
+ intrinsics::offset(ptr, count)
}
-/// Calculate the offset from a mut pointer
+/// Calculate the offset from a mut pointer. The count *must* be in bounds or
+/// otherwise the loads of this address are undefined.
#[inline]
#[cfg(not(stage0))]
-pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
- unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
+pub unsafe fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
+ intrinsics::offset(ptr as *T, count) as *mut T
}
/// Return the offset of the first null pointer in `buf`.
fn is_not_null(&self) -> bool;
fn to_uint(&self) -> uint;
unsafe fn to_option(&self) -> Option<&T>;
- fn offset(&self, count: int) -> Self;
- unsafe fn offset_inbounds(self, count: int) -> Self;
+ unsafe fn offset(self, count: int) -> Self;
}
/// Extension methods for immutable pointers
}
}
- /// Calculates the offset from a pointer.
- #[inline]
- fn offset(&self, count: int) -> *T { offset(*self, count) }
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end.
#[inline]
- unsafe fn offset_inbounds(self, count: int) -> *T {
- intrinsics::offset_inbounds(self, count)
- }
+ unsafe fn offset(self, count: int) -> *T { offset(self, count) }
}
/// Extension methods for mutable pointers
}
}
- /// Calculates the offset from a mutable pointer.
- #[inline]
- fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end. An arithmetic overflow is also
/// undefined behaviour.
/// This method should be preferred over `offset` when the guarantee can be
/// satisfied, to enable better optimization.
#[inline]
- unsafe fn offset_inbounds(self, count: int) -> *mut T {
- intrinsics::offset_inbounds(self as *T, count) as *mut T
- }
+ unsafe fn offset(self, count: int) -> *mut T { mut_offset(self, count) }
}
// Equality for pointers
}
}
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *T> for *T {
- /// Add an integer value to a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
- #[inline]
- fn add(&self, rhs: &I) -> *T {
- self.offset(rhs.to_int() as int)
- }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *T> for *T {
- /// Subtract an integer value from a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
- #[inline]
- fn sub(&self, rhs: &I) -> *T {
- self.offset(-rhs.to_int() as int)
- }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Add<I, *mut T> for *mut T {
- /// Add an integer value to a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
- #[inline]
- fn add(&self, rhs: &I) -> *mut T {
- self.offset(rhs.to_int() as int)
- }
-}
-
-#[cfg(not(test))]
-impl<T, I: Int> Sub<I, *mut T> for *mut T {
- /// Subtract an integer value from a pointer to get an offset pointer.
- /// Is calculated according to the size of the type pointed to.
- #[inline]
- fn sub(&self, rhs: &I) -> *mut T {
- self.offset(-rhs.to_int() as int)
- }
-}
-
#[cfg(test)]
pub mod ptr_tests {
use super::*;
assert!(p.is_null());
assert!(!p.is_not_null());
- let q = offset(p, 1);
+ let q = unsafe { offset(p, 1) };
assert!(!q.is_null());
assert!(q.is_not_null());
assert!(mp.is_null());
assert!(!mp.is_not_null());
- let mq = mp.offset(1);
+ let mq = unsafe { mp.offset(1) };
assert!(!mq.is_null());
assert!(mq.is_not_null());
}
unsafe {
let xs = ~[5, ..16];
let mut ptr = to_ptr(xs);
- let end = ptr + 16;
+ let end = ptr.offset(16);
while ptr < end {
assert_eq!(*ptr, 5);
- ptr = ptr + 1u;
+ ptr = ptr.offset(1);
}
let mut xs_mut = xs.clone();
let mut m_ptr = to_mut_ptr(xs_mut);
- let m_end = m_ptr + 16i16;
+ let m_end = m_ptr.offset(16);
while m_ptr < m_end {
*m_ptr += 5;
- m_ptr = m_ptr + 1u8;
+ m_ptr = m_ptr.offset(1);
}
assert_eq!(xs_mut, ~[10, ..16]);
let ptr = to_ptr(xs);
while idx >= 0i8 {
- assert_eq!(*(ptr + idx), idx as int);
+ assert_eq!(*(ptr.offset(idx as int)), idx as int);
idx = idx - 1i8;
}
let mut xs_mut = xs.clone();
let m_start = to_mut_ptr(xs_mut);
- let mut m_ptr = m_start + 9u32;
+ let mut m_ptr = m_start.offset(9);
while m_ptr >= m_start {
*m_ptr += *m_ptr;
- m_ptr = m_ptr - 1i8;
+ m_ptr = m_ptr.offset(-1);
}
assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
* 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(ptr::offset(p, sz as int) as uint, al) as *u8;
+ 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)
}
}
*/
#[doc(hidden)];
-#[deny(unused_imports)];
-#[deny(unused_mut)];
-#[deny(unused_variable)];
-#[deny(unused_unsafe)];
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;
/// Point one word beyond the high end of the allocated stack
pub fn end(&self) -> *uint {
- vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+ unsafe {
+ vec::raw::to_ptr(self.buf).offset(self.buf.len() as int) as *uint
+ }
}
}
use borrow;
use cast::transmute;
use cleanup;
+use local_data;
use libc::{c_void, uintptr_t};
-use ptr;
use prelude::*;
use option::{Option, Some, None};
use rt::borrowck;
}
pub struct GarbageCollector;
-pub struct LocalStorage(*c_void, Option<extern "Rust" fn(*c_void)>);
+pub struct LocalStorage(Option<local_data::Map>);
pub struct Unwinder {
unwinding: bool,
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
- storage: LocalStorage(ptr::null(), None),
+ storage: LocalStorage(None),
logger: StdErrLogger,
unwinder: Unwinder { unwinding: false },
taskgroup: None,
// Run the task main function, then do some cleanup.
do f.finally {
-
- // Destroy task-local storage. This may run user dtors.
- match self.storage {
- LocalStorage(ptr, Some(ref dtor)) => {
- (*dtor)(ptr)
- }
- _ => ()
- }
-
+ // First, destroy task-local storage. This may run user dtors.
+ //
// FIXME #8302: Dear diary. I'm so tired and confused.
// There's some interaction in rustc between the box
// annihilator and the TLS dtor by which TLS is
// TLS would be reinitialized but never destroyed,
// but somehow this works. I have no idea what's going
// on but this seems to make things magically work. FML.
- self.storage = LocalStorage(ptr::null(), None);
+ //
+ // (added after initial comment) A possible interaction here is
+ // that the destructors for the objects in TLS themselves invoke
+ // TLS, or possibly some destructors for those objects being
+ // annihilated invoke TLS. Sadly these two operations seemed to
+ // be intertwined, and miraculously work for now...
+ self.storage.take();
// Destroy remaining boxes. Also may run user dtors.
unsafe { cleanup::annihilate(); }
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,
pub unsafe fn slice_unchecked<'a>(s: &'a str, begin: uint, end: uint) -> &'a str {
do s.as_imm_buf |sbuf, _n| {
cast::transmute(Slice {
- data: sbuf.offset_inbounds(begin as int),
+ data: sbuf.offset(begin as int),
len: end - begin,
})
}
/// 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)
}
}
+++ /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.
-
-#[allow(missing_doc)];
-
-use cast;
-use libc;
-use local_data;
-use prelude::*;
-use ptr;
-use unstable::raw;
-use util;
-
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
- NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
- pub fn new() -> Handle {
- use rt::local::Local;
- unsafe {
- let task: *mut Task = Local::unsafe_borrow();
- NewHandle(&mut (*task).storage)
- }
- }
-}
-
-#[deriving(Eq)]
-enum LoanState {
- NoLoan, ImmLoan, MutLoan
-}
-
-impl LoanState {
- fn describe(&self) -> &'static str {
- match *self {
- NoLoan => "no loan",
- ImmLoan => "immutable",
- MutLoan => "mutable"
- }
- }
-}
-
-trait LocalData {}
-impl<T: 'static> LocalData for T {}
-
-// The task-local-map stores all TLS information for the currently running task.
-// It is stored as an owned pointer into the runtime, and it's only allocated
-// when TLS is used for the first time. This map must be very carefully
-// constructed because it has many mutable loans unsoundly handed out on it to
-// the various invocations of TLS requests.
-//
-// One of the most important operations is loaning a value via `get` to a
-// caller. In doing so, the slot that the TLS entry is occupying cannot be
-// invalidated because upon returning it's loan state must be updated. Currently
-// the TLS map is a vector, but this is possibly dangerous because the vector
-// can be reallocated/moved when new values are pushed onto it.
-//
-// This problem currently isn't solved in a very elegant way. Inside the `get`
-// function, it internally "invalidates" all references after the loan is
-// finished and looks up into the vector again. In theory this will prevent
-// pointers from being moved under our feet so long as LLVM doesn't go too crazy
-// with the optimizations.
-//
-// n.b. Other structures are not sufficient right now:
-// * HashMap uses ~[T] internally (push reallocates/moves)
-// * TreeMap is plausible, but it's in extra
-// * dlist plausible, but not in std
-// * a custom owned linked list was attempted, but difficult to write
-// and involved a lot of extra code bloat
-//
-// n.b. Has to be stored with a pointer at outermost layer; the foreign call
-// returns void *.
-//
-// n.b. If TLS is used heavily in future, this could be made more efficient with
-// a proper map.
-type TaskLocalMap = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
-type TLSValue = ~LocalData:;
-
-fn cleanup_task_local_map(map_ptr: *libc::c_void) {
- unsafe {
- assert!(!map_ptr.is_null());
- // Get and keep the single reference that was created at the
- // beginning.
- let _map: TaskLocalMap = cast::transmute(map_ptr);
- // All local_data will be destroyed along with the map.
- }
-}
-
-// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
-
- unsafe fn newsched_map(local: *mut LocalStorage) -> &mut TaskLocalMap {
- // This is based on the same idea as the oldsched code above.
- match &mut *local {
- // If the at_exit function is already set, then we just need to take
- // a loan out on the TLS map stored inside
- &LocalStorage(ref mut map_ptr, Some(_)) => {
- assert!(map_ptr.is_not_null());
- return cast::transmute(map_ptr);
- }
- // If this is the first time we've accessed TLS, perform similar
- // actions to the oldsched way of doing things.
- &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
- assert!(map_ptr.is_null());
- assert!(at_exit.is_none());
- let map: TaskLocalMap = ~[];
- *map_ptr = cast::transmute(map);
- *at_exit = Some(cleanup_task_local_map);
- return cast::transmute(map_ptr);
- }
- }
- }
-
- match handle {
- NewHandle(local_storage) => newsched_map(local_storage)
- }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<T>) -> *libc::c_void {
- let pair: raw::Closure = cast::transmute_copy(&key);
- return pair.code as *libc::c_void;
-}
-
-pub unsafe fn local_pop<T: 'static>(handle: Handle,
- key: local_data::Key<T>) -> Option<T> {
- let map = get_local_map(handle);
- let key_value = key_to_key_value(key);
-
- for entry in map.mut_iter() {
- match *entry {
- Some((k, _, loan)) if k == key_value => {
- if loan != NoLoan {
- fail!("TLS value cannot be removed because it is already \
- borrowed as %s", loan.describe());
- }
- // Move the data out of the `entry` slot via util::replace. This
- // is guaranteed to succeed because we already matched on `Some`
- // above.
- let data = match util::replace(entry, None) {
- Some((_, data, _)) => data,
- None => abort(),
- };
-
- // Move `data` into transmute to get out the memory that it
- // owns, we must free it manually later.
- let (_vtable, box): (uint, ~~T) = cast::transmute(data);
-
- // Read the box's value (using the compiler's built-in
- // auto-deref functionality to obtain a pointer to the base)
- let ret = ptr::read_ptr(cast::transmute::<&T, *mut T>(*box));
-
- // Finally free the allocated memory. we don't want this to
- // actually touch the memory inside because it's all duplicated
- // now, so the box is transmuted to a 0-sized type. We also use
- // a type which references `T` because currently the layout
- // could depend on whether T contains managed pointers or not.
- let _: ~~[T, ..0] = cast::transmute(box);
-
- // Everything is now deallocated, and we own the value that was
- // located inside TLS, so we now return it.
- return Some(ret);
- }
- _ => {}
- }
- }
- return None;
-}
-
-pub unsafe fn local_get<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- f: &fn(Option<&T>) -> U) -> U {
- local_get_with(handle, key, ImmLoan, f)
-}
-
-pub unsafe fn local_get_mut<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- f: &fn(Option<&mut T>) -> U) -> U {
- do local_get_with(handle, key, MutLoan) |x| {
- match x {
- None => f(None),
- // We're violating a lot of compiler guarantees with this
- // invocation of `transmute_mut`, but we're doing runtime checks to
- // ensure that it's always valid (only one at a time).
- //
- // there is no need to be upset!
- Some(x) => { f(Some(cast::transmute_mut(x))) }
- }
- }
-}
-
-unsafe fn local_get_with<T: 'static, U>(handle: Handle,
- key: local_data::Key<T>,
- state: LoanState,
- f: &fn(Option<&T>) -> U) -> U {
- // This function must be extremely careful. Because TLS can store owned
- // values, and we must have some form of `get` function other than `pop`,
- // this function has to give a `&` reference back to the caller.
- //
- // One option is to return the reference, but this cannot be sound because
- // the actual lifetime of the object is not known. The slot in TLS could not
- // be modified until the object goes out of scope, but the TLS code cannot
- // know when this happens.
- //
- // For this reason, the reference is yielded to a specified closure. This
- // way the TLS code knows exactly what the lifetime of the yielded pointer
- // is, allowing callers to acquire references to owned data. This is also
- // sound so long as measures are taken to ensure that while a TLS slot is
- // loaned out to a caller, it's not modified recursively.
- let map = get_local_map(handle);
- let key_value = key_to_key_value(key);
-
- let pos = map.iter().position(|entry| {
- match *entry {
- Some((k, _, _)) if k == key_value => true, _ => false
- }
- });
- match pos {
- None => { return f(None); }
- Some(i) => {
- let ret;
- let mut return_loan = false;
- match map[i] {
- Some((_, ref data, ref mut loan)) => {
- match (state, *loan) {
- (_, NoLoan) => {
- *loan = state;
- return_loan = true;
- }
- (ImmLoan, ImmLoan) => {}
- (want, cur) => {
- fail!("TLS slot cannot be borrowed as %s because \
- it is already borrowed as %s",
- want.describe(), cur.describe());
- }
- }
- // data was created with `~~T as ~LocalData`, so we extract
- // pointer part of the trait, (as ~~T), and then use
- // compiler coercions to achieve a '&' pointer.
- match *cast::transmute::<&TLSValue, &(uint, ~~T)>(data) {
- (_vtable, ref box) => {
- let value: &T = **box;
- ret = f(Some(value));
- }
- }
- }
- _ => abort()
- }
-
- // n.b. 'data' and 'loans' are both invalid pointers at the point
- // 'f' returned because `f` could have appended more TLS items which
- // in turn relocated the vector. Hence we do another lookup here to
- // fixup the loans.
- if return_loan {
- match map[i] {
- Some((_, _, ref mut loan)) => { *loan = NoLoan; }
- None => { abort(); }
- }
- }
- return ret;
- }
- }
-}
-
-fn abort() -> ! {
- #[fixed_stack_segment]; #[inline(never)];
-
- unsafe { libc::abort() }
-}
-
-pub unsafe fn local_set<T: 'static>(handle: Handle,
- key: local_data::Key<T>,
- data: T) {
- let map = get_local_map(handle);
- let keyval = key_to_key_value(key);
-
- // When the task-local map is destroyed, all the data needs to be cleaned
- // up. For this reason we can't do some clever tricks to store '~T' as a
- // '*c_void' or something like that. To solve the problem, we cast
- // everything to a trait (LocalData) which is then stored inside the map.
- // Upon destruction of the map, all the objects will be destroyed and the
- // traits have enough information about them to destroy themselves.
- //
- // FIXME(#7673): This should be "~data as ~LocalData" (without the colon at
- // the end, and only one sigil)
- let data = ~~data as ~LocalData:;
-
- fn insertion_position(map: &mut TaskLocalMap,
- key: *libc::c_void) -> Option<uint> {
- // First see if the map contains this key already
- let curspot = map.iter().position(|entry| {
- match *entry {
- Some((ekey, _, loan)) if key == ekey => {
- if loan != NoLoan {
- fail!("TLS value cannot be overwritten because it is
- already borrowed as %s", loan.describe())
- }
- true
- }
- _ => false,
- }
- });
- // If it doesn't contain the key, just find a slot that's None
- match curspot {
- Some(i) => Some(i),
- None => map.iter().position(|entry| entry.is_none())
- }
- }
-
- match insertion_position(map, keyval) {
- Some(i) => { map[i] = Some((keyval, data, NoLoan)); }
- None => { map.push(Some((keyval, data, NoLoan))); }
- }
-}
#[cfg(test)] use ptr;
#[cfg(test)] use task;
-mod local_data_priv;
pub mod spawn;
/**
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));
/// Get the address of the `__morestack` stack growth function.
pub fn morestack_addr() -> *();
- /// Calculates the offset from a pointer.
- ///
- /// This is implemented as an intrinsic to avoid converting to and from an
- /// integer, since the conversion would throw away aliasing information.
- pub fn offset<T>(dst: *T, offset: int) -> *T;
-
/// Calculates the offset from a pointer. The offset *must* be in-bounds of
/// the object, or one-byte-past-the-end. An arithmetic overflow is also
/// undefined behaviour.
///
- /// This intrinsic should be preferred over `offset` when the guarantee can
- /// be satisfied, to enable better optimization.
- pub fn offset_inbounds<T>(dst: *T, offset: int) -> *T;
+ /// This is implemented as an intrinsic to avoid converting to and from an
+ /// integer, since the conversion would throw away aliasing information.
+ pub fn offset<T>(dst: *T, offset: int) -> *T;
/// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
/// 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() {
lifetime: cast::transmute(p)}
} else {
VecIterator{ptr: p,
- end: p.offset_inbounds(self.len() as int),
+ end: p.offset(self.len() as int),
lifetime: cast::transmute(p)}
}
}
lifetime: cast::transmute(p)}
} else {
VecMutIterator{ptr: p,
- end: p.offset_inbounds(self.len() as int),
+ end: p.offset(self.len() as int),
lifetime: cast::transmute(p)}
}
}
// same pointer.
cast::transmute(self.ptr as uint + 1)
} else {
- self.ptr.offset_inbounds(1)
+ self.ptr.offset(1)
};
Some(cast::transmute(old))
// See above for why 'ptr.offset' isn't used
cast::transmute(self.end as uint - 1)
} else {
- self.end.offset_inbounds(-1)
+ self.end.offset(-1)
};
Some(cast::transmute(self.end))
}
ty_tup(~[Ty]),
ty_path(Path, Option<OptVec<TyParamBound>>, NodeId), // for #7264; see above
ty_mac(mac),
+ ty_typeof(@expr),
// ty_infer means the type should be inferred instead of it having been
// specified. This should only appear at the "top level" of a type and not
// nested in one.
fld.fold_expr(e)
)
}
+ ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
ty_mac(ref mac) => ty_mac(fold_mac(mac))
}
}
(v.visit_ty)(mt.ty, (e.clone(), v));
(v.visit_expr)(ex, (e.clone(), v));
},
+ ty_typeof(ex) => {
+ (v.visit_expr)(ex, (e.clone(), v));
+ }
ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
}
}
use ast::{sty_box, sty_region, sty_static, sty_uniq, sty_value};
use ast::{token_tree, trait_method, trait_ref, tt_delim, tt_seq, tt_tok};
use ast::{tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot, ty_box};
-use ast::{TypeField, ty_fixed_length_vec, ty_closure, ty_bare_fn};
+use ast::{TypeField, ty_fixed_length_vec, ty_closure, ty_bare_fn, ty_typeof};
use ast::{ty_infer, TypeMethod};
use ast::{ty_nil, TyParam, TyParamBound, ty_path, ty_ptr, ty_rptr};
use ast::{ty_tup, ty_u32, ty_uniq, ty_vec, uniq};
let result = self.parse_ty_closure(ast::BorrowedSigil, None);
self.obsolete(*self.last_span, ObsoleteBareFnType);
result
+ } else if self.eat_keyword(keywords::Typeof) {
+ // TYPEOF
+ // In order to not be ambiguous, the type must be surrounded by parens.
+ self.expect(&token::LPAREN);
+ let e = self.parse_expr();
+ self.expect(&token::RPAREN);
+ ty_typeof(e)
} else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) {
// NAMED TYPE
self.bump();
sty_value
}
+ token::BINOP(token::STAR) => {
+ // Possibly "*self" or "*mut self" -- not supported. Try to avoid
+ // emitting cryptic "unexpected token" errors.
+ self.bump();
+ if self.token_is_mutability(self.token) {
+ self.bump();
+ }
+ if self.is_self_ident() {
+ self.span_err(*self.span, "cannot pass self by unsafe pointer");
+ self.bump();
+ }
+ sty_value
+ }
_ => {
sty_static
}
"be", // 64
"pure", // 65
"yield", // 66
+ "typeof", // 67
];
@ident_interner {
True,
Trait,
Type,
+ Typeof,
Unsafe,
Use,
While,
True => ident { name: 57, ctxt: 0 },
Trait => ident { name: 58, ctxt: 0 },
Type => ident { name: 59, ctxt: 0 },
+ Typeof => ident { name: 67, ctxt: 0 },
Unsafe => ident { name: 60, ctxt: 0 },
Use => ident { name: 61, ctxt: 0 },
While => ident { name: 62, ctxt: 0 },
pub fn is_any_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 8 | 27 | 32 .. 66 => true,
+ 8 | 27 | 32 .. 67 => true,
_ => false,
},
_ => false
pub fn is_reserved_keyword(tok: &Token) -> bool {
match *tok {
token::IDENT(sid, false) => match sid.name {
- 64 .. 66 => true,
+ 64 .. 67 => true,
_ => false,
},
_ => false,
print_expr(s, v);
word(s.s, "]");
}
+ ast::ty_typeof(e) => {
+ word(s.s, "typeof(");
+ print_expr(s, e);
+ word(s.s, ")");
+ }
ast::ty_mac(_) => {
fail!("print_type doesn't know how to print a ty_mac");
}
visitor.visit_ty(mutable_type.ty, env.clone());
visitor.visit_expr(expression, env)
}
+ ty_typeof(expression) => {
+ visitor.visit_expr(expression, env)
+ }
ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
}
}
-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 =
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;
+ }
+}
--- /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.
+
+// Regression test for issue #5239
+
+fn main() {
+ let x: &fn(int) -> int = |ref x| { x += 1; }; //~ ERROR binary operation + cannot be applied to type `&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.
+
+fn main() {
+ let typeof = (); //~ ERROR `typeof` is a reserved keyword
+}
--- /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.
+
+trait A {
+ fn foo(*mut self); //~ ERROR cannot pass self by unsafe pointer
+ fn bar(*self); //~ ERROR cannot pass self by unsafe pointer
+}
+
+struct X;
+impl A for X {
+ fn foo(*mut self) { } //~ ERROR cannot pass self by unsafe pointer
+ fn bar(*self) { } //~ ERROR cannot pass self by unsafe pointer
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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() {}
#[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()));
--- /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.
+
+// Regression test for issue #5239
+
+fn main() {
+ let _f: &fn(int) -> int = |ref x: int| { *x };
+ let foo = 10;
+ assert!(_f(foo) == 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.
+
+// 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>());
+}
/// 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());