]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #14236 : alexcrichton/rust/issue-14082, r=brson
authorbors <bors@rust-lang.org>
Sat, 17 May 2014 04:36:23 +0000 (21:36 -0700)
committerbors <bors@rust-lang.org>
Sat, 17 May 2014 04:36:23 +0000 (21:36 -0700)
The reexport didn't switch the privacy, so the reexport was actually considered
private, erroneously failing to resolve imports later on.

Closes #14082

268 files changed:
Makefile.in
mk/crates.mk
mk/docs.mk
mk/rt.mk
mk/tests.mk
src/compiletest/common.rs
src/compiletest/compiletest.rs
src/compiletest/errors.rs
src/compiletest/header.rs
src/compiletest/procsrv.rs
src/compiletest/runtest.rs
src/compiletest/util.rs
src/doc/complement-cheatsheet.md
src/doc/guide-macros.md
src/doc/guide-tasks.md
src/doc/guide-testing.md
src/doc/po/ja/complement-cheatsheet.md.po
src/doc/po/ja/rust.md.po
src/doc/po/ja/tutorial.md.po
src/doc/rust.md
src/doc/rustdoc.md
src/doc/tutorial.md
src/libarena/lib.rs
src/libcollections/btree.rs
src/libcollections/hashmap.rs
src/libcollections/lru_cache.rs
src/libcore/any.rs
src/libcore/cell.rs
src/libcore/char.rs
src/libcore/clone.rs
src/libcore/cmp.rs
src/libcore/default.rs
src/libcore/failure.rs
src/libcore/fmt/float.rs [new file with mode: 0644]
src/libcore/fmt/mod.rs [new file with mode: 0644]
src/libcore/fmt/num.rs [new file with mode: 0644]
src/libcore/fmt/rt.rs [new file with mode: 0644]
src/libcore/intrinsics.rs
src/libcore/iter.rs
src/libcore/lib.rs
src/libcore/macros.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/num/mod.rs
src/libcore/option.rs
src/libcore/owned.rs [deleted file]
src/libcore/prelude.rs
src/libcore/ptr.rs
src/libcore/result.rs
src/libcore/should_not_exist.rs
src/libcore/str.rs
src/libcore/unit.rs [deleted file]
src/libflate/lib.rs
src/libfmt_macros/lib.rs
src/libgetopts/lib.rs
src/libgreen/macros.rs
src/libgreen/sched.rs
src/liblog/lib.rs
src/libnative/io/file_unix.rs
src/libnative/io/file_win32.rs
src/libnative/io/mod.rs
src/libnative/io/process.rs
src/libnum/bigint.rs
src/libnum/complex.rs
src/libnum/lib.rs
src/libnum/rational.rs
src/libregex/parse.rs
src/libregex/re.rs
src/librlibc/lib.rs [new file with mode: 0644]
src/librustc/back/archive.rs
src/librustc/back/link.rs
src/librustc/driver/config.rs
src/librustc/driver/driver.rs
src/librustc/driver/mod.rs
src/librustc/driver/session.rs
src/librustc/lib.rs
src/librustc/lib/llvm.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/cfg/graphviz.rs [new file with mode: 0644]
src/librustc/middle/cfg/mod.rs
src/librustc/middle/graph.rs
src/librustc/middle/lint.rs
src/librustc/middle/liveness.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/monomorphize.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/variance.rs
src/librustdoc/clean.rs
src/librustdoc/core.rs
src/librustdoc/html/escape.rs
src/librustdoc/html/format.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/html/toc.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/librustuv/file.rs
src/librustuv/lib.rs
src/librustuv/macros.rs
src/librustuv/net.rs
src/librustuv/pipe.rs
src/librustuv/process.rs
src/librustuv/uvio.rs
src/libsemver/lib.rs
src/libserialize/base64.rs
src/libserialize/ebml.rs
src/libserialize/hex.rs
src/libserialize/json.rs
src/libserialize/serialize.rs
src/libstd/bitflags.rs
src/libstd/c_str.rs
src/libstd/fmt.rs [new file with mode: 0644]
src/libstd/fmt/mod.rs [deleted file]
src/libstd/fmt/num.rs [deleted file]
src/libstd/fmt/rt.rs [deleted file]
src/libstd/io/buffered.rs
src/libstd/io/flate.rs [deleted file]
src/libstd/io/mod.rs
src/libstd/io/net/ip.rs
src/libstd/io/net/udp.rs
src/libstd/io/process.rs
src/libstd/io/stdio.rs
src/libstd/io/tempfile.rs
src/libstd/lib.rs
src/libstd/macros.rs
src/libstd/num/f32.rs
src/libstd/num/f64.rs
src/libstd/num/i16.rs
src/libstd/num/i32.rs
src/libstd/num/i64.rs
src/libstd/num/i8.rs
src/libstd/num/int.rs
src/libstd/num/int_macros.rs
src/libstd/num/mod.rs
src/libstd/num/strconv.rs
src/libstd/num/u16.rs
src/libstd/num/u32.rs
src/libstd/num/u64.rs
src/libstd/num/u8.rs
src/libstd/num/uint.rs
src/libstd/num/uint_macros.rs
src/libstd/os.rs
src/libstd/owned.rs
src/libstd/path/posix.rs
src/libstd/path/windows.rs
src/libstd/prelude.rs
src/libstd/repr.rs
src/libstd/result.rs [deleted file]
src/libstd/rt/local.rs
src/libstd/rt/rtio.rs
src/libstd/rt/thread.rs
src/libstd/rt/unwind.rs
src/libstd/rt/util.rs
src/libstd/str.rs
src/libstd/strbuf.rs
src/libstd/task.rs
src/libstd/unstable/dynamic_lib.rs
src/libstd/unstable/mod.rs
src/libstd/vec.rs
src/libsyntax/abi.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map.rs
src/libsyntax/crateid.rs
src/libsyntax/diagnostic.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/deriving/show.rs
src/libsyntax/ext/format.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/token.rs
src/libterm/lib.rs
src/libterm/terminfo/mod.rs
src/libterm/win.rs [new file with mode: 0644]
src/libtest/lib.rs
src/libtest/stats.rs
src/libtime/lib.rs
src/liburl/lib.rs
src/libuuid/lib.rs
src/libworkcache/lib.rs
src/rustllvm/PassWrapper.cpp
src/snapshots.txt
src/test/auxiliary/cci_class_cast.rs
src/test/auxiliary/linkage-visibility.rs
src/test/bench/shootout-chameneos-redux.rs
src/test/bench/shootout-mandelbrot.rs
src/test/bench/shootout-pfib.rs
src/test/compile-fail-fulldeps/gated-phase.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs [new file with mode: 0644]
src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs [new file with mode: 0644]
src/test/compile-fail/gated-phase.rs [deleted file]
src/test/compile-fail/ifmt-unimpl.rs
src/test/compile-fail/macro-crate-unexported-macro.rs [deleted file]
src/test/compile-fail/macro-crate-unknown-crate.rs [deleted file]
src/test/compile-fail/phase-syntax-doesnt-resolve.rs [deleted file]
src/test/compile-fail/use-after-move-implicity-coerced-object.rs
src/test/run-make/graphviz-flowgraph/Makefile [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f00.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f01.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f02.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f03.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f04.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f05.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f06.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f07.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f08.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f09.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f10.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f11.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f12.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f13.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f14.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f15.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f16.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f17.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f18.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f19.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f20.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f21.rs [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot [new file with mode: 0644]
src/test/run-make/graphviz-flowgraph/f22.rs [new file with mode: 0644]
src/test/run-make/unicode-input/multiple_files.rs
src/test/run-make/unicode-input/span_length.rs
src/test/run-pass/backtrace.rs
src/test/run-pass/capturing-logging.rs
src/test/run-pass/class-separate-impl.rs
src/test/run-pass/colorful-write-macros.rs
src/test/run-pass/core-run-destroy.rs
src/test/run-pass/deriving-show-2.rs
src/test/run-pass/foreign-call-no-runtime.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/issue-10626.rs
src/test/run-pass/issue-13304.rs
src/test/run-pass/issue-2804.rs
src/test/run-pass/issue-2904.rs
src/test/run-pass/issue-3563-3.rs
src/test/run-pass/logging-separate-lines.rs
src/test/run-pass/new-impl-syntax.rs
src/test/run-pass/out-of-stack.rs
src/test/run-pass/process-detach.rs
src/test/run-pass/process-spawn-with-unicode-params.rs
src/test/run-pass/signal-exit-status.rs
src/test/run-pass/sigpipe-should-be-ignored.rs
src/test/run-pass/tempfile.rs

index c0e1973e95e59038da25441e125095d1fbc1b10f..5d37c1da8fb3cb51453324b5c76d9aca11b4f4da 100644 (file)
@@ -68,7 +68,7 @@
 #
 #   * `TESTNAME=...` - Specify the name of tests to run
 #   * `CHECK_IGNORED=1` - Run normally-ignored tests
-#   * `NO_BENCH=1` - Don't run crate benchmarks (disable `--bench` flag)
+#   * `PLEASE_BENCH=1` - Run crate benchmarks (enable `--bench` flag)
 #
 #   * `CFG_ENABLE_VALGRIND=1` - Run tests under valgrind
 #   * `VALGRIND_COMPILE=1` - Run the compiler itself under valgrind
index 0437e08de28b6b4f3eba83fcbbc07f0ae8a48d2a..4ac4abe9063ef9662855ec4b8d444cf9a3223b09 100644 (file)
 
 TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
                  uuid serialize sync getopts collections num test time rand \
-                workcache url log regex graphviz core
+                workcache url log regex graphviz core rlibc
 HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros
 CRATES := $(TARGET_CRATES) $(HOST_CRATES)
 TOOLS := compiletest rustdoc rustc
 
 DEPS_core :=
+DEPS_rlibc :=
 DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:jemalloc
+DEPS_graphviz := std
 DEPS_green := std rand native:context_switch
 DEPS_rustuv := std native:uv native:uv_support
 DEPS_native := std
 DEPS_syntax := std term serialize collections log fmt_macros
 DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
-              collections time log
+              collections time log graphviz
 DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \
                 test time
 DEPS_flate := std native:miniz
@@ -71,7 +73,7 @@ DEPS_arena := std collections
 DEPS_graphviz := std
 DEPS_glob := std
 DEPS_serialize := std collections log
-DEPS_term := std collections
+DEPS_term := std collections log
 DEPS_semver := std
 DEPS_uuid := std serialize rand
 DEPS_sync := std
@@ -80,8 +82,8 @@ DEPS_collections := std rand
 DEPS_fourcc := syntax std
 DEPS_hexfloat := syntax std
 DEPS_num := std rand
-DEPS_test := std collections getopts serialize term time
-DEPS_time := std serialize
+DEPS_test := std collections getopts serialize term time regex
+DEPS_time := std serialize sync
 DEPS_rand := std
 DEPS_url := std collections
 DEPS_workcache := std serialize collections log
@@ -98,6 +100,7 @@ TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
 TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
 
 ONLY_RLIB_core := 1
+ONLY_RLIB_rlibc := 1
 
 ################################################################################
 # You should not need to edit below this line
index 40c2440c0c07a524d519e9f8d22c3496367ec184..4d00223fca88045e871e1f9493a8972324059db2 100644 (file)
@@ -30,7 +30,7 @@ DOCS := index intro tutorial guide-ffi guide-macros guide-lifetimes \
        guide-tasks guide-container guide-pointers guide-testing \
        guide-runtime complement-bugreport complement-cheatsheet \
        complement-lang-faq complement-project-faq rust rustdoc \
-       guide-unsafe not_found
+       guide-unsafe
 
 PDF_DOCS := tutorial rust
 
@@ -42,10 +42,11 @@ L10N_LANGS := ja
 # Generally no need to edit below here.
 
 # The options are passed to the documentation generators.
-RUSTDOC_HTML_OPTS = --markdown-css rust.css \
-       --markdown-before-content=doc/version_info.html \
+RUSTDOC_HTML_OPTS_NO_CSS = --markdown-before-content=doc/version_info.html \
        --markdown-in-header=doc/favicon.inc --markdown-after-content=doc/footer.inc
 
+RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
+
 PANDOC_BASE_OPTS := --standalone --toc --number-sections
 PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --include-before-body=doc/version.tex \
        --from=markdown --include-before-body=doc/footer.tex --to=latex
@@ -152,6 +153,11 @@ doc/footer.tex: $(D)/footer.inc | doc/
        @$(call E, pandoc: $@)
        $(CFG_PANDOC) --from=html --to=latex $< --output=$@
 
+# HTML (rustdoc)
+DOC_TARGETS += doc/not_found.html
+doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/
+       $(RUSTDOC) $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css http://static.rust-lang.org/doc/master/rust.css $<
+
 define DEF_DOC
 
 # HTML (rustdoc)
index 67ca5fefffc3ede870062ca9a88f77ba26f11a20..c506e8f78cb7d24e5b872e8454b9a65b9e6e67b4 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -261,7 +261,7 @@ $$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
                AR="$$(AR_$(1))" \
                RANLIB="$$(AR_$(1)) s" \
                CPPFLAGS="-I $(S)src/rt/" \
-               EXTRA_CFLAGS="$$(CFG_CFLAGS_$(1))"
+               EXTRA_CFLAGS="$$(CFG_CFLAGS_$(1)) -g1"
        $$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
        $$(Q)cp $$(JEMALLOC_BUILD_DIR_$(1))/lib/$$(JEMALLOC_REAL_NAME_$(1)) $$(JEMALLOC_LIB_$(1))
 
index befd1a737f7e67a1a096b3c8f1fcf0a99e1ae028..8f20d55e3859cf997ee36e7dd75cd8f6042cd0eb 100644 (file)
@@ -32,7 +32,7 @@ ifdef CHECK_IGNORED
   TESTARGS += --ignored
 endif
 
-TEST_BENCH = --bench
+TEST_BENCH =
 
 # Arguments to the cfail/rfail/rpass/bench tests
 ifdef CFG_VALGRIND
@@ -40,8 +40,8 @@ ifdef CFG_VALGRIND
   TEST_BENCH =
 endif
 
-ifdef NO_BENCH
-  TEST_BENCH =
+ifdef PLEASE_BENCH
+  TEST_BENCH = --bench
 endif
 
 # Arguments to the perf tests
index 9934a48c856554c1096538333e9e5a3b714beec7..a7f693da6cceceff6948bd85f6055cb14cce2ba2 100644 (file)
@@ -10,6 +10,7 @@
 
 use std::from_str::FromStr;
 use std::fmt;
+use regex::Regex;
 
 #[deriving(Clone, Eq)]
 pub enum Mode {
@@ -40,25 +41,25 @@ fn from_str(s: &str) -> Option<Mode> {
 impl fmt::Show for Mode {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let msg = match *self {
-          CompileFail => "compile-fail",
-          RunFail => "run-fail",
-          RunPass => "run-pass",
-          Pretty => "pretty",
-          DebugInfoGdb => "debuginfo-gdb",
-          DebugInfoLldb => "debuginfo-lldb",
-          Codegen => "codegen",
+            CompileFail => "compile-fail",
+            RunFail => "run-fail",
+            RunPass => "run-pass",
+            Pretty => "pretty",
+            DebugInfoGdb => "debuginfo-gdb",
+            DebugInfoLldb => "debuginfo-lldb",
+            Codegen => "codegen",
         };
-        write!(f.buf, "{}", msg)
+        msg.fmt(f)
     }
 }
 
 #[deriving(Clone)]
 pub struct Config {
     // The library paths required for running the compiler
-    pub compile_lib_path: ~str,
+    pub compile_lib_path: StrBuf,
 
     // The library paths required for running compiled programs
-    pub run_lib_path: ~str,
+    pub run_lib_path: StrBuf,
 
     // The rustc executable
     pub rustc_path: Path,
@@ -79,7 +80,7 @@ pub struct Config {
     pub aux_base: Path,
 
     // The name of the stage being built (stage1, etc)
-    pub stage_id: ~str,
+    pub stage_id: StrBuf,
 
     // The test mode, compile-fail, run-fail, run-pass
     pub mode: Mode,
@@ -88,7 +89,7 @@ pub struct Config {
     pub run_ignored: bool,
 
     // Only run tests that match this filter
-    pub filter: Option<~str>,
+    pub filter: Option<Regex>,
 
     // Write out a parseable log of tests that were run
     pub logfile: Option<Path>,
@@ -109,37 +110,37 @@ pub struct Config {
 
     // A command line to prefix program execution with,
     // for running under valgrind
-    pub runtool: Option<~str>,
+    pub runtool: Option<StrBuf>,
 
     // Flags to pass to the compiler when building for the host
-    pub host_rustcflags: Option<~str>,
+    pub host_rustcflags: Option<StrBuf>,
 
     // Flags to pass to the compiler when building for the target
-    pub target_rustcflags: Option<~str>,
+    pub target_rustcflags: Option<StrBuf>,
 
     // Run tests using the JIT
     pub jit: bool,
 
     // Target system to be tested
-    pub target: ~str,
+    pub target: StrBuf,
 
     // Host triple for the compiler being invoked
-    pub host: ~str,
+    pub host: StrBuf,
 
     // Path to the android tools
     pub android_cross_path: Path,
 
     // Extra parameter to run adb on arm-linux-androideabi
-    pub adb_path: ~str,
+    pub adb_path: StrBuf,
 
     // Extra parameter to run test sute on arm-linux-androideabi
-    pub adb_test_dir: ~str,
+    pub adb_test_dir: StrBuf,
 
     // status whether android device available or not
     pub adb_device_status: bool,
 
     // the path containing LLDB's Python module
-    pub lldb_python_dir: Option<~str>,
+    pub lldb_python_dir: Option<StrBuf>,
 
     // Explain what's going on
     pub verbose: bool
index 32bd66c2004311bd673749c07f297bd2ae63dc1e..3fb354a786768250b688f9cad6e6089839766606 100644 (file)
@@ -23,6 +23,8 @@
 extern crate green;
 extern crate rustuv;
 
+extern crate regex;
+
 use std::os;
 use std::io;
 use std::io::fs;
@@ -46,12 +48,14 @@ fn start(argc: int, argv: **u8) -> int {
 
 pub fn main() {
     let args = os::args();
-    let config = parse_config(args.move_iter().collect());
+    let config = parse_config(args.move_iter()
+                                  .map(|x| x.to_strbuf())
+                                  .collect());
     log_config(&config);
     run_tests(&config);
 }
 
-pub fn parse_config(args: Vec<~str> ) -> Config {
+pub fn parse_config(args: Vec<StrBuf> ) -> Config {
 
     let groups : Vec<getopts::OptGroup> =
         vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
@@ -89,7 +93,7 @@ pub fn parse_config(args: Vec<~str> ) -> Config {
     assert!(!args.is_empty());
     let argv0 = (*args.get(0)).clone();
     let args_ = args.tail();
-    if *args.get(1) == "-h".to_owned() || *args.get(1) == "--help".to_owned() {
+    if args.get(1).as_slice() == "-h" || args.get(1).as_slice() == "--help" {
         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
         println!("{}", getopts::usage(message, groups.as_slice()));
         println!("");
@@ -97,7 +101,7 @@ pub fn parse_config(args: Vec<~str> ) -> Config {
     }
 
     let matches =
-        &match getopts::getopts(args_, groups.as_slice()) {
+        &match getopts::getopts(args_.as_slice(), groups.as_slice()) {
           Ok(m) => m,
           Err(f) => fail!("{}", f.to_err_msg())
         };
@@ -113,45 +117,67 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
         Path::new(m.opt_str(nm).unwrap())
     }
 
+    let filter = if !matches.free.is_empty() {
+        let s = matches.free.get(0).as_slice();
+        match regex::Regex::new(s) {
+            Ok(re) => Some(re),
+            Err(e) => {
+                println!("failed to parse filter /{}/: {}", s, e);
+                fail!()
+            }
+        }
+    } else {
+        None
+    };
+
     Config {
-        compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
-        run_lib_path: matches.opt_str("run-lib-path").unwrap(),
+        compile_lib_path: matches.opt_str("compile-lib-path")
+                                 .unwrap()
+                                 .to_strbuf(),
+        run_lib_path: matches.opt_str("run-lib-path").unwrap().to_strbuf(),
         rustc_path: opt_path(matches, "rustc-path"),
         clang_path: matches.opt_str("clang-path").map(|s| Path::new(s)),
         llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| Path::new(s)),
         src_base: opt_path(matches, "src-base"),
         build_base: opt_path(matches, "build-base"),
         aux_base: opt_path(matches, "aux-base"),
-        stage_id: matches.opt_str("stage-id").unwrap(),
-        mode: FromStr::from_str(matches.opt_str("mode").unwrap()).expect("invalid mode"),
+        stage_id: matches.opt_str("stage-id").unwrap().to_strbuf(),
+        mode: FromStr::from_str(matches.opt_str("mode")
+                                       .unwrap()
+                                       .as_slice()).expect("invalid mode"),
         run_ignored: matches.opt_present("ignored"),
-        filter:
-            if !matches.free.is_empty() {
-                 Some((*matches.free.get(0)).clone())
-            } else {
-                None
-            },
+        filter: filter,
         logfile: matches.opt_str("logfile").map(|s| Path::new(s)),
         save_metrics: matches.opt_str("save-metrics").map(|s| Path::new(s)),
         ratchet_metrics:
             matches.opt_str("ratchet-metrics").map(|s| Path::new(s)),
         ratchet_noise_percent:
-            matches.opt_str("ratchet-noise-percent").and_then(|s| from_str::<f64>(s)),
-        runtool: matches.opt_str("runtool"),
-        host_rustcflags: matches.opt_str("host-rustcflags"),
-        target_rustcflags: matches.opt_str("target-rustcflags"),
+            matches.opt_str("ratchet-noise-percent")
+                   .and_then(|s| from_str::<f64>(s.as_slice())),
+        runtool: matches.opt_str("runtool").map(|x| x.to_strbuf()),
+        host_rustcflags: matches.opt_str("host-rustcflags")
+                                .map(|x| x.to_strbuf()),
+        target_rustcflags: matches.opt_str("target-rustcflags")
+                                  .map(|x| x.to_strbuf()),
         jit: matches.opt_present("jit"),
-        target: opt_str2(matches.opt_str("target")).to_str(),
-        host: opt_str2(matches.opt_str("host")).to_str(),
+        target: opt_str2(matches.opt_str("target").map(|x| x.to_strbuf())),
+        host: opt_str2(matches.opt_str("host").map(|x| x.to_strbuf())),
         android_cross_path: opt_path(matches, "android-cross-path"),
-        adb_path: opt_str2(matches.opt_str("adb-path")).to_str(),
-        adb_test_dir:
-            opt_str2(matches.opt_str("adb-test-dir")).to_str(),
+        adb_path: opt_str2(matches.opt_str("adb-path")
+                                  .map(|x| x.to_strbuf())),
+        adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")
+                                      .map(|x| x.to_strbuf())),
         adb_device_status:
-            "arm-linux-androideabi" == opt_str2(matches.opt_str("target")) &&
-            "(none)" != opt_str2(matches.opt_str("adb-test-dir")) &&
-            !opt_str2(matches.opt_str("adb-test-dir")).is_empty(),
-        lldb_python_dir: matches.opt_str("lldb-python-dir"),
+            "arm-linux-androideabi" ==
+                opt_str2(matches.opt_str("target")
+                                .map(|x| x.to_strbuf())).as_slice() &&
+            "(none)" !=
+                opt_str2(matches.opt_str("adb-test-dir")
+                                .map(|x| x.to_strbuf())).as_slice() &&
+            !opt_str2(matches.opt_str("adb-test-dir")
+                             .map(|x| x.to_strbuf())).is_empty(),
+        lldb_python_dir: matches.opt_str("lldb-python-dir")
+                                .map(|x| x.to_strbuf()),
         test_shard: test::opt_shard(matches.opt_str("test-shard")
                                            .map(|x| x.to_strbuf())),
         verbose: matches.opt_present("verbose")
@@ -160,50 +186,59 @@ fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
 
 pub fn log_config(config: &Config) {
     let c = config;
-    logv(c, format!("configuration:"));
-    logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
-    logv(c, format!("run_lib_path: {}", config.run_lib_path));
-    logv(c, format!("rustc_path: {}", config.rustc_path.display()));
-    logv(c, format!("src_base: {}", config.src_base.display()));
-    logv(c, format!("build_base: {}", config.build_base.display()));
-    logv(c, format!("stage_id: {}", config.stage_id));
-    logv(c, format!("mode: {}", config.mode));
-    logv(c, format!("run_ignored: {}", config.run_ignored));
-    logv(c, format!("filter: {}", opt_str(&config.filter)));
-    logv(c, format!("runtool: {}", opt_str(&config.runtool)));
-    logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
-    logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
-    logv(c, format!("jit: {}", config.jit));
-    logv(c, format!("target: {}", config.target));
-    logv(c, format!("host: {}", config.host));
-    logv(c, format!("android-cross-path: {}", config.android_cross_path.display()));
-    logv(c, format!("adb_path: {}", config.adb_path));
-    logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
-    logv(c, format!("adb_device_status: {}", config.adb_device_status));
+    logv(c, format_strbuf!("configuration:"));
+    logv(c, format_strbuf!("compile_lib_path: {}", config.compile_lib_path));
+    logv(c, format_strbuf!("run_lib_path: {}", config.run_lib_path));
+    logv(c, format_strbuf!("rustc_path: {}", config.rustc_path.display()));
+    logv(c, format_strbuf!("src_base: {}", config.src_base.display()));
+    logv(c, format_strbuf!("build_base: {}", config.build_base.display()));
+    logv(c, format_strbuf!("stage_id: {}", config.stage_id));
+    logv(c, format_strbuf!("mode: {}", config.mode));
+    logv(c, format_strbuf!("run_ignored: {}", config.run_ignored));
+    logv(c, format_strbuf!("filter: {}",
+                           opt_str(&config.filter
+                                          .as_ref()
+                                          .map(|re| {
+                                              re.to_str().into_strbuf()
+                                          }))));
+    logv(c, format_strbuf!("runtool: {}", opt_str(&config.runtool)));
+    logv(c, format_strbuf!("host-rustcflags: {}",
+                           opt_str(&config.host_rustcflags)));
+    logv(c, format_strbuf!("target-rustcflags: {}",
+                           opt_str(&config.target_rustcflags)));
+    logv(c, format_strbuf!("jit: {}", config.jit));
+    logv(c, format_strbuf!("target: {}", config.target));
+    logv(c, format_strbuf!("host: {}", config.host));
+    logv(c, format_strbuf!("android-cross-path: {}",
+                           config.android_cross_path.display()));
+    logv(c, format_strbuf!("adb_path: {}", config.adb_path));
+    logv(c, format_strbuf!("adb_test_dir: {}", config.adb_test_dir));
+    logv(c, format_strbuf!("adb_device_status: {}",
+                           config.adb_device_status));
     match config.test_shard {
-        None => logv(c, "test_shard: (all)".to_owned()),
-        Some((a,b)) => logv(c, format!("test_shard: {}.{}", a, b))
+        None => logv(c, "test_shard: (all)".to_strbuf()),
+        Some((a,b)) => logv(c, format_strbuf!("test_shard: {}.{}", a, b))
     }
-    logv(c, format!("verbose: {}", config.verbose));
-    logv(c, format!("\n"));
+    logv(c, format_strbuf!("verbose: {}", config.verbose));
+    logv(c, format_strbuf!("\n"));
 }
 
-pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
+pub fn opt_str<'a>(maybestr: &'a Option<StrBuf>) -> &'a str {
     match *maybestr {
         None => "(none)",
-        Some(ref s) => {
-            let s: &'a str = *s;
-            s
-        }
+        Some(ref s) => s.as_slice(),
     }
 }
 
-pub fn opt_str2(maybestr: Option<~str>) -> ~str {
-    match maybestr { None => "(none)".to_owned(), Some(s) => { s } }
+pub fn opt_str2(maybestr: Option<StrBuf>) -> StrBuf {
+    match maybestr {
+        None => "(none)".to_strbuf(),
+        Some(s) => s,
+    }
 }
 
 pub fn run_tests(config: &Config) {
-    if config.target == "arm-linux-androideabi".to_owned() {
+    if config.target.as_slice() == "arm-linux-androideabi" {
         match config.mode {
             DebugInfoGdb => {
                 println!("arm-linux-androideabi debug-info \
@@ -238,7 +273,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
     test::TestOpts {
         filter: match config.filter {
             None => None,
-            Some(ref filter) => Some(filter.to_strbuf()),
+            Some(ref filter) => Some(filter.clone()),
         },
         run_ignored: config.run_ignored,
         logfile: config.logfile.clone(),
@@ -311,11 +346,11 @@ pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
 pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
 
     // Try to elide redundant long paths
-    fn shorten(path: &Path) -> ~str {
+    fn shorten(path: &Path) -> StrBuf {
         let filename = path.filename_str();
         let p = path.dir_path();
         let dir = p.filename_str();
-        format!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
+        format_strbuf!("{}/{}", dir.unwrap_or(""), filename.unwrap_or(""))
     }
 
     test::DynTestName(format_strbuf!("[{}] {}",
@@ -326,14 +361,16 @@ fn shorten(path: &Path) -> ~str {
 pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
     let config = (*config).clone();
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let testfile = testfile.as_str().unwrap().to_owned();
-    test::DynTestFn(proc() { runtest::run(config, testfile) })
+    let testfile = testfile.as_str().unwrap().to_strbuf();
+    test::DynTestFn(proc() {
+        runtest::run(config, testfile)
+    })
 }
 
 pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
     let config = (*config).clone();
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let testfile = testfile.as_str().unwrap().to_owned();
+    let testfile = testfile.as_str().unwrap().to_strbuf();
     test::DynMetricFn(proc(mm) {
         runtest::run_metrics(config, testfile, mm)
     })
index 9300cee432ff44a177e2e3c8b7a649294979ab95..4e65115caa2bec6fcbeab9e8eee2cf9f563268a9 100644 (file)
@@ -12,8 +12,8 @@
 
 pub struct ExpectedError {
     pub line: uint,
-    pub kind: ~str,
-    pub msg: ~str,
+    pub kind: StrBuf,
+    pub msg: StrBuf,
 }
 
 // Load any test directives embedded in the file
@@ -23,17 +23,18 @@ pub fn load_errors(testfile: &Path) -> Vec<ExpectedError> {
     let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
     let mut line_num = 1u;
     for ln in rdr.lines() {
-        error_patterns.push_all_move(parse_expected(line_num, ln.unwrap()));
+        error_patterns.push_all_move(parse_expected(line_num,
+                                                    ln.unwrap().to_strbuf()));
         line_num += 1u;
     }
     return error_patterns;
 }
 
-fn parse_expected(line_num: uint, line: ~str) -> Vec<ExpectedError> {
-    let line = line.trim();
-    let error_tag = "//~".to_owned();
+fn parse_expected(line_num: uint, line: StrBuf) -> Vec<ExpectedError> {
+    let line = line.as_slice().trim().to_strbuf();
+    let error_tag = "//~".to_strbuf();
     let mut idx;
-    match line.find_str(error_tag) {
+    match line.as_slice().find_str(error_tag.as_slice()) {
       None => return Vec::new(),
       Some(nn) => { idx = (nn as uint) + error_tag.len(); }
     }
@@ -42,25 +43,34 @@ fn parse_expected(line_num: uint, line: ~str) -> Vec<ExpectedError> {
     // three lines above current line:
     let mut adjust_line = 0u;
     let len = line.len();
-    while idx < len && line[idx] == ('^' as u8) {
+    while idx < len && line.as_slice()[idx] == ('^' as u8) {
         adjust_line += 1u;
         idx += 1u;
     }
 
     // Extract kind:
-    while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
+    while idx < len && line.as_slice()[idx] == (' ' as u8) {
+        idx += 1u;
+    }
     let start_kind = idx;
-    while idx < len && line[idx] != (' ' as u8) { idx += 1u; }
+    while idx < len && line.as_slice()[idx] != (' ' as u8) {
+        idx += 1u;
+    }
 
-    let kind = line.slice(start_kind, idx);
-    let kind = kind.to_ascii().to_lower().into_str();
+    let kind = line.as_slice().slice(start_kind, idx);
+    let kind = kind.to_ascii().to_lower().into_str().to_strbuf();
 
     // Extract msg:
-    while idx < len && line[idx] == (' ' as u8) { idx += 1u; }
-    let msg = line.slice(idx, len).to_owned();
+    while idx < len && line.as_slice()[idx] == (' ' as u8) {
+        idx += 1u;
+    }
+    let msg = line.as_slice().slice(idx, len).to_strbuf();
 
     debug!("line={} kind={} msg={}", line_num - adjust_line, kind, msg);
 
-    return vec!(ExpectedError{line: line_num - adjust_line, kind: kind,
-                           msg: msg});
+    return vec!(ExpectedError{
+        line: line_num - adjust_line,
+        kind: kind,
+        msg: msg,
+    });
 }
index 047be9554774632734624f18a845ef6fb8573879..5729a11d7ad7ef0862131a798607612d810f396a 100644 (file)
 
 pub struct TestProps {
     // Lines that should be expected, in order, on standard out
-    pub error_patterns: Vec<~str> ,
+    pub error_patterns: Vec<StrBuf> ,
     // Extra flags to pass to the compiler
-    pub compile_flags: Option<~str>,
+    pub compile_flags: Option<StrBuf>,
     // Extra flags to pass when the compiled code is run (such as --bench)
-    pub run_flags: Option<~str>,
+    pub run_flags: Option<StrBuf>,
     // If present, the name of a file that this test should match when
     // pretty-printed
     pub pp_exact: Option<Path>,
     // Modules from aux directory that should be compiled
-    pub aux_builds: Vec<~str> ,
+    pub aux_builds: Vec<StrBuf> ,
     // Environment settings to use during execution
-    pub exec_env: Vec<(~str,~str)> ,
+    pub exec_env: Vec<(StrBuf,StrBuf)> ,
     // Lines to check if they appear in the expected debugger output
-    pub check_lines: Vec<~str> ,
+    pub check_lines: Vec<StrBuf> ,
     // Flag to force a crate to be built with the host architecture
     pub force_host: bool,
     // Check stdout for error-pattern output as well as stderr
@@ -119,22 +119,30 @@ pub fn load_props(testfile: &Path) -> TestProps {
 }
 
 pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
-    fn ignore_target(config: &Config) -> ~str {
-        "ignore-".to_owned() + util::get_os(config.target)
+    fn ignore_target(config: &Config) -> StrBuf {
+        format_strbuf!("ignore-{}", util::get_os(config.target.as_slice()))
     }
-    fn ignore_stage(config: &Config) -> ~str {
-        "ignore-".to_owned() + config.stage_id.split('-').next().unwrap()
+    fn ignore_stage(config: &Config) -> StrBuf {
+        format_strbuf!("ignore-{}",
+                       config.stage_id.as_slice().split('-').next().unwrap())
     }
 
     let val = iter_header(testfile, |ln| {
-        if parse_name_directive(ln, "ignore-test") { false }
-        else if parse_name_directive(ln, ignore_target(config)) { false }
-        else if parse_name_directive(ln, ignore_stage(config)) { false }
-        else if config.mode == common::Pretty &&
-            parse_name_directive(ln, "ignore-pretty") { false }
-        else if config.target != config.host &&
-            parse_name_directive(ln, "ignore-cross-compile") { false }
-        else { true }
+        if parse_name_directive(ln, "ignore-test") {
+            false
+        } else if parse_name_directive(ln, ignore_target(config).as_slice()) {
+            false
+        } else if parse_name_directive(ln, ignore_stage(config).as_slice()) {
+            false
+        } else if config.mode == common::Pretty &&
+                parse_name_directive(ln, "ignore-pretty") {
+            false
+        } else if config.target != config.host &&
+                parse_name_directive(ln, "ignore-cross-compile") {
+            false
+        } else {
+            true
+        }
     });
 
     !val
@@ -156,24 +164,24 @@ fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
     return true;
 }
 
-fn parse_error_pattern(line: &str) -> Option<~str> {
-    parse_name_value_directive(line, "error-pattern".to_owned())
+fn parse_error_pattern(line: &str) -> Option<StrBuf> {
+    parse_name_value_directive(line, "error-pattern".to_strbuf())
 }
 
-fn parse_aux_build(line: &str) -> Option<~str> {
-    parse_name_value_directive(line, "aux-build".to_owned())
+fn parse_aux_build(line: &str) -> Option<StrBuf> {
+    parse_name_value_directive(line, "aux-build".to_strbuf())
 }
 
-fn parse_compile_flags(line: &str) -> Option<~str> {
-    parse_name_value_directive(line, "compile-flags".to_owned())
+fn parse_compile_flags(line: &str) -> Option<StrBuf> {
+    parse_name_value_directive(line, "compile-flags".to_strbuf())
 }
 
-fn parse_run_flags(line: &str) -> Option<~str> {
-    parse_name_value_directive(line, "run-flags".to_owned())
+fn parse_run_flags(line: &str) -> Option<StrBuf> {
+    parse_name_value_directive(line, "run-flags".to_strbuf())
 }
 
-fn parse_check_line(line: &str) -> Option<~str> {
-    parse_name_value_directive(line, "check".to_owned())
+fn parse_check_line(line: &str) -> Option<StrBuf> {
+    parse_name_value_directive(line, "check".to_strbuf())
 }
 
 fn parse_force_host(line: &str) -> bool {
@@ -192,13 +200,16 @@ fn parse_no_pretty_expanded(line: &str) -> bool {
     parse_name_directive(line, "no-pretty-expanded")
 }
 
-fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
-    parse_name_value_directive(line, "exec-env".to_owned()).map(|nv| {
+fn parse_exec_env(line: &str) -> Option<(StrBuf, StrBuf)> {
+    parse_name_value_directive(line, "exec-env".to_strbuf()).map(|nv| {
         // nv is either FOO or FOO=BAR
-        let mut strs: Vec<~str> = nv.splitn('=', 1).map(|s| s.to_owned()).collect();
+        let mut strs: Vec<StrBuf> = nv.as_slice()
+                                      .splitn('=', 1)
+                                      .map(|s| s.to_strbuf())
+                                      .collect();
 
         match strs.len() {
-          1u => (strs.pop().unwrap(), "".to_owned()),
+          1u => (strs.pop().unwrap(), "".to_strbuf()),
           2u => {
               let end = strs.pop().unwrap();
               (strs.pop().unwrap(), end)
@@ -209,7 +220,7 @@ fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
 }
 
 fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
-    match parse_name_value_directive(line, "pp-exact".to_owned()) {
+    match parse_name_value_directive(line, "pp-exact".to_strbuf()) {
       Some(s) => Some(Path::new(s)),
       None => {
         if parse_name_directive(line, "pp-exact") {
@@ -225,14 +236,14 @@ fn parse_name_directive(line: &str, directive: &str) -> bool {
     line.contains(directive)
 }
 
-pub fn parse_name_value_directive(line: &str,
-                              directive: ~str) -> Option<~str> {
-    let keycolon = directive + ":";
-    match line.find_str(keycolon) {
+pub fn parse_name_value_directive(line: &str, directive: StrBuf)
+                                  -> Option<StrBuf> {
+    let keycolon = format_strbuf!("{}:", directive);
+    match line.find_str(keycolon.as_slice()) {
         Some(colon) => {
             let value = line.slice(colon + keycolon.len(),
-                                   line.len()).to_owned();
-            debug!("{}: {}", directive,  value);
+                                   line.len()).to_strbuf();
+            debug!("{}: {}", directive, value);
             Some(value)
         }
         None => None
index d3642a939db049a30c9c42a9ea561fe30b33a79c..9f62fd7096c1a62e8980da95e6bbdecf80f6d31c 100644 (file)
 
 use std::os;
 use std::str;
-use std::io::process::{ProcessExit, Process, ProcessConfig, ProcessOutput};
+use std::io::process::{ProcessExit, Command, Process, ProcessOutput};
 
 #[cfg(target_os = "win32")]
-fn target_env(lib_path: &str, prog: &str) -> Vec<(~str, ~str)> {
+fn target_env(lib_path: &str, prog: &str) -> Vec<(StrBuf, StrBuf)> {
     let env = os::env();
 
     // Make sure we include the aux directory in the path
@@ -22,14 +22,14 @@ fn target_env(lib_path: &str, prog: &str) -> Vec<(~str, ~str)> {
 
     let mut new_env: Vec<_> = env.move_iter().map(|(k, v)| {
         let new_v = if "PATH" == k {
-            format!("{};{};{}", v, lib_path, aux_path)
+            format_strbuf!("{};{};{}", v, lib_path, aux_path)
         } else {
-            v
+            v.to_strbuf()
         };
-        (k, new_v)
+        (k.to_strbuf(), new_v)
     }).collect();
     if prog.ends_with("rustc.exe") {
-        new_env.push(("RUST_THREADS".to_owned(), "1".to_owned()));
+        new_env.push(("RUST_THREADS".to_strbuf(), "1".to_strbuf()));
     }
     return new_env;
 }
@@ -37,11 +37,14 @@ fn target_env(lib_path: &str, prog: &str) -> Vec<(~str, ~str)> {
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
-fn target_env(lib_path: &str, prog: &str) -> Vec<(~str,~str)> {
+fn target_env(lib_path: &str, prog: &str) -> Vec<(StrBuf,StrBuf)> {
     // Make sure we include the aux directory in the path
     let aux_path = prog + ".libaux";
 
-    let mut env: Vec<(~str,~str)> = os::env().move_iter().collect();
+    let mut env: Vec<(StrBuf,StrBuf)> =
+        os::env().move_iter()
+                 .map(|(ref k, ref v)| (k.to_strbuf(), v.to_strbuf()))
+                 .collect();
     let var = if cfg!(target_os = "macos") {
         "DYLD_LIBRARY_PATH"
     } else {
@@ -49,33 +52,26 @@ fn target_env(lib_path: &str, prog: &str) -> Vec<(~str,~str)> {
     };
     let prev = match env.iter().position(|&(ref k, _)| k.as_slice() == var) {
         Some(i) => env.remove(i).unwrap().val1(),
-        None => "".to_owned(),
+        None => "".to_strbuf(),
     };
-    env.push((var.to_owned(), if prev.is_empty() {
-        lib_path + ":" + aux_path
+    env.push((var.to_strbuf(), if prev.is_empty() {
+        format_strbuf!("{}:{}", lib_path, aux_path)
     } else {
-        lib_path + ":" + aux_path + ":" + prev
+        format_strbuf!("{}:{}:{}", lib_path, aux_path, prev)
     }));
     return env;
 }
 
-pub struct Result {pub status: ProcessExit, pub out: ~str, pub err: ~str}
+pub struct Result {pub status: ProcessExit, pub out: StrBuf, pub err: StrBuf}
 
 pub fn run(lib_path: &str,
            prog: &str,
-           args: &[~str],
-           env: Vec<(~str, ~str)> ,
-           input: Option<~str>) -> Option<Result> {
+           args: &[StrBuf],
+           env: Vec<(StrBuf, StrBuf)> ,
+           input: Option<StrBuf>) -> Option<Result> {
 
     let env = env.clone().append(target_env(lib_path, prog).as_slice());
-    let opt_process = Process::configure(ProcessConfig {
-        program: prog,
-        args: args,
-        env: Some(env.as_slice()),
-        .. ProcessConfig::new()
-    });
-
-    match opt_process {
+    match Command::new(prog).args(args).env(env.as_slice()).spawn() {
         Ok(mut process) => {
             for input in input.iter() {
                 process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
@@ -85,8 +81,8 @@ pub fn run(lib_path: &str,
 
             Some(Result {
                 status: status,
-                out: str::from_utf8(output.as_slice()).unwrap().to_owned(),
-                err: str::from_utf8(error.as_slice()).unwrap().to_owned()
+                out: str::from_utf8(output.as_slice()).unwrap().to_strbuf(),
+                err: str::from_utf8(error.as_slice()).unwrap().to_strbuf()
             })
         },
         Err(..) => None
@@ -95,19 +91,12 @@ pub fn run(lib_path: &str,
 
 pub fn run_background(lib_path: &str,
            prog: &str,
-           args: &[~str],
-           env: Vec<(~str, ~str)> ,
-           input: Option<~str>) -> Option<Process> {
+           args: &[StrBuf],
+           env: Vec<(StrBuf, StrBuf)> ,
+           input: Option<StrBuf>) -> Option<Process> {
 
     let env = env.clone().append(target_env(lib_path, prog).as_slice());
-    let opt_process = Process::configure(ProcessConfig {
-        program: prog,
-        args: args,
-        env: Some(env.as_slice()),
-        .. ProcessConfig::new()
-    });
-
-    match opt_process {
+    match Command::new(prog).args(args).env(env.as_slice()).spawn() {
         Ok(mut process) => {
             for input in input.iter() {
                 process.stdin.get_mut_ref().write(input.as_bytes()).unwrap();
index dab1185435d9319c850a5e9ff1dcc95ab644f653..55c3b6a34e5a994381374a2563184549b4092c9a 100644 (file)
@@ -31,7 +31,7 @@
 use std::task;
 use test::MetricMap;
 
-pub fn run(config: Config, testfile: ~str) {
+pub fn run(config: Config, testfile: StrBuf) {
 
     match config.target.as_slice() {
 
@@ -48,7 +48,7 @@ pub fn run(config: Config, testfile: ~str) {
     run_metrics(config, testfile, &mut _mm);
 }
 
-pub fn run_metrics(config: Config, testfile: ~str, mm: &mut MetricMap) {
+pub fn run_metrics(config: Config, testfile: StrBuf, mm: &mut MetricMap) {
     if config.verbose {
         // We're going to be dumping a lot of info. Start on a new line.
         print!("\n\n");
@@ -72,7 +72,8 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
     let proc_res = compile_test(config, props, testfile);
 
     if proc_res.status.success() {
-        fatal_ProcRes("compile-fail test compiled successfully!".to_owned(), &proc_res);
+        fatal_ProcRes("compile-fail test compiled successfully!".to_strbuf(),
+                      &proc_res);
     }
 
     check_correct_failure_status(&proc_res);
@@ -80,7 +81,8 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) {
     let expected_errors = errors::load_errors(testfile);
     if !expected_errors.is_empty() {
         if !props.error_patterns.is_empty() {
-            fatal("both error pattern and expected errors specified".to_owned());
+            fatal("both error pattern and expected errors \
+                   specified".to_strbuf());
         }
         check_expected_errors(expected_errors, testfile, &proc_res);
     } else {
@@ -94,7 +96,7 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
         let proc_res = compile_test(config, props, testfile);
 
         if !proc_res.status.success() {
-            fatal_ProcRes("compilation failed!".to_owned(), &proc_res);
+            fatal_ProcRes("compilation failed!".to_strbuf(), &proc_res);
         }
 
         exec_compiled_test(config, props, testfile)
@@ -105,7 +107,8 @@ fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
     // The value our Makefile configures valgrind to return on failure
     static VALGRIND_ERR: int = 100;
     if proc_res.status.matches_exit_status(VALGRIND_ERR) {
-        fatal_ProcRes("run-fail test isn't valgrind-clean!".to_owned(), &proc_res);
+        fatal_ProcRes("run-fail test isn't valgrind-clean!".to_strbuf(),
+                      &proc_res);
     }
 
     check_correct_failure_status(&proc_res);
@@ -117,7 +120,8 @@ fn check_correct_failure_status(proc_res: &ProcRes) {
     static RUST_ERR: int = 101;
     if !proc_res.status.matches_exit_status(RUST_ERR) {
         fatal_ProcRes(
-            format!("failure produced the wrong error: {}", proc_res.status),
+            format_strbuf!("failure produced the wrong error: {}",
+                           proc_res.status),
             proc_res);
     }
 }
@@ -127,40 +131,49 @@ fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
         let mut proc_res = compile_test(config, props, testfile);
 
         if !proc_res.status.success() {
-            fatal_ProcRes("compilation failed!".to_owned(), &proc_res);
+            fatal_ProcRes("compilation failed!".to_strbuf(), &proc_res);
         }
 
         proc_res = exec_compiled_test(config, props, testfile);
 
         if !proc_res.status.success() {
-            fatal_ProcRes("test run failed!".to_owned(), &proc_res);
+            fatal_ProcRes("test run failed!".to_strbuf(), &proc_res);
         }
     } else {
         let proc_res = jit_test(config, props, testfile);
 
-        if !proc_res.status.success() { fatal_ProcRes("jit failed!".to_owned(), &proc_res); }
+        if !proc_res.status.success() {
+            fatal_ProcRes("jit failed!".to_strbuf(), &proc_res);
+        }
     }
 }
 
 fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
     if props.pp_exact.is_some() {
-        logv(config, "testing for exact pretty-printing".to_owned());
-    } else { logv(config, "testing for converging pretty-printing".to_owned()); }
+        logv(config, "testing for exact pretty-printing".to_strbuf());
+    } else {
+        logv(config, "testing for converging pretty-printing".to_strbuf());
+    }
 
     let rounds =
         match props.pp_exact { Some(_) => 1, None => 2 };
 
     let src = File::open(testfile).read_to_end().unwrap();
-    let src = str::from_utf8(src.as_slice()).unwrap().to_owned();
+    let src = str::from_utf8(src.as_slice()).unwrap().to_strbuf();
     let mut srcs = vec!(src);
 
     let mut round = 0;
     while round < rounds {
-        logv(config, format!("pretty-printing round {}", round));
-        let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "normal");
+        logv(config, format_strbuf!("pretty-printing round {}", round));
+        let proc_res = print_source(config,
+                                    props,
+                                    testfile,
+                                    (*srcs.get(round)).to_strbuf(),
+                                    "normal");
 
         if !proc_res.status.success() {
-            fatal_ProcRes(format!("pretty-printing failed in round {}", round),
+            fatal_ProcRes(format_strbuf!("pretty-printing failed in round {}",
+                                         round),
                           &proc_res);
         }
 
@@ -173,7 +186,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
         Some(ref file) => {
             let filepath = testfile.dir_path().join(file);
             let s = File::open(&filepath).read_to_end().unwrap();
-            str::from_utf8(s.as_slice()).unwrap().to_owned()
+            str::from_utf8(s.as_slice()).unwrap().to_strbuf()
           }
           None => { (*srcs.get(srcs.len() - 2u)).clone() }
         };
@@ -181,31 +194,35 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
 
     if props.pp_exact.is_some() {
         // Now we have to care about line endings
-        let cr = "\r".to_owned();
-        actual = actual.replace(cr, "");
-        expected = expected.replace(cr, "");
+        let cr = "\r".to_strbuf();
+        actual = actual.replace(cr.as_slice(), "").to_strbuf();
+        expected = expected.replace(cr.as_slice(), "").to_strbuf();
     }
 
-    compare_source(expected, actual);
+    compare_source(expected.as_slice(), actual.as_slice());
 
     // Finally, let's make sure it actually appears to remain valid code
     let proc_res = typecheck_source(config, props, testfile, actual);
 
     if !proc_res.status.success() {
-        fatal_ProcRes("pretty-printed source does not typecheck".to_owned(), &proc_res);
+        fatal_ProcRes("pretty-printed source does not typecheck".to_strbuf(),
+                      &proc_res);
     }
     if props.no_pretty_expanded { return }
 
     // additionally, run `--pretty expanded` and try to build it.
     let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "expanded");
     if !proc_res.status.success() {
-        fatal_ProcRes(format!("pretty-printing (expanded) failed"), &proc_res);
+        fatal_ProcRes(format_strbuf!("pretty-printing (expanded) failed"),
+                                     &proc_res);
     }
 
     let ProcRes{ stdout: expanded_src, .. } = proc_res;
     let proc_res = typecheck_source(config, props, testfile, expanded_src);
     if !proc_res.status.success() {
-        fatal_ProcRes(format!("pretty-printed source (expanded) does not typecheck"), &proc_res);
+        fatal_ProcRes(format_strbuf!("pretty-printed source (expanded) does \
+                                      not typecheck"),
+                      &proc_res);
     }
 
     return;
@@ -213,30 +230,43 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
     fn print_source(config: &Config,
                     props: &TestProps,
                     testfile: &Path,
-                    src: ~str,
+                    src: StrBuf,
                     pretty_type: &str) -> ProcRes {
-        compose_and_run(config, testfile,
-                        make_pp_args(config, props, testfile, pretty_type.to_owned()),
-                        props.exec_env.clone(), config.compile_lib_path, Some(src))
+        compose_and_run(config,
+                        testfile,
+                        make_pp_args(config,
+                                     props,
+                                     testfile,
+                                     pretty_type.to_strbuf()),
+                        props.exec_env.clone(),
+                        config.compile_lib_path.as_slice(),
+                        Some(src))
     }
 
     fn make_pp_args(config: &Config,
                     props: &TestProps,
                     testfile: &Path,
-                    pretty_type: ~str) -> ProcArgs {
+                    pretty_type: StrBuf) -> ProcArgs {
         let aux_dir = aux_output_dir_name(config, testfile);
         // FIXME (#9639): This needs to handle non-utf8 paths
-        let mut args = vec!("-".to_owned(), "--pretty".to_owned(), pretty_type,
-                            "--target=".to_owned() + config.target,
-                            "-L".to_owned(), aux_dir.as_str().unwrap().to_owned());
+        let mut args = vec!("-".to_strbuf(),
+                            "--pretty".to_strbuf(),
+                            pretty_type,
+                            format_strbuf!("--target={}", config.target),
+                            "-L".to_strbuf(),
+                            aux_dir.as_str().unwrap().to_strbuf());
         args.push_all_move(split_maybe_args(&config.target_rustcflags));
         args.push_all_move(split_maybe_args(&props.compile_flags));
-        return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
+        return ProcArgs {
+            prog: config.rustc_path.as_str().unwrap().to_strbuf(),
+            args: args,
+        };
     }
 
     fn compare_source(expected: &str, actual: &str) {
         if expected != actual {
-            error("pretty-printed source does not match expected source".to_owned());
+            error("pretty-printed source does not match expected \
+                   source".to_strbuf());
             println!("\n\
 expected:\n\
 ------------------------------------------\n\
@@ -253,7 +283,7 @@ fn compare_source(expected: &str, actual: &str) {
     }
 
     fn typecheck_source(config: &Config, props: &TestProps,
-                        testfile: &Path, src: ~str) -> ProcRes {
+                        testfile: &Path, src: StrBuf) -> ProcRes {
         let args = make_typecheck_args(config, props, testfile);
         compose_and_run_compiler(config, props, testfile, args, Some(src))
     }
@@ -266,16 +296,21 @@ fn make_typecheck_args(config: &Config, props: &TestProps, testfile: &Path) -> P
             config.target.as_slice()
         };
         // FIXME (#9639): This needs to handle non-utf8 paths
-        let mut args = vec!("-".to_owned(),
-                         "--no-trans".to_owned(), "--crate-type=lib".to_owned(),
-                         "--target=".to_owned() + target,
-                         "-L".to_owned(), config.build_base.as_str().unwrap().to_owned(),
-                         "-L".to_owned(),
-                         aux_dir.as_str().unwrap().to_owned());
+        let mut args = vec!("-".to_strbuf(),
+                            "--no-trans".to_strbuf(),
+                            "--crate-type=lib".to_strbuf(),
+                            format_strbuf!("--target={}", target),
+                            "-L".to_strbuf(),
+                            config.build_base.as_str().unwrap().to_strbuf(),
+                            "-L".to_strbuf(),
+                            aux_dir.as_str().unwrap().to_strbuf());
         args.push_all_move(split_maybe_args(&config.target_rustcflags));
         args.push_all_move(split_maybe_args(&props.compile_flags));
         // FIXME (#9639): This needs to handle non-utf8 paths
-        return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
+        return ProcArgs {
+            prog: config.rustc_path.as_str().unwrap().to_strbuf(),
+            args: args,
+        };
     }
 }
 
@@ -288,12 +323,12 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
 
     let config = &mut config;
     let DebuggerCommands { commands, check_lines, .. } = parse_debugger_commands(testfile, "gdb");
-    let mut cmds = commands.connect("\n");
+    let mut cmds = commands.connect("\n").to_strbuf();
 
     // compile test file (it shoud have 'compile-flags:-g' in the header)
     let compiler_run_result = compile_test(config, props, testfile);
     if !compiler_run_result.status.success() {
-        fatal_ProcRes("compilation failed!".to_owned(), &compiler_run_result);
+        fatal_ProcRes("compilation failed!".to_strbuf(), &compiler_run_result);
     }
 
     let exe_file = make_exe_name(config, testfile);
@@ -303,38 +338,64 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
     match config.target.as_slice() {
         "arm-linux-androideabi" => {
 
-            cmds = cmds.replace("run","continue");
+            cmds = cmds.replace("run", "continue").to_strbuf();
 
             // write debugger script
-            let script_str = ["set charset UTF-8".to_owned(),
-                              format!("file {}",exe_file.as_str().unwrap().to_owned()),
-                              "target remote :5039".to_owned(),
+            let script_str = ["set charset UTF-8".to_strbuf(),
+                              format_strbuf!("file {}",
+                                             exe_file.as_str()
+                                                     .unwrap()
+                                                     .to_strbuf()),
+                              "target remote :5039".to_strbuf(),
                               cmds,
-                              "quit".to_owned()].connect("\n");
+                              "quit".to_strbuf()].connect("\n");
             debug!("script_str = {}", script_str);
             dump_output_file(config, testfile, script_str, "debugger.script");
 
 
-            procsrv::run("", config.adb_path,
-                         ["push".to_owned(), exe_file.as_str().unwrap().to_owned(),
-                          config.adb_test_dir.clone()],
-                         vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-                .expect(format!("failed to exec `{}`", config.adb_path));
-
-            procsrv::run("", config.adb_path,
-                         ["forward".to_owned(), "tcp:5039".to_owned(), "tcp:5039".to_owned()],
-                         vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-                .expect(format!("failed to exec `{}`", config.adb_path));
-
-            let adb_arg = format!("export LD_LIBRARY_PATH={}; gdbserver :5039 {}/{}",
-                                  config.adb_test_dir.clone(), config.adb_test_dir.clone(),
-                                  str::from_utf8(exe_file.filename().unwrap()).unwrap());
-
-            let mut process = procsrv::run_background("", config.adb_path,
-                                                      ["shell".to_owned(),adb_arg.clone()],
-                                                      vec!(("".to_owned(),"".to_owned())),
-                                                      Some("".to_owned()))
-                .expect(format!("failed to exec `{}`", config.adb_path));
+            procsrv::run("",
+                         config.adb_path.as_slice(),
+                         [
+                            "push".to_strbuf(),
+                            exe_file.as_str().unwrap().to_strbuf(),
+                            config.adb_test_dir.clone()
+                         ],
+                         vec!(("".to_strbuf(), "".to_strbuf())),
+                         Some("".to_strbuf()))
+                .expect(format_strbuf!("failed to exec `{}`",
+                                       config.adb_path));
+
+            procsrv::run("",
+                         config.adb_path.as_slice(),
+                         [
+                            "forward".to_strbuf(),
+                            "tcp:5039".to_strbuf(),
+                            "tcp:5039".to_strbuf()
+                         ],
+                         vec!(("".to_strbuf(), "".to_strbuf())),
+                         Some("".to_strbuf()))
+                .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
+
+            let adb_arg = format_strbuf!("export LD_LIBRARY_PATH={}; \
+                                          gdbserver :5039 {}/{}",
+                                         config.adb_test_dir.clone(),
+                                         config.adb_test_dir.clone(),
+                                         str::from_utf8(
+                                             exe_file.filename()
+                                             .unwrap()).unwrap());
+
+            let mut process = procsrv::run_background("",
+                                                      config.adb_path
+                                                            .as_slice(),
+                                                      [
+                                                        "shell".to_strbuf(),
+                                                        adb_arg.clone()
+                                                      ],
+                                                      vec!(("".to_strbuf(),
+                                                            "".to_strbuf())),
+                                                      Some("".to_strbuf()))
+                .expect(format_strbuf!("failed to exec `{}`",
+                                       config.adb_path));
             loop {
                 //waiting 1 second for gdbserver start
                 timer::sleep(1000);
@@ -349,27 +410,34 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
 
             let tool_path = match config.android_cross_path.as_str() {
                 Some(x) => x.to_strbuf(),
-                None => fatal("cannot find android cross path".to_owned())
+                None => fatal("cannot find android cross path".to_strbuf())
             };
 
             let debugger_script = make_out_name(config, testfile, "debugger.script");
             // FIXME (#9639): This needs to handle non-utf8 paths
-            let debugger_opts = vec!("-quiet".to_owned(), "-batch".to_owned(), "-nx".to_owned(),
-                                  "-command=" + debugger_script.as_str().unwrap().to_owned());
+            let debugger_opts =
+                vec!("-quiet".to_strbuf(),
+                     "-batch".to_strbuf(),
+                     "-nx".to_strbuf(),
+                     format_strbuf!("-command={}",
+                                    debugger_script.as_str().unwrap()));
 
             let gdb_path = tool_path.append("/bin/arm-linux-androideabi-gdb");
-            let procsrv::Result{ out, err, status }=
-                procsrv::run("",
+            let procsrv::Result {
+                out,
+                err,
+                status
+            } = procsrv::run("",
                              gdb_path.as_slice(),
                              debugger_opts.as_slice(),
-                             vec!(("".to_owned(),"".to_owned())),
+                             vec!(("".to_strbuf(), "".to_strbuf())),
                              None)
-                .expect(format!("failed to exec `{}`", gdb_path));
+                .expect(format_strbuf!("failed to exec `{}`", gdb_path));
             let cmdline = {
                 let cmdline = make_cmdline("",
                                            "arm-linux-androideabi-gdb",
                                            debugger_opts.as_slice());
-                logv(config, format!("executing {}", cmdline));
+                logv(config, format_strbuf!("executing {}", cmdline));
                 cmdline
             };
 
@@ -384,25 +452,38 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
 
         _=> {
             // write debugger script
-            let script_str = ["set charset UTF-8".to_owned(),
+            let script_str = [
+                "set charset UTF-8".to_strbuf(),
                 cmds,
-                "quit\n".to_owned()].connect("\n");
+                "quit\n".to_strbuf()
+            ].connect("\n");
             debug!("script_str = {}", script_str);
             dump_output_file(config, testfile, script_str, "debugger.script");
 
             // run debugger script with gdb
             #[cfg(windows)]
-            fn debugger() -> ~str { "gdb.exe".to_owned() }
+            fn debugger() -> StrBuf {
+                "gdb.exe".to_strbuf()
+            }
             #[cfg(unix)]
-            fn debugger() -> ~str { "gdb".to_owned() }
+            fn debugger() -> StrBuf {
+                "gdb".to_strbuf()
+            }
 
             let debugger_script = make_out_name(config, testfile, "debugger.script");
 
             // FIXME (#9639): This needs to handle non-utf8 paths
-            let debugger_opts = vec!("-quiet".to_owned(), "-batch".to_owned(), "-nx".to_owned(),
-                "-command=" + debugger_script.as_str().unwrap().to_owned(),
-                exe_file.as_str().unwrap().to_owned());
-            proc_args = ProcArgs {prog: debugger(), args: debugger_opts};
+            let debugger_opts =
+                vec!("-quiet".to_strbuf(),
+                     "-batch".to_strbuf(),
+                     "-nx".to_strbuf(),
+                     format_strbuf!("-command={}",
+                                    debugger_script.as_str().unwrap()),
+                     exe_file.as_str().unwrap().to_strbuf());
+            proc_args = ProcArgs {
+                prog: debugger(),
+                args: debugger_opts,
+            };
             debugger_run_result = compose_and_run(config,
                                                   testfile,
                                                   proc_args,
@@ -413,17 +494,18 @@ fn debugger() -> ~str { "gdb".to_owned() }
     }
 
     if !debugger_run_result.status.success() {
-        fatal("gdb failed to execute".to_owned());
+        fatal("gdb failed to execute".to_strbuf());
     }
 
     check_debugger_output(&debugger_run_result, check_lines.as_slice());
 }
 
 fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
-    use std::io::process::{Process, ProcessConfig, ProcessOutput};
+    use std::io::process::{Command, ProcessOutput};
 
     if config.lldb_python_dir.is_none() {
-        fatal("Can't run LLDB test because LLDB's python path is not set.".to_owned());
+        fatal("Can't run LLDB test because LLDB's python path is not \
+               set.".to_strbuf());
     }
 
     let mut config = Config {
@@ -437,7 +519,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
     // compile test file (it shoud have 'compile-flags:-g' in the header)
     let compile_result = compile_test(config, props, testfile);
     if !compile_result.status.success() {
-        fatal_ProcRes("compilation failed!".to_owned(), &compile_result);
+        fatal_ProcRes("compilation failed!".to_strbuf(), &compile_result);
     }
 
     let exe_file = make_exe_name(config, testfile);
@@ -476,63 +558,54 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
     let debugger_run_result = run_lldb(config, &exe_file, &debugger_script);
 
     if !debugger_run_result.status.success() {
-        fatal_ProcRes("Error while running LLDB".to_owned(), &debugger_run_result);
+        fatal_ProcRes("Error while running LLDB".to_strbuf(),
+                      &debugger_run_result);
     }
 
     check_debugger_output(&debugger_run_result, check_lines.as_slice());
 
     fn run_lldb(config: &Config, test_executable: &Path, debugger_script: &Path) -> ProcRes {
         // Prepare the lldb_batchmode which executes the debugger script
-        let lldb_batchmode_script = "./src/etc/lldb_batchmode.py".to_owned();
-        let test_executable_str = test_executable.as_str().unwrap().to_owned();
-        let debugger_script_str = debugger_script.as_str().unwrap().to_owned();
-        let commandline = format!("python {} {} {}",
-                                  lldb_batchmode_script.as_slice(),
-                                  test_executable_str.as_slice(),
-                                  debugger_script_str.as_slice());
-
-        let args = &[lldb_batchmode_script, test_executable_str, debugger_script_str];
-        let env = &[("PYTHONPATH".to_owned(), config.lldb_python_dir.clone().unwrap())];
-
-        let opt_process = Process::configure(ProcessConfig {
-            program: "python",
-            args: args,
-            env: Some(env),
-            .. ProcessConfig::new()
-        });
+        let mut cmd = Command::new("python");
+        cmd.arg("./src/etc/lldb_batchmode.py")
+           .arg(test_executable)
+           .arg(debugger_script)
+           .env([("PYTHONPATH", config.lldb_python_dir.clone().unwrap().as_slice())]);
 
-        let (status, out, err) = match opt_process {
+        let (status, out, err) = match cmd.spawn() {
             Ok(process) => {
                 let ProcessOutput { status, output, error } =
                     process.wait_with_output().unwrap();
 
                 (status,
-                 str::from_utf8(output.as_slice()).unwrap().to_owned(),
-                 str::from_utf8(error.as_slice()).unwrap().to_owned())
+                 str::from_utf8(output.as_slice()).unwrap().to_strbuf(),
+                 str::from_utf8(error.as_slice()).unwrap().to_strbuf())
             },
             Err(e) => {
-                fatal(format!("Failed to setup Python process for LLDB script: {}", e))
+                fatal(format_strbuf!("Failed to setup Python process for \
+                                      LLDB script: {}",
+                                     e))
             }
         };
 
-        dump_output(config, test_executable, out, err);
+        dump_output(config, test_executable, out.as_slice(), err.as_slice());
         return ProcRes {
             status: status,
             stdout: out,
             stderr: err,
-            cmdline: commandline
+            cmdline: format_strbuf!("{}", cmd)
         };
     }
 }
 
-struct DebuggerCommands
-{
-    commands: Vec<~str>,
-    check_lines: Vec<~str>,
-    breakpoint_lines: Vec<uint>
+struct DebuggerCommands {
+    commands: Vec<StrBuf>,
+    check_lines: Vec<StrBuf>,
+    breakpoint_lines: Vec<uint>,
 }
 
-fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) -> DebuggerCommands {
+fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
+                           -> DebuggerCommands {
     use std::io::{BufferedReader, File};
 
     let command_directive = debugger_prefix + "-command";
@@ -550,14 +623,22 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) -> DebuggerC
                     breakpoint_lines.push(counter);
                 }
 
-                header::parse_name_value_directive(line, command_directive.clone())
-                    .map(|cmd| commands.push(cmd));
+                header::parse_name_value_directive(
+                        line,
+                        command_directive.to_strbuf()).map(|cmd| {
+                    commands.push(cmd)
+                });
 
-                header::parse_name_value_directive(line, check_directive.clone())
-                    .map(|cmd| check_lines.push(cmd));
+                header::parse_name_value_directive(
+                        line,
+                        check_directive.to_strbuf()).map(|cmd| {
+                    check_lines.push(cmd)
+                });
             }
             Err(e) => {
-                fatal(format!("Error while parsing debugger commands: {}", e))
+                fatal(format_strbuf!("Error while parsing debugger commands: \
+                                      {}",
+                                     e))
             }
         }
         counter += 1;
@@ -570,41 +651,55 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str) -> DebuggerC
     }
 }
 
-fn cleanup_debug_info_options(options: &Option<~str>) -> Option<~str> {
+fn cleanup_debug_info_options(options: &Option<StrBuf>) -> Option<StrBuf> {
     if options.is_none() {
         return None;
     }
 
     // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
-    let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
-    let new_options = split_maybe_args(options).move_iter()
-                                               .filter(|x| !options_to_remove.contains(x))
-                                               .collect::<Vec<~str>>()
-                                               .connect(" ");
+    let options_to_remove = [
+        "-O".to_strbuf(),
+        "-g".to_strbuf(),
+        "--debuginfo".to_strbuf()
+    ];
+    let new_options =
+        split_maybe_args(options).move_iter()
+                                 .filter(|x| !options_to_remove.contains(x))
+                                 .collect::<Vec<StrBuf>>()
+                                 .connect(" ")
+                                 .to_strbuf();
     Some(new_options)
 }
 
-fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[~str]) {
+fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[StrBuf]) {
     let num_check_lines = check_lines.len();
     if num_check_lines > 0 {
         // Allow check lines to leave parts unspecified (e.g., uninitialized
         // bits in the wrong case of an enum) with the notation "[...]".
-        let check_fragments: Vec<Vec<~str>> =
+        let check_fragments: Vec<Vec<StrBuf>> =
             check_lines.iter().map(|s| {
-                s.trim().split_str("[...]").map(|x| x.to_str()).collect()
+                s.as_slice()
+                 .trim()
+                 .split_str("[...]")
+                 .map(|x| x.to_strbuf())
+                 .collect()
             }).collect();
         // check if each line in props.check_lines appears in the
         // output (in order)
         let mut i = 0u;
-        for line in debugger_run_result.stdout.lines() {
+        for line in debugger_run_result.stdout.as_slice().lines() {
             let mut rest = line.trim();
             let mut first = true;
             let mut failed = false;
             for frag in check_fragments.get(i).iter() {
                 let found = if first {
-                    if rest.starts_with(*frag) { Some(0) } else { None }
+                    if rest.starts_with(frag.as_slice()) {
+                        Some(0)
+                    } else {
+                        None
+                    }
                 } else {
-                    rest.find_str(*frag)
+                    rest.find_str(frag.as_slice())
                 };
                 match found {
                     None => {
@@ -626,8 +721,10 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[~str]) {
             }
         }
         if i != num_check_lines {
-            fatal_ProcRes(format!("line not found in debugger output: {}",
-                                  check_lines.get(i).unwrap()), debugger_run_result);
+            fatal_ProcRes(format_strbuf!("line not found in debugger output: \
+                                          {}",
+                                         check_lines.get(i).unwrap()),
+                          debugger_run_result);
         }
     }
 }
@@ -636,24 +733,24 @@ fn check_error_patterns(props: &TestProps,
                         testfile: &Path,
                         proc_res: &ProcRes) {
     if props.error_patterns.is_empty() {
-        fatal("no error pattern specified in ".to_owned() +
-              testfile.display().as_maybe_owned().as_slice());
+        fatal(format_strbuf!("no error pattern specified in {}",
+                             testfile.display().as_maybe_owned().as_slice()));
     }
 
     if proc_res.status.success() {
-        fatal("process did not return an error status".to_owned());
+        fatal("process did not return an error status".to_strbuf());
     }
 
     let mut next_err_idx = 0u;
     let mut next_err_pat = props.error_patterns.get(next_err_idx);
     let mut done = false;
     let output_to_check = if props.check_stdout {
-        proc_res.stdout + proc_res.stderr
+        format_strbuf!("{}{}", proc_res.stdout, proc_res.stderr)
     } else {
         proc_res.stderr.clone()
     };
-    for line in output_to_check.lines() {
-        if line.contains(*next_err_pat) {
+    for line in output_to_check.as_slice().lines() {
+        if line.contains(next_err_pat.as_slice()) {
             debug!("found error pattern {}", *next_err_pat);
             next_err_idx += 1u;
             if next_err_idx == props.error_patterns.len() {
@@ -669,20 +766,22 @@ fn check_error_patterns(props: &TestProps,
     let missing_patterns =
         props.error_patterns.slice(next_err_idx, props.error_patterns.len());
     if missing_patterns.len() == 1u {
-        fatal_ProcRes(format!("error pattern '{}' not found!",
-                              missing_patterns[0]), proc_res);
+        fatal_ProcRes(format_strbuf!("error pattern '{}' not found!",
+                                     missing_patterns[0]),
+                      proc_res);
     } else {
         for pattern in missing_patterns.iter() {
-            error(format!("error pattern '{}' not found!", *pattern));
+            error(format_strbuf!("error pattern '{}' not found!", *pattern));
         }
-        fatal_ProcRes("multiple error patterns not found".to_owned(), proc_res);
+        fatal_ProcRes("multiple error patterns not found".to_strbuf(),
+                      proc_res);
     }
 }
 
 fn check_no_compiler_crash(proc_res: &ProcRes) {
-    for line in proc_res.stderr.lines() {
+    for line in proc_res.stderr.as_slice().lines() {
         if line.starts_with("error: internal compiler error:") {
-            fatal_ProcRes("compiler encountered internal error".to_owned(),
+            fatal_ProcRes("compiler encountered internal error".to_strbuf(),
                           proc_res);
         }
     }
@@ -697,15 +796,15 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
         expected_errors.len(), false);
 
     if proc_res.status.success() {
-        fatal("process did not return an error status".to_owned());
+        fatal("process did not return an error status".to_strbuf());
     }
 
     let prefixes = expected_errors.iter().map(|ee| {
-        format!("{}:{}:", testfile.display(), ee.line)
-    }).collect::<Vec<~str> >();
+        format_strbuf!("{}:{}:", testfile.display(), ee.line)
+    }).collect::<Vec<StrBuf> >();
 
     #[cfg(target_os = "win32")]
-    fn to_lower( s : &str ) -> ~str {
+    fn to_lower( s : &str ) -> StrBuf {
         let i = s.chars();
         let c : Vec<char> = i.map( |c| {
             if c.is_ascii() {
@@ -714,12 +813,12 @@ fn to_lower( s : &str ) -> ~str {
                 c
             }
         } ).collect();
-        str::from_chars(c.as_slice())
+        str::from_chars(c.as_slice()).to_strbuf()
     }
 
     #[cfg(target_os = "win32")]
     fn prefix_matches( line : &str, prefix : &str ) -> bool {
-        to_lower(line).starts_with( to_lower(prefix) )
+        to_lower(line).as_slice().starts_with(to_lower(prefix).as_slice())
     }
 
     #[cfg(target_os = "linux")]
@@ -735,15 +834,18 @@ fn prefix_matches( line : &str, prefix : &str ) -> bool {
     //    filename:line1:col1: line2:col2: *warning:* msg
     // where line1:col1: is the starting point, line2:col2:
     // is the ending point, and * represents ANSI color codes.
-    for line in proc_res.stderr.lines() {
+    for line in proc_res.stderr.as_slice().lines() {
         let mut was_expected = false;
         for (i, ee) in expected_errors.iter().enumerate() {
             if !*found_flags.get(i) {
                 debug!("prefix={} ee.kind={} ee.msg={} line={}",
-                       *prefixes.get(i), ee.kind, ee.msg, line);
-                if prefix_matches(line, *prefixes.get(i)) &&
-                    line.contains(ee.kind) &&
-                    line.contains(ee.msg) {
+                       prefixes.get(i).as_slice(),
+                       ee.kind,
+                       ee.msg,
+                       line);
+                if prefix_matches(line, prefixes.get(i).as_slice()) &&
+                    line.contains(ee.kind.as_slice()) &&
+                    line.contains(ee.msg.as_slice()) {
                     *found_flags.get_mut(i) = true;
                     was_expected = true;
                     break;
@@ -757,8 +859,9 @@ fn prefix_matches( line : &str, prefix : &str ) -> bool {
         }
 
         if !was_expected && is_compiler_error_or_warning(line) {
-            fatal_ProcRes(format!("unexpected compiler error or warning: '{}'",
-                               line),
+            fatal_ProcRes(format_strbuf!("unexpected compiler error or \
+                                          warning: '{}'",
+                                         line),
                           proc_res);
         }
     }
@@ -766,8 +869,12 @@ fn prefix_matches( line : &str, prefix : &str ) -> bool {
     for (i, &flag) in found_flags.iter().enumerate() {
         if !flag {
             let ee = expected_errors.get(i);
-            fatal_ProcRes(format!("expected {} on line {} not found: {}",
-                               ee.kind, ee.line, ee.msg), proc_res);
+            fatal_ProcRes(format_strbuf!("expected {} on line {} not found: \
+                                          {}",
+                                         ee.kind,
+                                         ee.line,
+                                         ee.msg),
+                          proc_res);
         }
     }
 }
@@ -847,9 +954,17 @@ fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
     return true;
 }
 
-struct ProcArgs {prog: ~str, args: Vec<~str> }
+struct ProcArgs {
+    prog: StrBuf,
+    args: Vec<StrBuf>,
+}
 
-struct ProcRes {status: ProcessExit, stdout: ~str, stderr: ~str, cmdline: ~str}
+struct ProcRes {
+    status: ProcessExit,
+    stdout: StrBuf,
+    stderr: StrBuf,
+    cmdline: StrBuf,
+}
 
 fn compile_test(config: &Config, props: &TestProps,
                 testfile: &Path) -> ProcRes {
@@ -857,14 +972,15 @@ fn compile_test(config: &Config, props: &TestProps,
 }
 
 fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
-    compile_test_(config, props, testfile, ["--jit".to_owned()])
+    compile_test_(config, props, testfile, ["--jit".to_strbuf()])
 }
 
 fn compile_test_(config: &Config, props: &TestProps,
-                 testfile: &Path, extra_args: &[~str]) -> ProcRes {
+                 testfile: &Path, extra_args: &[StrBuf]) -> ProcRes {
     let aux_dir = aux_output_dir_name(config, testfile);
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let link_args = vec!("-L".to_owned(), aux_dir.as_str().unwrap().to_owned());
+    let link_args = vec!("-L".to_strbuf(),
+                         aux_dir.as_str().unwrap().to_strbuf());
     let args = make_compile_args(config,
                                  props,
                                  link_args.append(extra_args),
@@ -884,10 +1000,12 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
         }
 
         _=> {
-            compose_and_run(config, testfile,
+            compose_and_run(config,
+                            testfile,
                             make_run_args(config, props, testfile),
                             env,
-                            config.run_lib_path, None)
+                            config.run_lib_path.as_slice(),
+                            None)
         }
     }
 }
@@ -897,7 +1015,7 @@ fn compose_and_run_compiler(
     props: &TestProps,
     testfile: &Path,
     args: ProcArgs,
-    input: Option<~str>) -> ProcRes {
+    input: Option<StrBuf>) -> ProcRes {
 
     if !props.aux_builds.is_empty() {
         ensure_dir(&aux_output_dir_name(config, testfile));
@@ -913,37 +1031,48 @@ fn compose_and_run_compiler(
         let crate_type = if aux_props.no_prefer_dynamic {
             Vec::new()
         } else {
-            vec!("--crate-type=dylib".to_owned())
+            vec!("--crate-type=dylib".to_strbuf())
         };
         let aux_args =
             make_compile_args(config,
                               &aux_props,
-                              crate_type.append(extra_link_args.as_slice()),
+                              crate_type.append(
+                                  extra_link_args.iter()
+                                                 .map(|x| x.to_strbuf())
+                                                 .collect::<Vec<_>>()
+                                                 .as_slice()),
                               |a,b| {
                                   let f = make_lib_name(a, b, testfile);
                                   ThisDirectory(f.dir_path())
-                              }, &abs_ab);
-        let auxres = compose_and_run(config, &abs_ab, aux_args, Vec::new(),
-                                     config.compile_lib_path, None);
+                              },
+                              &abs_ab);
+        let auxres = compose_and_run(config,
+                                     &abs_ab,
+                                     aux_args,
+                                     Vec::new(),
+                                     config.compile_lib_path.as_slice(),
+                                     None);
         if !auxres.status.success() {
             fatal_ProcRes(
-                format!("auxiliary build of {} failed to compile: ",
-                     abs_ab.display()),
+                format_strbuf!("auxiliary build of {} failed to compile: ",
+                               abs_ab.display()),
                 &auxres);
         }
 
         match config.target.as_slice() {
-
             "arm-linux-androideabi" => {
                 _arm_push_aux_shared_library(config, testfile);
             }
-
-            _=> { }
+            _ => {}
         }
     }
 
-    compose_and_run(config, testfile, args, Vec::new(),
-                    config.compile_lib_path, input)
+    compose_and_run(config,
+                    testfile,
+                    args,
+                    Vec::new(),
+                    config.compile_lib_path.as_slice(),
+                    input)
 }
 
 fn ensure_dir(path: &Path) {
@@ -953,9 +1082,9 @@ fn ensure_dir(path: &Path) {
 
 fn compose_and_run(config: &Config, testfile: &Path,
                    ProcArgs{ args, prog }: ProcArgs,
-                   procenv: Vec<(~str, ~str)> ,
+                   procenv: Vec<(StrBuf, StrBuf)> ,
                    lib_path: &str,
-                   input: Option<~str>) -> ProcRes {
+                   input: Option<StrBuf>) -> ProcRes {
     return program_output(config, testfile, lib_path,
                           prog, args, procenv, input);
 }
@@ -967,7 +1096,7 @@ enum TargetLocation {
 
 fn make_compile_args(config: &Config,
                      props: &TestProps,
-                     extras: Vec<~str> ,
+                     extras: Vec<StrBuf> ,
                      xform: |&Config, &Path| -> TargetLocation,
                      testfile: &Path)
                      -> ProcArgs {
@@ -978,26 +1107,36 @@ fn make_compile_args(config: &Config,
         config.target.as_slice()
     };
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let mut args = vec!(testfile.as_str().unwrap().to_owned(),
-                     "-L".to_owned(), config.build_base.as_str().unwrap().to_owned(),
-                     "--target=".to_owned() + target);
+    let mut args = vec!(testfile.as_str().unwrap().to_strbuf(),
+                        "-L".to_strbuf(),
+                        config.build_base.as_str().unwrap().to_strbuf(),
+                        format_strbuf!("--target={}", target));
     args.push_all(extras.as_slice());
     if !props.no_prefer_dynamic {
-        args.push("-C".to_owned());
-        args.push("prefer-dynamic".to_owned());
+        args.push("-C".to_strbuf());
+        args.push("prefer-dynamic".to_strbuf());
     }
     let path = match xform_file {
-        ThisFile(path) => { args.push("-o".to_owned()); path }
-        ThisDirectory(path) => { args.push("--out-dir".to_owned()); path }
+        ThisFile(path) => {
+            args.push("-o".to_strbuf());
+            path
+        }
+        ThisDirectory(path) => {
+            args.push("--out-dir".to_strbuf());
+            path
+        }
     };
-    args.push(path.as_str().unwrap().to_owned());
+    args.push(path.as_str().unwrap().to_strbuf());
     if props.force_host {
         args.push_all_move(split_maybe_args(&config.host_rustcflags));
     } else {
         args.push_all_move(split_maybe_args(&config.target_rustcflags));
     }
     args.push_all_move(split_maybe_args(&props.compile_flags));
-    return ProcArgs {prog: config.rustc_path.as_str().unwrap().to_owned(), args: args};
+    return ProcArgs {
+        prog: config.rustc_path.as_str().unwrap().to_strbuf(),
+        args: args,
+    };
 }
 
 fn make_lib_name(config: &Config, auxfile: &Path, testfile: &Path) -> Path {
@@ -1026,64 +1165,88 @@ fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
     let exe_file = make_exe_name(config, testfile);
 
     // FIXME (#9639): This needs to handle non-utf8 paths
-    args.push(exe_file.as_str().unwrap().to_owned());
+    args.push(exe_file.as_str().unwrap().to_strbuf());
 
     // Add the arguments in the run_flags directive
     args.push_all_move(split_maybe_args(&props.run_flags));
 
     let prog = args.shift().unwrap();
-    return ProcArgs {prog: prog, args: args};
+    return ProcArgs {
+        prog: prog,
+        args: args,
+    };
 }
 
-fn split_maybe_args(argstr: &Option<~str>) -> Vec<~str> {
+fn split_maybe_args(argstr: &Option<StrBuf>) -> Vec<StrBuf> {
     match *argstr {
         Some(ref s) => {
-            s.split(' ')
-                .filter_map(|s| if s.is_whitespace() {None} else {Some(s.to_owned())})
-                .collect()
+            s.as_slice()
+             .split(' ')
+             .filter_map(|s| {
+                 if s.is_whitespace() {
+                     None
+                 } else {
+                     Some(s.to_strbuf())
+                 }
+             }).collect()
         }
         None => Vec::new()
     }
 }
 
-fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: ~str,
-                  args: Vec<~str> , env: Vec<(~str, ~str)> ,
-                  input: Option<~str>) -> ProcRes {
+fn program_output(config: &Config, testfile: &Path, lib_path: &str, prog: StrBuf,
+                  args: Vec<StrBuf> , env: Vec<(StrBuf, StrBuf)> ,
+                  input: Option<StrBuf>) -> ProcRes {
     let cmdline =
         {
-            let cmdline = make_cmdline(lib_path, prog, args.as_slice());
-            logv(config, format!("executing {}", cmdline));
+            let cmdline = make_cmdline(lib_path,
+                                       prog.as_slice(),
+                                       args.as_slice());
+            logv(config, format_strbuf!("executing {}", cmdline));
             cmdline
         };
-    let procsrv::Result{ out, err, status } =
-            procsrv::run(lib_path, prog, args.as_slice(), env, input)
-            .expect(format!("failed to exec `{}`", prog));
-    dump_output(config, testfile, out, err);
-    return ProcRes {status: status,
-         stdout: out,
-         stderr: err,
-         cmdline: cmdline};
+    let procsrv::Result {
+        out,
+        err,
+        status
+    } = procsrv::run(lib_path,
+                     prog.as_slice(),
+                     args.as_slice(),
+                     env,
+                     input).expect(format_strbuf!("failed to exec `{}`",
+                                                  prog));
+    dump_output(config, testfile, out.as_slice(), err.as_slice());
+    return ProcRes {
+        status: status,
+        stdout: out,
+        stderr: err,
+        cmdline: cmdline,
+    };
 }
 
 // Linux and mac don't require adjusting the library search path
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
-fn make_cmdline(_libpath: &str, prog: &str, args: &[~str]) -> ~str {
-    format!("{} {}", prog, args.connect(" "))
+fn make_cmdline(_libpath: &str, prog: &str, args: &[StrBuf]) -> StrBuf {
+    format_strbuf!("{} {}", prog, args.connect(" "))
 }
 
 #[cfg(target_os = "win32")]
-fn make_cmdline(libpath: &str, prog: &str, args: &[~str]) -> ~str {
-    format!("{} {} {}", lib_path_cmd_prefix(libpath), prog,
-         args.connect(" "))
+fn make_cmdline(libpath: &str, prog: &str, args: &[StrBuf]) -> StrBuf {
+    format_strbuf!("{} {} {}",
+                   lib_path_cmd_prefix(libpath),
+                   prog,
+                   args.connect(" "))
 }
 
 // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
 // for diagnostic purposes
 #[cfg(target_os = "win32")]
-fn lib_path_cmd_prefix(path: &str) -> ~str {
-    format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
+fn lib_path_cmd_prefix(path: &str) -> StrBuf {
+    format_strbuf!("{}=\"{}\"",
+                   util::lib_path_env_var(),
+                   util::make_new_path(path))
 }
 
 fn dump_output(config: &Config, testfile: &Path, out: &str, err: &str) {
@@ -1131,11 +1294,11 @@ fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
     }
 }
 
-fn error(err: ~str) { println!("\nerror: {}", err); }
+fn error(err: StrBuf) { println!("\nerror: {}", err); }
 
-fn fatal(err: ~str) -> ! { error(err); fail!(); }
+fn fatal(err: StrBuf) -> ! { error(err); fail!(); }
 
-fn fatal_ProcRes(err: ~str, proc_res: &ProcRes) -> ! {
+fn fatal_ProcRes(err: StrBuf, proc_res: &ProcRes) -> ! {
     print!("\n\
 error: {}\n\
 status: {}\n\
@@ -1154,63 +1317,85 @@ fn fatal_ProcRes(err: ~str, proc_res: &ProcRes) -> ! {
     fail!();
 }
 
-fn _arm_exec_compiled_test(config: &Config, props: &TestProps,
-                      testfile: &Path, env: Vec<(~str, ~str)> ) -> ProcRes {
-
+fn _arm_exec_compiled_test(config: &Config,
+                           props: &TestProps,
+                           testfile: &Path,
+                           env: Vec<(StrBuf, StrBuf)>)
+                           -> ProcRes {
     let args = make_run_args(config, props, testfile);
-    let cmdline = make_cmdline("", args.prog, args.args.as_slice());
+    let cmdline = make_cmdline("",
+                               args.prog.as_slice(),
+                               args.args.as_slice());
 
     // get bare program string
-    let mut tvec: Vec<~str> = args.prog.split('/').map(|ts| ts.to_owned()).collect();
+    let mut tvec: Vec<StrBuf> = args.prog
+                                    .as_slice()
+                                    .split('/')
+                                    .map(|ts| ts.to_strbuf())
+                                    .collect();
     let prog_short = tvec.pop().unwrap();
 
     // copy to target
-    let copy_result = procsrv::run("", config.adb_path,
-        ["push".to_owned(), args.prog.clone(), config.adb_test_dir.clone()],
-        vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-        .expect(format!("failed to exec `{}`", config.adb_path));
+    let copy_result = procsrv::run("",
+                                   config.adb_path.as_slice(),
+                                   [
+                                    "push".to_strbuf(),
+                                    args.prog.clone(),
+                                    config.adb_test_dir.clone()
+                                   ],
+                                   vec!(("".to_strbuf(), "".to_strbuf())),
+                                   Some("".to_strbuf()))
+        .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
 
     if config.verbose {
         println!("push ({}) {} {} {}",
-            config.target, args.prog,
-            copy_result.out, copy_result.err);
+                 config.target,
+                 args.prog,
+                 copy_result.out,
+                 copy_result.err);
     }
 
-    logv(config, format!("executing ({}) {}", config.target, cmdline));
+    logv(config, format_strbuf!("executing ({}) {}", config.target, cmdline));
 
     let mut runargs = Vec::new();
 
     // run test via adb_run_wrapper
-    runargs.push("shell".to_owned());
+    runargs.push("shell".to_strbuf());
     for (key, val) in env.move_iter() {
-        runargs.push(format!("{}={}", key, val));
+        runargs.push(format_strbuf!("{}={}", key, val));
     }
-    runargs.push(format!("{}/adb_run_wrapper.sh", config.adb_test_dir));
-    runargs.push(format!("{}", config.adb_test_dir));
-    runargs.push(format!("{}", prog_short));
+    runargs.push(format_strbuf!("{}/adb_run_wrapper.sh",
+                                config.adb_test_dir));
+    runargs.push(format_strbuf!("{}", config.adb_test_dir));
+    runargs.push(format_strbuf!("{}", prog_short));
 
     for tv in args.args.iter() {
-        runargs.push(tv.to_owned());
+        runargs.push(tv.to_strbuf());
     }
     procsrv::run("",
-                 config.adb_path,
+                 config.adb_path.as_slice(),
                  runargs.as_slice(),
-                 vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-        .expect(format!("failed to exec `{}`", config.adb_path));
+                 vec!(("".to_strbuf(), "".to_strbuf())), Some("".to_strbuf()))
+        .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
 
     // get exitcode of result
     runargs = Vec::new();
-    runargs.push("shell".to_owned());
-    runargs.push("cat".to_owned());
-    runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
+    runargs.push("shell".to_strbuf());
+    runargs.push("cat".to_strbuf());
+    runargs.push(format_strbuf!("{}/{}.exitcode",
+                                config.adb_test_dir,
+                                prog_short));
 
     let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
-        procsrv::run("", config.adb_path, runargs.as_slice(), vec!(("".to_owned(),"".to_owned())),
-                     Some("".to_owned()))
-        .expect(format!("failed to exec `{}`", config.adb_path));
+        procsrv::run("",
+                     config.adb_path.as_slice(),
+                     runargs.as_slice(),
+                     vec!(("".to_strbuf(), "".to_strbuf())),
+                     Some("".to_strbuf()))
+        .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
 
-    let mut exitcode : int = 0;
-    for c in exitcode_out.chars() {
+    let mut exitcode: int = 0;
+    for c in exitcode_out.as_slice().chars() {
         if !c.is_digit() { break; }
         exitcode = exitcode * 10 + match c {
             '0' .. '9' => c as int - ('0' as int),
@@ -1220,31 +1405,40 @@ fn _arm_exec_compiled_test(config: &Config, props: &TestProps,
 
     // get stdout of result
     runargs = Vec::new();
-    runargs.push("shell".to_owned());
-    runargs.push("cat".to_owned());
-    runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
+    runargs.push("shell".to_strbuf());
+    runargs.push("cat".to_strbuf());
+    runargs.push(format_strbuf!("{}/{}.stdout",
+                                config.adb_test_dir,
+                                prog_short));
 
     let procsrv::Result{ out: stdout_out, err: _, status: _ } =
         procsrv::run("",
-                     config.adb_path,
+                     config.adb_path.as_slice(),
                      runargs.as_slice(),
-                     vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-        .expect(format!("failed to exec `{}`", config.adb_path));
+                     vec!(("".to_strbuf(), "".to_strbuf())),
+                     Some("".to_strbuf()))
+        .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
 
     // get stderr of result
     runargs = Vec::new();
-    runargs.push("shell".to_owned());
-    runargs.push("cat".to_owned());
-    runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
+    runargs.push("shell".to_strbuf());
+    runargs.push("cat".to_strbuf());
+    runargs.push(format_strbuf!("{}/{}.stderr",
+                                config.adb_test_dir,
+                                prog_short));
 
     let procsrv::Result{ out: stderr_out, err: _, status: _ } =
         procsrv::run("",
-                     config.adb_path,
+                     config.adb_path.as_slice(),
                      runargs.as_slice(),
-                     vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-        .expect(format!("failed to exec `{}`", config.adb_path));
+                     vec!(("".to_strbuf(), "".to_strbuf())),
+                     Some("".to_strbuf()))
+        .expect(format_strbuf!("failed to exec `{}`", config.adb_path));
 
-    dump_output(config, testfile, stdout_out, stderr_out);
+    dump_output(config,
+                testfile,
+                stdout_out.as_slice(),
+                stderr_out.as_slice());
 
     ProcRes {
         status: process::ExitStatus(exitcode),
@@ -1261,10 +1455,20 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
     for file in dirs.iter() {
         if file.extension_str() == Some("so") {
             // FIXME (#9639): This needs to handle non-utf8 paths
-            let copy_result = procsrv::run("", config.adb_path,
-                ["push".to_owned(), file.as_str().unwrap().to_owned(), config.adb_test_dir.clone()],
-                vec!(("".to_owned(),"".to_owned())), Some("".to_owned()))
-                .expect(format!("failed to exec `{}`", config.adb_path));
+            let copy_result = procsrv::run("",
+                                           config.adb_path.as_slice(),
+                                           [
+                                            "push".to_strbuf(),
+                                            file.as_str()
+                                                .unwrap()
+                                                .to_strbuf(),
+                                            config.adb_test_dir.to_strbuf()
+                                           ],
+                                           vec!(("".to_strbuf(),
+                                                 "".to_strbuf())),
+                                           Some("".to_strbuf()))
+                .expect(format_strbuf!("failed to exec `{}`",
+                                       config.adb_path));
 
             if config.verbose {
                 println!("push ({}) {} {} {}",
@@ -1294,9 +1498,12 @@ fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
                                  testfile: &Path) -> ProcRes {
     let aux_dir = aux_output_dir_name(config, testfile);
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let link_args = vec!("-L".to_owned(), aux_dir.as_str().unwrap().to_owned());
-    let llvm_args = vec!("--emit=obj".to_owned(), "--crate-type=lib".to_owned(),
-                         "-C".to_owned(), "save-temps".to_owned());
+    let link_args = vec!("-L".to_strbuf(),
+                         aux_dir.as_str().unwrap().to_strbuf());
+    let llvm_args = vec!("--emit=obj".to_strbuf(),
+                         "--crate-type=lib".to_strbuf(),
+                         "-C".to_strbuf(),
+                         "save-temps".to_strbuf());
     let args = make_compile_args(config,
                                  props,
                                  link_args.append(llvm_args.as_slice()),
@@ -1311,11 +1518,12 @@ fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
     let testcc = testfile.with_extension("cc");
     let proc_args = ProcArgs {
         // FIXME (#9639): This needs to handle non-utf8 paths
-        prog: config.clang_path.get_ref().as_str().unwrap().to_owned(),
-        args: vec!("-c".to_owned(),
-                "-emit-llvm".to_owned(),
-                "-o".to_owned(), bitcodefile.as_str().unwrap().to_owned(),
-                testcc.as_str().unwrap().to_owned() )
+        prog: config.clang_path.get_ref().as_str().unwrap().to_strbuf(),
+        args: vec!("-c".to_strbuf(),
+                   "-emit-llvm".to_strbuf(),
+                   "-o".to_strbuf(),
+                   bitcodefile.as_str().unwrap().to_strbuf(),
+                   testcc.as_str().unwrap().to_strbuf())
     };
     compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
 }
@@ -1329,10 +1537,10 @@ fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
     let prog = config.llvm_bin_path.get_ref().join("llvm-extract");
     let proc_args = ProcArgs {
         // FIXME (#9639): This needs to handle non-utf8 paths
-        prog: prog.as_str().unwrap().to_owned(),
-        args: vec!("-func=" + fname,
-                "-o=" + extracted_bc.as_str().unwrap(),
-                bitcodefile.as_str().unwrap().to_owned() )
+        prog: prog.as_str().unwrap().to_strbuf(),
+        args: vec!(format_strbuf!("-func={}", fname),
+                   format_strbuf!("-o={}", extracted_bc.as_str().unwrap()),
+                   bitcodefile.as_str().unwrap().to_strbuf())
     };
     compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
 }
@@ -1346,9 +1554,9 @@ fn disassemble_extract(config: &Config, _props: &TestProps,
     let prog = config.llvm_bin_path.get_ref().join("llvm-dis");
     let proc_args = ProcArgs {
         // FIXME (#9639): This needs to handle non-utf8 paths
-        prog: prog.as_str().unwrap().to_owned(),
-        args: vec!("-o=" + extracted_ll.as_str().unwrap(),
-                extracted_bc.as_str().unwrap().to_owned() )
+        prog: prog.as_str().unwrap().to_strbuf(),
+        args: vec!(format_strbuf!("-o={}", extracted_ll.as_str().unwrap()),
+                   extracted_bc.as_str().unwrap().to_strbuf())
     };
     compose_and_run(config, testfile, proc_args, Vec::new(), "", None)
 }
@@ -1365,42 +1573,44 @@ fn run_codegen_test(config: &Config, props: &TestProps,
                     testfile: &Path, mm: &mut MetricMap) {
 
     if config.llvm_bin_path.is_none() {
-        fatal("missing --llvm-bin-path".to_owned());
+        fatal("missing --llvm-bin-path".to_strbuf());
     }
 
     if config.clang_path.is_none() {
-        fatal("missing --clang-path".to_owned());
+        fatal("missing --clang-path".to_strbuf());
     }
 
     let mut proc_res = compile_test_and_save_bitcode(config, props, testfile);
     if !proc_res.status.success() {
-        fatal_ProcRes("compilation failed!".to_owned(), &proc_res);
+        fatal_ProcRes("compilation failed!".to_strbuf(), &proc_res);
     }
 
     proc_res = extract_function_from_bitcode(config, props, "test", testfile, "");
     if !proc_res.status.success() {
-        fatal_ProcRes("extracting 'test' function failed".to_owned(), &proc_res);
+        fatal_ProcRes("extracting 'test' function failed".to_strbuf(),
+                      &proc_res);
     }
 
     proc_res = disassemble_extract(config, props, testfile, "");
     if !proc_res.status.success() {
-        fatal_ProcRes("disassembling extract failed".to_owned(), &proc_res);
+        fatal_ProcRes("disassembling extract failed".to_strbuf(), &proc_res);
     }
 
 
     let mut proc_res = compile_cc_with_clang_and_save_bitcode(config, props, testfile);
     if !proc_res.status.success() {
-        fatal_ProcRes("compilation failed!".to_owned(), &proc_res);
+        fatal_ProcRes("compilation failed!".to_strbuf(), &proc_res);
     }
 
     proc_res = extract_function_from_bitcode(config, props, "test", testfile, "clang");
     if !proc_res.status.success() {
-        fatal_ProcRes("extracting 'test' function failed".to_owned(), &proc_res);
+        fatal_ProcRes("extracting 'test' function failed".to_strbuf(),
+                      &proc_res);
     }
 
     proc_res = disassemble_extract(config, props, testfile, "clang");
     if !proc_res.status.success() {
-        fatal_ProcRes("disassembling extract failed".to_owned(), &proc_res);
+        fatal_ProcRes("disassembling extract failed".to_strbuf(), &proc_res);
     }
 
     let base = output_base_name(config, testfile);
index 253b7e87d02234199ae2cf2a7e6172248b9c05c1..942541c79eee7661b8c927ef8e5c165c95a49e81 100644 (file)
@@ -33,25 +33,25 @@ pub fn get_os(triple: &str) -> &'static str {
 }
 
 #[cfg(target_os = "win32")]
-pub fn make_new_path(path: &str) -> ~str {
+pub fn make_new_path(path: &str) -> StrBuf {
 
     // Windows just uses PATH as the library search path, so we have to
     // maintain the current value while adding our own
-    match getenv(lib_path_env_var()) {
+    match getenv(lib_path_env_var().as_slice()) {
       Some(curr) => {
-        format!("{}{}{}", path, path_div(), curr)
+        format_strbuf!("{}{}{}", path, path_div(), curr)
       }
-      None => path.to_str()
+      None => path.to_str().to_strbuf()
     }
 }
 
 #[cfg(target_os = "win32")]
-pub fn lib_path_env_var() -> ~str { "PATH".to_owned() }
+pub fn lib_path_env_var() -> StrBuf { "PATH".to_strbuf() }
 
 #[cfg(target_os = "win32")]
-pub fn path_div() -> ~str { ";".to_owned() }
+pub fn path_div() -> StrBuf { ";".to_strbuf() }
 
-pub fn logv(config: &Config, s: ~str) {
+pub fn logv(config: &Config, s: StrBuf) {
     debug!("{}", s);
     if config.verbose { println!("{}", s); }
 }
index 804d878398bf9018f6bedee78346c5a6824c792f..4670a2922cf8c6100bb51f6a4cf6548bc658484c 100644 (file)
@@ -8,7 +8,7 @@ Use [`ToStr`](http://static.rust-lang.org/doc/master/std/to_str/trait.ToStr.html
 
 ~~~
 let x: int = 42;
-let y: ~str = x.to_str();
+let y: StrBuf = x.to_str().to_strbuf();
 ~~~
 
 **String to int**
@@ -22,14 +22,14 @@ let y: int = x.unwrap();
 
 **Int to string, in non-base-10**
 
-Use the `format!` syntax extension.
+Use the `format_strbuf!` syntax extension.
 
 ~~~
 let x: int = 42;
-let y: ~str = format!("{:t}", x);   // binary
-let y: ~str = format!("{:o}", x);   // octal
-let y: ~str = format!("{:x}", x);   // lowercase hexadecimal
-let y: ~str = format!("{:X}", x);   // uppercase hexadecimal
+let y: StrBuf = format_strbuf!("{:t}", x);   // binary
+let y: StrBuf = format_strbuf!("{:o}", x);   // octal
+let y: StrBuf = format_strbuf!("{:x}", x);   // lowercase hexadecimal
+let y: StrBuf = format_strbuf!("{:X}", x);   // uppercase hexadecimal
 ~~~
 
 **String to int, in non-base-10**
@@ -55,13 +55,14 @@ let x: Option<&str> = str::from_utf8(bytes);
 let y: &str = x.unwrap();
 ~~~
 
-To return an Owned String (~str) use the str helper function [`from_utf8_owned`](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8_owned.html).
+To return an Owned String (StrBuf) use the str helper function [`from_utf8_owned`](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8_owned.html).
 
 ~~~
 use std::str;
 
-let x: Option<~str> = str::from_utf8_owned(~[104u8,105u8]);
-let y: ~str = x.unwrap();
+let x: Result<StrBuf,~[u8]> =
+    str::from_utf8_owned(~[104u8,105u8]).map(|x| x.to_strbuf());
+let y: StrBuf = x.unwrap();
 ~~~
 
 To return a [`MaybeOwned`](http://static.rust-lang.org/doc/master/std/str/enum.MaybeOwned.html) use the str helper function [`from_utf8_lossy`](http://static.rust-lang.org/doc/master/std/str/fn.from_utf8_owned.html).  This function also replaces non-valid utf-8 sequences with U+FFFD replacement character.
@@ -181,7 +182,7 @@ enum Closed {}
 Phantom types are useful for enforcing state at compile time. For example:
 
 ~~~
-struct Door<State>(~str);
+struct Door<State>(StrBuf);
 
 struct Open;
 struct Closed;
@@ -194,13 +195,13 @@ fn open(Door(name): Door<Closed>) -> Door<Open> {
     Door::<Open>(name)
 }
 
-let _ = close(Door::<Open>("front".to_owned()));
+let _ = close(Door::<Open>("front".to_strbuf()));
 ~~~
 
 Attempting to close a closed door is prevented statically:
 
 ~~~ {.ignore}
-let _ = close(Door::<Closed>("front".to_owned())); // error: mismatched types: expected `main::Door<main::Open>` but found `main::Door<main::Closed>`
+let _ = close(Door::<Closed>("front".to_strbuf())); // error: mismatched types: expected `main::Door<main::Open>` but found `main::Door<main::Closed>`
 ~~~
 
 # FFI (Foreign Function Interface)
index 303a32289b0ea47a7c4c3d5be928024b0ee21f1c..66935300f18d9ccc2bd5ec1855075cc85d32accf 100644 (file)
@@ -85,7 +85,7 @@ To take as an argument a fragment of Rust code, write `$` followed by a name
   `foo`.)
 * `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
   `f(42)`.)
-* `ty` (a type. Examples: `int`, `~[(char, ~str)]`, `&T`.)
+* `ty` (a type. Examples: `int`, `~[(char, StrBuf)]`, `&T`.)
 * `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
   a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
 * `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
index 853516f51d81e9c8a192e1097d1ecc0545de1ddc..8df11c59f60ef8271a0f0b25add20389feb311b4 100644 (file)
@@ -343,12 +343,9 @@ fn main() {
     let numbers_arc = Arc::new(numbers);
 
     for num in range(1u, 10) {
-        let (tx, rx) = channel();
-        tx.send(numbers_arc.clone());
+        let task_numbers = numbers_arc.clone();
 
         spawn(proc() {
-            let local_arc : Arc<Vec<f64>> = rx.recv();
-            let task_numbers = &*local_arc;
             println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
         });
     }
@@ -369,40 +366,27 @@ let numbers_arc=Arc::new(numbers);
 # }
 ~~~
 
-and a clone of it is sent to each task
+and a unique clone is captured for each task via a procedure. This only copies the wrapper and not
+it's contents. Within the task's procedure, the captured Arc reference can be used as an immutable
+reference to the underlying vector as if it were local.
 
 ~~~
 # extern crate sync;
 # extern crate rand;
 # use sync::Arc;
+# fn pnorm(nums: &[f64], p: uint) -> f64 { 4.0 }
 # fn main() {
 # let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
 # let numbers_arc = Arc::new(numbers);
-# let (tx, rx) = channel();
-tx.send(numbers_arc.clone());
-# }
-~~~
-
-copying only the wrapper and not its contents.
-
-Each task recovers the underlying data by
-
-~~~
-# extern crate sync;
-# extern crate rand;
-# use sync::Arc;
-# fn main() {
-# let numbers=Vec::from_fn(1000000, |_| rand::random::<f64>());
-# let numbers_arc=Arc::new(numbers);
-# let (tx, rx) = channel();
-# tx.send(numbers_arc.clone());
-# let local_arc : Arc<Vec<f64>> = rx.recv();
-let task_numbers = &*local_arc;
+# let num = 4;
+let task_numbers = numbers_arc.clone();
+spawn(proc() {
+    // Capture task_numbers and use it as if it was the underlying vector
+    println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num));
+});
 # }
 ~~~
 
-and can use it as if it were local.
-
 The `arc` module also implements Arcs around mutable data that are not covered here.
 
 # Handling task failure
@@ -479,11 +463,11 @@ Here is the function that implements the child task:
 ~~~
 extern crate sync;
 # fn main() {
-fn stringifier(channel: &sync::DuplexStream<~str, uint>) {
+fn stringifier(channel: &sync::DuplexStream<StrBuf, uint>) {
     let mut value: uint;
     loop {
         value = channel.recv();
-        channel.send(value.to_str());
+        channel.send(value.to_str().to_strbuf());
         if value == 0 { break; }
     }
 }
@@ -504,11 +488,11 @@ Here is the code for the parent task:
 extern crate sync;
 # use std::task::spawn;
 # use sync::DuplexStream;
-# fn stringifier(channel: &sync::DuplexStream<~str, uint>) {
+# fn stringifier(channel: &sync::DuplexStream<StrBuf, uint>) {
 #     let mut value: uint;
 #     loop {
 #         value = channel.recv();
-#         channel.send(value.to_str());
+#         channel.send(value.to_str().to_strbuf());
 #         if value == 0u { break; }
 #     }
 # }
@@ -521,13 +505,13 @@ spawn(proc() {
 });
 
 from_child.send(22);
-assert!(from_child.recv() == "22".to_owned());
+assert!(from_child.recv().as_slice() == "22");
 
 from_child.send(23);
 from_child.send(0);
 
-assert!(from_child.recv() == "23".to_owned());
-assert!(from_child.recv() == "0".to_owned());
+assert!(from_child.recv().as_slice() == "23");
+assert!(from_child.recv().as_slice() == "0");
 
 # }
 ~~~
index 0be831c5132842320ad8f86ca8669ab7d0da0bcd..057849f1bca736cae83af409610a135909cd0820 100644 (file)
@@ -90,10 +90,15 @@ fn test_out_of_bounds_failure() {
 ~~~
 
 A test runner built with the `--test` flag supports a limited set of
-arguments to control which tests are run: the first free argument
-passed to a test runner specifies a filter used to narrow down the set
-of tests being run; the `--ignored` flag tells the test runner to run
-only tests with the `ignore` attribute.
+arguments to control which tests are run:
+
+- the first free argument passed to a test runner is interpreted as a
+  regular expression
+  ([syntax reference](regex/index.html#syntax))
+  and is used to narrow down the set of tests being run. Note: a plain
+  string is a valid regular expression that matches itself.
+- the `--ignored` flag tells the test runner to run only tests with the
+  `ignore` attribute.
 
 ## Parallelism
 
@@ -146,16 +151,31 @@ result: FAILED. 1 passed; 1 failed; 0 ignored
 
 ### Running a subset of tests
 
+Using a plain string:
+
+~~~ {.notrust}
+$ mytests mytest23
+
+running 1 tests
+running driver::tests::mytest23 ... ok
+
+result: ok. 1 passed; 0 failed; 0 ignored
+~~~
+
+Using some regular expression features:
+
 ~~~ {.notrust}
-$ mytests mytest1
+$ mytests 'mytest[145]'
 
-running 11 tests
+running 13 tests
 running driver::tests::mytest1 ... ok
+running driver::tests::mytest4 ... ok
+running driver::tests::mytest5 ... ok
 running driver::tests::mytest10 ... ignored
 ... snip ...
 running driver::tests::mytest19 ... ok
 
-result: ok. 11 passed; 0 failed; 1 ignored
+result: ok. 13 passed; 0 failed; 1 ignored
 ~~~
 
 # Microbenchmarking
index f387f3be9f36311f38c1fa133e774070c6967e0a..4ce4d1697be0bd94f1dfe21285fe96ad890a7c2d 100644 (file)
@@ -34,7 +34,7 @@ msgstr ""
 #, fuzzy
 #| msgid ""
 #| "~~~~ let x: f64 = 4.0; let y: uint = x as uint; assert!(y == 4u); ~~~~"
-msgid "~~~ let x: int = 42; let y: ~str = x.to_str(); ~~~"
+msgid "~~~ let x: int = 42; let y: StrBuf = x.to_str(); ~~~"
 msgstr ""
 "~~~~\n"
 "let x: f64 = 4.0;\n"
@@ -96,7 +96,7 @@ msgstr ""
 #, fuzzy
 #| msgid ""
 #| "~~~~ let x: f64 = 4.0; let y: uint = x as uint; assert!(y == 4u); ~~~~"
-msgid "let x: int = 42; let y: ~str = x.to_str_radix(16); ~~~"
+msgid "let x: int = 42; let y: StrBuf = x.to_str_radix(16); ~~~"
 msgstr ""
 "~~~~\n"
 "let x: f64 = 4.0;\n"
index 758d9863b0a35acf54880c072612f3c2152fb0e4..b23f130f2663887d0f5402d8448c294c13a726dd 100644 (file)
@@ -1641,7 +1641,7 @@ msgstr "## 最小限の例"
 msgid ""
 "~~~~\n"
 "trait Printable {\n"
-"  fn to_string(&self) -> ~str;\n"
+"  fn to_string(&self) -> StrBuf;\n"
 "}\n"
 msgstr ""
 "~~~~ {.ignore}\n"
@@ -1656,7 +1656,7 @@ msgstr ""
 #| msgid "~~~~ {.ignore} // main.rs extern crate world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
 msgid ""
 "impl Printable for int {\n"
-"  fn to_string(&self) -> ~str { self.to_str() }\n"
+"  fn to_string(&self) -> StrBuf { self.to_str() }\n"
 "}\n"
 msgstr ""
 "~~~~ {.ignore}\n"
@@ -1702,7 +1702,7 @@ msgstr "# クロージャ"
 msgid ""
 "~~~~\n"
 "trait Printable {\n"
-"  fn make_string(&self) -> ~str;\n"
+"  fn make_string(&self) -> StrBuf;\n"
 "}\n"
 msgstr ""
 "~~~~ {.ignore}\n"
@@ -1716,8 +1716,8 @@ msgstr ""
 #, fuzzy, no-wrap
 #| msgid "~~~~ {.ignore} // main.rs extern crate world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
 msgid ""
-"impl Printable for ~str {\n"
-"    fn make_string(&self) -> ~str {\n"
+"impl Printable for StrBuf {\n"
+"    fn make_string(&self) -> StrBuf {\n"
 "        (*self).clone()\n"
 "    }\n"
 "}\n"
index 721b5b2b659d1a376f3d14de09f5f3905bf99bea..96514e99b86b1682eeda44ca65db46cdf524907d 100644 (file)
@@ -3755,15 +3755,15 @@ msgstr ""
 #| msgid ""
 #| "Traits may be implemented for specific types with [impls]. An impl that "
 #| "implements a trait includes the name of the trait at the start of the "
-#| "definition, as in the following impls of `Printable` for `int` and `~str`."
+#| "definition, as in the following impls of `Printable` for `int` and `StrBuf`."
 msgid ""
 "Traits may be implemented for specific types with [impls]. An impl for a "
 "particular trait gives an implementation of the methods that trait "
 "provides.  For instance, the following impls of `Printable` for `int` and "
-"`~str` give implementations of the `print` method."
+"`StrBuf` give implementations of the `print` method."
 msgstr ""
 "[impl][impls] により特定の型にトレイトを実装することができます。トレイトを実"
-"装する impl は、以下の `Printable` の `int` と `~str` に対する実装のように、"
+"装する impl は、以下の `Printable` の `int` と `StrBuf` に対する実装のように、"
 "定義の先頭にトレイトの名前を含みます。"
 
 #. type: Plain text
@@ -3776,7 +3776,7 @@ msgstr "[impls]: #メソッド"
 #, fuzzy, no-wrap
 #| msgid "~~~~ {.ignore} // main.rs extern crate world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
 msgid ""
-"impl Printable for ~str {\n"
+"impl Printable for StrBuf {\n"
 "    fn print(&self) { println!(\"{}\", *self) }\n"
 "}\n"
 msgstr ""
index f242a89784ce966c4dbcb36e76b94d78106db52d..4986ad1ba99f55809a4d11b13bed018fd2ca909d 100644 (file)
@@ -473,7 +473,7 @@ Two examples of paths with type arguments:
 # struct HashMap<K, V>;
 # fn f() {
 # fn id<T>(t: T) -> T { t }
-type T = HashMap<int,~str>;  // Type arguments used in a type expression
+type T = HashMap<int,StrBuf>;  // Type arguments used in a type expression
 let x = id::<int>(10);       // Type arguments used in a call expression
 # }
 ~~~~
@@ -1259,12 +1259,12 @@ Enumeration constructors can have either named or unnamed fields:
 
 ~~~~
 enum Animal {
-    Dog (~str, f64),
-    Cat { name: ~str, weight: f64 }
+    Dog (StrBuf, f64),
+    Cat { name: StrBuf, weight: f64 }
 }
 
-let mut a: Animal = Dog("Cocoa".to_owned(), 37.2);
-a = Cat{ name: "Spotty".to_owned(), weight: 2.7 };
+let mut a: Animal = Dog("Cocoa".to_strbuf(), 37.2);
+a = Cat { name: "Spotty".to_strbuf(), weight: 2.7 };
 ~~~~
 
 In this example, `Cat` is a _struct-like enum variant_,
@@ -1799,6 +1799,8 @@ type int8_t = i8;
 - `no_start` - disable linking to the `native` crate, which specifies the
   "start" language item.
 - `no_std` - disable linking to the `std` crate.
+- `no_builtins` - disable optimizing certain code patterns to invocations of
+                  library functions that are assumed to exist
 
 ### Module-only attributes
 
@@ -2079,7 +2081,7 @@ These are functions:
 * `str_eq`
   : Compare two strings (`&str`) for equality.
 * `uniq_str_eq`
-  : Compare two owned strings (`~str`) for equality.
+  : Compare two owned strings (`StrBuf`) for equality.
 * `strdup_uniq`
   : Return a new unique string
     containing a copy of the contents of a unique string.
@@ -3307,7 +3309,7 @@ A value of type `str` is a Unicode string,
 represented as a vector of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints.
 Since `str` is of unknown size, it is not a _first class_ type,
 but can only be instantiated through a pointer type,
-such as `&str` or `~str`.
+such as `&str` or `StrBuf`.
 
 ### Tuple types
 
@@ -3571,11 +3573,11 @@ An example of an object type:
 
 ~~~~
 trait Printable {
-  fn to_string(&self) -> ~str;
+  fn to_string(&self) -> StrBuf;
 }
 
 impl Printable for int {
-  fn to_string(&self) -> ~str { self.to_str() }
+  fn to_string(&self) -> StrBuf { self.to_str().to_strbuf() }
 }
 
 fn print(a: Box<Printable>) {
@@ -3616,17 +3618,17 @@ example, in:
 
 ~~~~
 trait Printable {
-  fn make_string(&self) -> ~str;
+  fn make_string(&self) -> StrBuf;
 }
 
-impl Printable for ~str {
-    fn make_string(&self) -> ~str {
+impl Printable for StrBuf {
+    fn make_string(&self) -> StrBuf {
         (*self).clone()
     }
 }
 ~~~~
 
-`self` refers to the value of type `~str` that is the receiver for a
+`self` refers to the value of type `StrBuf` that is the receiver for a
 call to the method `make_string`.
 
 ## Type kinds
index 06ee875f6d6210dc5707d39ad13cf3fa25a96eae..3b7f4e1bf5013940cbd34d081116dc8263abd2b8 100644 (file)
@@ -26,7 +26,7 @@ comments":
 pub struct Widget {
        /// All widgets have a purpose (this is a doc comment, and will show up
        /// the field's documentation).
-       purpose: ~str,
+       purpose: StrBuf,
        /// Humans are not allowed to understand some widgets
        understandable: bool
 }
index 7dd31f9cc77c6a16bf9f026396e7d3fd1ad2a38f..ad77b90e79b7023110ca784fc020158c4dc7b47b 100644 (file)
@@ -2213,7 +2213,7 @@ don't provide any methods.
 Traits may be implemented for specific types with [impls]. An impl for
 a particular trait gives an implementation of the methods that
 trait provides.  For instance, the following impls of
-`Printable` for `int` and `~str` give implementations of the `print`
+`Printable` for `int` and `StrBuf` give implementations of the `print`
 method.
 
 [impls]: #methods
@@ -2224,12 +2224,12 @@ impl Printable for int {
     fn print(&self) { println!("{:?}", *self) }
 }
 
-impl Printable for ~str {
+impl Printable for StrBuf {
     fn print(&self) { println!("{}", *self) }
 }
 
 # 1.print();
-# ("foo".to_owned()).print();
+# ("foo".to_strbuf()).print();
 ~~~~
 
 Methods defined in an impl for a trait may be called just like
@@ -2270,7 +2270,7 @@ trait Printable {
 
 impl Printable for int {}
 
-impl Printable for ~str {
+impl Printable for StrBuf {
     fn print(&self) { println!("{}", *self) }
 }
 
@@ -2279,7 +2279,7 @@ impl Printable for bool {}
 impl Printable for f32 {}
 
 # 1.print();
-# ("foo".to_owned()).print();
+# ("foo".to_strbuf()).print();
 # true.print();
 # 3.14159.print();
 ~~~~
@@ -2291,7 +2291,7 @@ provided in the trait definition.  Depending on the trait, default
 methods can save a great deal of boilerplate code from having to be
 written in impls.  Of course, individual impls can still override the
 default method for `print`, as is being done above in the impl for
-`~str`.
+`StrBuf`.
 
 ## Type-parameterized traits
 
index 47e9a013e11354c7186b09ca66dad376de98ca00..f49bffe06d3930cc07f1aec9c87732b91f00771b 100644 (file)
 //! once, once the arena itself is destroyed. They do not support deallocation
 //! of individual objects while the arena itself is still alive. The benefit
 //! of an arena is very fast allocation; just a pointer bump.
+//!
+//! This crate has two arenas implemented: TypedArena, which is a simpler
+//! arena but can only hold objects of a single type, and Arena, which is a
+//! more complex, slower Arena which can hold objects of any type.
 
 #![crate_id = "arena#0.11.0-pre"]
 #![crate_type = "rlib"]
@@ -56,41 +60,42 @@ unsafe fn as_ptr(&self) -> *u8 {
     }
 }
 
-// Arenas are used to quickly allocate objects that share a
-// lifetime. The arena uses ~[u8] vectors as a backing store to
-// allocate objects from. For each allocated object, the arena stores
-// a pointer to the type descriptor followed by the
-// object. (Potentially with alignment padding after each of them.)
-// When the arena is destroyed, it iterates through all of its chunks,
-// and uses the tydesc information to trace through the objects,
-// calling the destructors on them.
-// One subtle point that needs to be addressed is how to handle
-// failures while running the user provided initializer function. It
-// is important to not run the destructor on uninitialized objects, but
-// how to detect them is somewhat subtle. Since alloc() can be invoked
-// recursively, it is not sufficient to simply exclude the most recent
-// object. To solve this without requiring extra space, we use the low
-// order bit of the tydesc pointer to encode whether the object it
-// describes has been fully initialized.
-
-// As an optimization, objects with destructors are stored in
-// different chunks than objects without destructors. This reduces
-// overhead when initializing plain-old-data and means we don't need
-// to waste time running the destructors of POD.
+/// A slower reflection-based arena that can allocate objects of any type.
+///
+/// This arena uses Vec<u8> as a backing store to allocate objects from.  For
+/// each allocated object, the arena stores a pointer to the type descriptor
+/// followed by the object. (Potentially with alignment padding after each
+/// element.) When the arena is destroyed, it iterates through all of its
+/// chunks, and uses the tydesc information to trace through the objects,
+/// calling the destructors on them.  One subtle point that needs to be
+/// addressed is how to handle failures while running the user provided
+/// initializer function. It is important to not run the destructor on
+/// uninitialized objects, but how to detect them is somewhat subtle. Since
+/// alloc() can be invoked recursively, it is not sufficient to simply exclude
+/// the most recent object. To solve this without requiring extra space, we
+/// use the low order bit of the tydesc pointer to encode whether the object
+/// it describes has been fully initialized.
+///
+/// As an optimization, objects with destructors are stored in
+/// different chunks than objects without destructors. This reduces
+/// overhead when initializing plain-old-data and means we don't need
+/// to waste time running the destructors of POD.
 pub struct Arena {
     // The head is separated out from the list as a unbenchmarked
-    // microoptimization, to avoid needing to case on the list to
-    // access the head.
+    // microoptimization, to avoid needing to case on the list to access the
+    // head.
     head: Chunk,
     copy_head: Chunk,
     chunks: RefCell<Vec<Chunk>>,
 }
 
 impl Arena {
+    /// Allocate a new Arena with 32 bytes preallocated.
     pub fn new() -> Arena {
         Arena::new_with_size(32u)
     }
 
+    /// Allocate a new Arena with `initial_size` bytes preallocated.
     pub fn new_with_size(initial_size: uint) -> Arena {
         Arena {
             head: chunk(initial_size, false),
@@ -265,7 +270,8 @@ fn alloc_noncopy<'a, T>(&'a mut self, op: || -> T) -> &'a T {
         }
     }
 
-    // The external interface
+    /// Allocate a new item in the arena, using `op` to initialize the value
+    /// and returning a reference to it.
     #[inline]
     pub fn alloc<'a, T>(&'a self, op: || -> T) -> &'a T {
         unsafe {
@@ -313,7 +319,7 @@ fn test_arena_destructors_fail() {
     });
 }
 
-/// An arena that can hold objects of only one type.
+/// A faster arena that can hold objects of only one type.
 ///
 /// Safety note: Modifying objects in the arena that have already had their
 /// `drop` destructors run can cause leaks, because the destructor will not
@@ -405,13 +411,13 @@ fn end(&self) -> *u8 {
 }
 
 impl<T> TypedArena<T> {
-    /// Creates a new arena with preallocated space for 8 objects.
+    /// Creates a new TypedArena with preallocated space for 8 objects.
     #[inline]
     pub fn new() -> TypedArena<T> {
         TypedArena::with_capacity(8)
     }
 
-    /// Creates a new arena with preallocated space for the given number of
+    /// Creates a new TypedArena with preallocated space for the given number of
     /// objects.
     #[inline]
     pub fn with_capacity(capacity: uint) -> TypedArena<T> {
@@ -423,7 +429,7 @@ pub fn with_capacity(capacity: uint) -> TypedArena<T> {
         }
     }
 
-    /// Allocates an object into this arena.
+    /// Allocates an object in the TypedArena, returning a reference to it.
     #[inline]
     pub fn alloc<'a>(&'a self, object: T) -> &'a T {
         unsafe {
index 245040d791cff1cd3cee12c9c448a460588c018e..ba83ad8d37c9a77dfd901f4eae13afbc97b210c8 100644 (file)
@@ -425,8 +425,8 @@ impl<K: fmt::Show + TotalOrd, V: fmt::Show> fmt::Show for Leaf<K, V> {
     ///Returns a string representation of a Leaf.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         for (i, s) in self.elts.iter().enumerate() {
-            if i != 0 { try!(write!(f.buf, " // ")) }
-            try!(write!(f.buf, "{}", *s))
+            if i != 0 { try!(write!(f, " // ")) }
+            try!(write!(f, "{}", *s))
         }
         Ok(())
     }
@@ -654,10 +654,10 @@ impl<K: fmt::Show + TotalOrd, V: fmt::Show> fmt::Show for Branch<K, V> {
     ///Returns a string representation of a Branch.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         for (i, s) in self.elts.iter().enumerate() {
-            if i != 0 { try!(write!(f.buf, " // ")) }
-            try!(write!(f.buf, "{}", *s))
+            if i != 0 { try!(write!(f, " // ")) }
+            try!(write!(f, "{}", *s))
         }
-        write!(f.buf, " // rightmost child: ({}) ", *self.rightmost_child)
+        write!(f, " // rightmost child: ({}) ", *self.rightmost_child)
     }
 }
 
@@ -715,7 +715,7 @@ fn cmp(&self, other: &LeafElt<K, V>) -> Ordering {
 impl<K: fmt::Show + TotalOrd, V: fmt::Show> fmt::Show for LeafElt<K, V> {
     ///Returns a string representation of a LeafElt.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "Key: {}, value: {};", self.key, self.value)
+        write!(f, "Key: {}, value: {};", self.key, self.value)
     }
 }
 
@@ -765,7 +765,7 @@ impl<K: fmt::Show + TotalOrd, V: fmt::Show> fmt::Show for BranchElt<K, V> {
     /// Returns string containing key, value, and child (which should recur to a
     /// leaf) Consider changing in future to be more readable.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "Key: {}, value: {}, (child: {})",
+        write!(f, "Key: {}, value: {}, (child: {})",
                self.key, self.value, *self.left)
     }
 }
index 3cffea46fecbf545aa9949b86b455039b0b27724..4259f458e00643baacdd6ac9fb2435d4390a025c 100644 (file)
@@ -1239,31 +1239,14 @@ fn insert_hashed<'a>(&'a mut self, hash: table::SafeHash, k: K, v: V) -> &'a mut
     /// Return the value corresponding to the key in the map, or insert
     /// and return the value if it doesn't exist.
     pub fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a mut V {
-        let hash = self.make_hash(&k);
-        match self.search_hashed(&hash, &k) {
-            Some(idx) => {
-                let (_, v_ref) = self.table.read_mut(&idx);
-                v_ref
-            },
-            None => self.insert_hashed(hash, k, v)
-        }
+        self.find_with_or_insert_with(k, v, |_k, _v, _a| (), |_k, a| a)
     }
 
     /// Return the value corresponding to the key in the map, or create,
     /// insert, and return a new value if it doesn't exist.
     pub fn find_or_insert_with<'a>(&'a mut self, k: K, f: |&K| -> V)
                                -> &'a mut V {
-        let hash = self.make_hash(&k);
-        match self.search_hashed(&hash, &k) {
-            Some(idx) => {
-                let (_, v_ref) = self.table.read_mut(&idx);
-                v_ref
-            },
-            None => {
-                let v = f(&k);
-                self.insert_hashed(hash, k, v)
-            }
-        }
+        self.find_with_or_insert_with(k, (), |_k, _v, _a| (), |k, _a| f(k))
     }
 
     /// Insert a key-value pair into the map if the key is not already present.
@@ -1275,12 +1258,66 @@ pub fn insert_or_update_with<'a>(
                                  v: V,
                                  f: |&K, &mut V|)
                                  -> &'a mut V {
+        self.find_with_or_insert_with(k, v, |k, v, _a| f(k, v), |_k, a| a)
+    }
+
+    /// Modify and return the value corresponding to the key in the map, or
+    /// insert and return a new value if it doesn't exist.
+    ///
+    /// This method allows for all insertion behaviours of a hashmap;
+    /// see methods like `insert`, `find_or_insert` and
+    /// `insert_or_update_with` for less general and more friendly
+    /// variations of this.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use collections::HashMap;
+    ///
+    /// // map some strings to vectors of strings
+    /// let mut map = HashMap::new();
+    /// map.insert("a key", vec!["value"]);
+    /// map.insert("z key", vec!["value"]);
+    ///
+    /// let new = vec!["a key", "b key", "z key"];
+    ///
+    /// for k in new.move_iter() {
+    ///     map.find_with_or_insert_with(
+    ///         k, "new value",
+    ///         // if the key does exist either prepend or append this
+    ///         // new value based on the first letter of the key.
+    ///         |key, already, new| {
+    ///             if key.as_slice().starts_with("z") {
+    ///                 already.unshift(new);
+    ///             } else {
+    ///                 already.push(new);
+    ///             }
+    ///         },
+    ///         // if the key doesn't exist in the map yet, add it in
+    ///         // the obvious way.
+    ///         |_k, v| vec![v]);
+    /// }
+    ///
+    /// assert_eq!(map.len(), 3);
+    /// assert_eq!(map.get(&"a key"), &vec!["value", "new value"]);
+    /// assert_eq!(map.get(&"b key"), &vec!["new value"]);
+    /// assert_eq!(map.get(&"z key"), &vec!["new value", "value"]);
+    /// ```
+    pub fn find_with_or_insert_with<'a, A>(&'a mut self,
+                                           k: K,
+                                           a: A,
+                                           found: |&K, &mut V, A|,
+                                           not_found: |&K, A| -> V)
+                                          -> &'a mut V {
         let hash = self.make_hash(&k);
         match self.search_hashed(&hash, &k) {
-            None      => self.insert_hashed(hash, k, v),
+            None => {
+                let v = not_found(&k, a);
+                self.insert_hashed(hash, k, v)
+            },
             Some(idx) => {
                 let (_, v_ref) = self.table.read_mut(&idx);
-                f(&k, v_ref);
+                found(&k, v_ref, a);
                 v_ref
             }
         }
@@ -1381,14 +1418,14 @@ fn eq(&self, other: &HashMap<K, V, H>) -> bool {
 
 impl<K: TotalEq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, r"\{"));
+        try!(write!(f, r"\{"));
 
         for (i, (k, v)) in self.iter().enumerate() {
-            if i != 0 { try!(write!(f.buf, ", ")); }
-            try!(write!(f.buf, "{}: {}", *k, *v));
+            if i != 0 { try!(write!(f, ", ")); }
+            try!(write!(f, "{}: {}", *k, *v));
         }
 
-        write!(f.buf, r"\}")
+        write!(f, r"\}")
     }
 }
 
@@ -1568,14 +1605,14 @@ pub fn union<'a>(&'a self, other: &'a HashSet<T, H>)
 
 impl<T: TotalEq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, r"\{"));
+        try!(write!(f, r"\{"));
 
         for (i, x) in self.iter().enumerate() {
-            if i != 0 { try!(write!(f.buf, ", ")); }
-            try!(write!(f.buf, "{}", *x));
+            if i != 0 { try!(write!(f, ", ")); }
+            try!(write!(f, "{}", *x));
         }
 
-        write!(f.buf, r"\}")
+        write!(f, r"\}")
     }
 }
 
index 72eefe4f44d66d1a28ca72dd9f2e086c728debc7..8fdc0e095bf411096cb4caa6bc162fb4182d2e65 100644 (file)
@@ -205,20 +205,20 @@ impl<A: fmt::Show + Hash + TotalEq, B: fmt::Show> fmt::Show for LruCache<A, B> {
     /// Return a string that lists the key-value pairs from most-recently
     /// used to least-recently used.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, r"\{"));
+        try!(write!(f, r"\{"));
         let mut cur = self.head;
         for i in range(0, self.len()) {
-            if i > 0 { try!(write!(f.buf, ", ")) }
+            if i > 0 { try!(write!(f, ", ")) }
             unsafe {
                 cur = (*cur).next;
-                try!(write!(f.buf, "{}", (*cur).key));
+                try!(write!(f, "{}", (*cur).key));
             }
-            try!(write!(f.buf, ": "));
+            try!(write!(f, ": "));
             unsafe {
-                try!(write!(f.buf, "{}", (*cur).value));
+                try!(write!(f, "{}", (*cur).value));
             }
         }
-        write!(f.buf, r"\}")
+        write!(f, r"\}")
     }
 }
 
index 70cd46dcfa2b45ce8b9fc03685ba3c7b8226fe35..61c1193e515973f939e9daf8ede42269079de50b 100644 (file)
@@ -166,12 +166,12 @@ fn any_as_ref() {
 
         match a.as_ref::<uint>() {
             Some(&5) => {}
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match a.as_ref::<Test>() {
             None => {}
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
     }
 
@@ -189,7 +189,7 @@ fn any_as_mut() {
                 assert_eq!(*x, 5u);
                 *x = 612;
             }
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match b_r.as_mut::<uint>() {
@@ -197,27 +197,27 @@ fn any_as_mut() {
                 assert_eq!(*x, 7u);
                 *x = 413;
             }
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match a_r.as_mut::<Test>() {
             None => (),
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match b_r.as_mut::<Test>() {
             None => (),
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match a_r.as_mut::<uint>() {
             Some(&612) => {}
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
 
         match b_r.as_mut::<uint>() {
             Some(&413) => {}
-            x => fail!("Unexpected value {:?}", x)
+            x => fail!("Unexpected value {}", x)
         }
     }
 
@@ -229,11 +229,11 @@ fn any_move() {
         let b = box Test as Box<Any>;
 
         match a.move::<uint>() {
-            Ok(a) => { assert_eq!(a, box 8u); }
+            Ok(a) => { assert!(a == box 8u); }
             Err(..) => fail!()
         }
         match b.move::<Test>() {
-            Ok(a) => { assert_eq!(a, box Test); }
+            Ok(a) => { assert!(a == box Test); }
             Err(..) => fail!()
         }
 
@@ -246,13 +246,14 @@ fn any_move() {
 
     #[test]
     fn test_show() {
-        let a = box 8u as Box<::realcore::any::Any>;
-        let b = box Test as Box<::realcore::any::Any>;
-        assert_eq!(format!("{}", a), "Box<Any>".to_owned());
-        assert_eq!(format!("{}", b), "Box<Any>".to_owned());
-
-        let a = &8u as &::realcore::any::Any;
-        let b = &Test as &::realcore::any::Any;
+        use realstd::to_str::ToStr;
+        let a = box 8u as Box<::realstd::any::Any>;
+        let b = box Test as Box<::realstd::any::Any>;
+        assert_eq!(a.to_str(), "Box<Any>".to_owned());
+        assert_eq!(b.to_str(), "Box<Any>".to_owned());
+
+        let a = &8u as &Any;
+        let b = &Test as &Any;
         assert_eq!(format!("{}", a), "&Any".to_owned());
         assert_eq!(format!("{}", b), "&Any".to_owned());
     }
index 0413b31e8b76efa1694e3204a4db420fe9983150..d42ad49485f6dae9927a33e8df4c68afc394fe68 100644 (file)
@@ -186,6 +186,25 @@ fn deref<'a>(&'a self) -> &'a T {
     }
 }
 
+/// Copy a `Ref`.
+///
+/// The `RefCell` is already immutably borrowed, so this cannot fail.
+///
+/// A `Clone` implementation would interfere with the widespread
+/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
+#[experimental]
+pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
+    // Since this Ref exists, we know the borrow flag
+    // is not set to WRITING.
+    let borrow = orig.parent.borrow.get();
+    debug_assert!(borrow != WRITING && borrow != UNUSED);
+    orig.parent.borrow.set(borrow + 1);
+
+    Ref {
+        parent: orig.parent,
+    }
+}
+
 /// Wraps a mutable borrowed reference to a value in a `RefCell` box.
 pub struct RefMut<'b, T> {
     parent: &'b RefCell<T>
@@ -236,7 +255,7 @@ fn smoketest_cell() {
     fn cell_has_sensible_show() {
         use str::StrSlice;
 
-        let x = ::realcore::cell::Cell::new("foo bar");
+        let x = Cell::new("foo bar");
         assert!(format!("{}", x).contains(x.get()));
 
         x.set("baz qux");
@@ -307,4 +326,19 @@ fn discard_doesnt_unborrow() {
         let _ = _b;
         let _b = x.borrow_mut();
     }
+
+    #[test]
+    fn clone_ref_updates_flag() {
+        let x = RefCell::new(0);
+        {
+            let b1 = x.borrow();
+            assert!(x.try_borrow_mut().is_none());
+            {
+                let _b2 = clone_ref(&b1);
+                assert!(x.try_borrow_mut().is_none());
+            }
+            assert!(x.try_borrow_mut().is_none());
+        }
+        assert!(x.try_borrow_mut().is_some());
+    }
 }
index 934483dbed423d1337d4544fdde200820d7aa3fa..6e9d4c9bafbf616be4ae623ac8c9fad8ea641f87 100644 (file)
@@ -633,9 +633,9 @@ fn default() -> char { '\x00' }
 mod test {
     use super::{escape_unicode, escape_default};
 
-    use realcore::char::Char;
+    use char::Char;
     use slice::ImmutableVector;
-    use realstd::option::{Some, None};
+    use option::{Some, None};
     use realstd::strbuf::StrBuf;
     use realstd::str::StrAllocating;
 
index cd66beabc12de3fce964966012ded57abb79a347..c7befe2f4b1e0a64d23bd7c162577b79f067ef7e 100644 (file)
@@ -131,7 +131,7 @@ fn realclone_from<T: ::realstd::clone::Clone>(t1: &mut T, t2: &T) {
     fn test_owned_clone() {
         let a = box 5i;
         let b: Box<int> = realclone(&a);
-        assert_eq!(a, b);
+        assert!(a == b);
     }
 
     #[test]
index 52df7e71727ee2c8baa2b4216c2a6e22237be612..a50108607ce71cf46d1af2a618714e83317ebac9 100644 (file)
@@ -82,7 +82,7 @@ fn assert_receiver_is_total_eq(&self) {}
 }
 
 /// An ordering is, e.g, a result of a comparison between two values.
-#[deriving(Clone, Eq)]
+#[deriving(Clone, Eq, Show)]
 pub enum Ordering {
    /// An ordering where a compared value is less [than another].
    Less = -1,
@@ -192,7 +192,23 @@ pub fn max<T: TotalOrd>(v1: T, v2: T) -> T {
 // Implementation of Eq/TotalEq for some primitive types
 #[cfg(not(test))]
 mod impls {
-    use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering};
+    use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering, Equal};
+
+    impl Eq for () {
+        #[inline]
+        fn eq(&self, _other: &()) -> bool { true }
+        #[inline]
+        fn ne(&self, _other: &()) -> bool { false }
+    }
+    impl TotalEq for () {}
+    impl Ord for () {
+        #[inline]
+        fn lt(&self, _other: &()) -> bool { false }
+    }
+    impl TotalOrd for () {
+        #[inline]
+        fn cmp(&self, _other: &()) -> Ordering { Equal }
+    }
 
     // & pointers
     impl<'a, T: Eq> Eq for &'a T {
index af65fcc5a779da550cbf2410c9b6b732148bfe1f..50ddfcc52f7beed7c9c78ac3cc9f8a0a43416f23 100644 (file)
@@ -16,6 +16,11 @@ pub trait Default {
     fn default() -> Self;
 }
 
+impl Default for () {
+    #[inline]
+    fn default() -> () { () }
+}
+
 impl<T: Default + 'static> Default for @T {
     fn default() -> @T { @Default::default() }
 }
index 8a28f7b13928fc1d2287414a749eb68587fd4413..c4a2c9a609925fd15b9a565801c8399ad04d1bba 100644 (file)
@@ -9,21 +9,28 @@
 // except according to those terms.
 
 //! Failure support for libcore
+//!
+//! The core library cannot define failure, but it does *declare* failure. This
+//! means that the functions inside of libcore are allowed to fail, but to be
+//! useful an upstream crate must define failure for libcore to use. The current
+//! interface for failure is:
+//!
+//!     fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> !;
+//!
+//! This definition allows for failing with any general message, but it does not
+//! allow for failing with a `~Any` value. The reason for this is that libcore
+//! is not allowed to allocate.
+//!
+//! This module contains a few other failure functions, but these are just the
+//! necessary lang items for the compiler. All failure is funneled through this
+//! one function. Currently, the actual symbol is declared in the standard
+//! library, but the location of this may change over time.
 
 #![allow(dead_code, missing_doc)]
 
 #[cfg(not(test))]
 use str::raw::c_str_to_static_slice;
-
-// FIXME: Once std::fmt is in libcore, all of these functions should delegate
-//        to a common failure function with this signature:
-//
-//          extern {
-//              fn rust_unwind(f: &fmt::Arguments, file: &str, line: uint) -> !;
-//          }
-//
-//        Each of these functions can create a temporary fmt::Arguments
-//        structure to pass to this function.
+use fmt;
 
 #[cold] #[inline(never)] // this is the slow path, always
 #[lang="fail_"]
@@ -32,7 +39,11 @@ fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
     unsafe {
         let expr = c_str_to_static_slice(expr as *i8);
         let file = c_str_to_static_slice(file as *i8);
-        begin_unwind(expr, file, line)
+        format_args!(|args| -> () {
+            begin_unwind(args, file, line);
+        }, "{}", expr);
+
+        loop {}
     }
 }
 
@@ -40,16 +51,19 @@ fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
 #[lang="fail_bounds_check"]
 #[cfg(not(test))]
 fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
-    #[allow(ctypes)]
-    extern { fn rust_fail_bounds_check(file: *u8, line: uint,
-                                       index: uint, len: uint,) -> !; }
-    unsafe { rust_fail_bounds_check(file, line, index, len) }
+    let file = unsafe { c_str_to_static_slice(file as *i8) };
+    format_args!(|args| -> () {
+        begin_unwind(args, file, line);
+    }, "index out of bounds: the len is {} but the index is {}", len, index);
+    loop {}
 }
 
 #[cold]
-pub fn begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
+pub fn begin_unwind(fmt: &fmt::Arguments, file: &'static str, line: uint) -> ! {
+    // FIXME: this should be a proper lang item, it should not just be some
+    //        undefined symbol sitting in the middle of nowhere.
     #[allow(ctypes)]
-    extern { fn rust_begin_unwind(msg: &str, file: &'static str,
+    extern { fn rust_begin_unwind(fmt: &fmt::Arguments, file: &'static str,
                                   line: uint) -> !; }
-    unsafe { rust_begin_unwind(msg, file, line) }
+    unsafe { rust_begin_unwind(fmt, file, line) }
 }
diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs
new file mode 100644 (file)
index 0000000..e5fb148
--- /dev/null
@@ -0,0 +1,370 @@
+// Copyright 2013-2014 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 char;
+use container::Container;
+use fmt;
+use iter::{Iterator, range, DoubleEndedIterator};
+use num::{Float, FPNaN, FPInfinite, ToPrimitive, Primitive};
+use num::{Zero, One, cast};
+use option::{None, Some};
+use result::Ok;
+use slice::{ImmutableVector, MutableVector};
+use slice;
+use str::StrSlice;
+
+/// A flag that specifies whether to use exponential (scientific) notation.
+pub enum ExponentFormat {
+    /// Do not use exponential notation.
+    ExpNone,
+    /// Use exponential notation with the exponent having a base of 10 and the
+    /// exponent sign being `e` or `E`. For example, 1000 would be printed
+    /// 1e3.
+    ExpDec,
+    /// Use exponential notation with the exponent having a base of 2 and the
+    /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3.
+    ExpBin,
+}
+
+/// The number of digits used for emitting the fractional part of a number, if
+/// any.
+pub enum SignificantDigits {
+    /// All calculable digits will be printed.
+    ///
+    /// Note that bignums or fractions may cause a surprisingly large number
+    /// of digits to be printed.
+    DigAll,
+
+    /// At most the given number of digits will be printed, truncating any
+    /// trailing zeroes.
+    DigMax(uint),
+
+    /// Precisely the given number of digits will be printed.
+    DigExact(uint)
+}
+
+/// How to emit the sign of a number.
+pub enum SignFormat {
+    /// No sign will be printed. The exponent sign will also be emitted.
+    SignNone,
+    /// `-` will be printed for negative values, but no sign will be emitted
+    /// for positive numbers.
+    SignNeg,
+    /// `+` will be printed for positive values, and `-` will be printed for
+    /// negative values.
+    SignAll,
+}
+
+static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
+static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
+
+/**
+ * Converts a number to its string representation as a byte vector.
+ * This is meant to be a common base implementation for all numeric string
+ * conversion functions like `to_str()` or `to_str_radix()`.
+ *
+ * # Arguments
+ * - `num`           - The number to convert. Accepts any number that
+ *                     implements the numeric traits.
+ * - `radix`         - Base to use. Accepts only the values 2-36. If the exponential notation
+ *                     is used, then this base is only used for the significand. The exponent
+ *                     itself always printed using a base of 10.
+ * - `negative_zero` - Whether to treat the special value `-0` as
+ *                     `-0` or as `+0`.
+ * - `sign`          - How to emit the sign. See `SignFormat`.
+ * - `digits`        - The amount of digits to use for emitting the fractional
+ *                     part, if any. See `SignificantDigits`.
+ * - `exp_format`   - Whether or not to use the exponential (scientific) notation.
+ *                    See `ExponentFormat`.
+ * - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
+ *                     exponential notation is desired.
+ * - `f`             - A closure to invoke with the bytes representing the
+ *                     float.
+ *
+ * # Failure
+ * - Fails if `radix` < 2 or `radix` > 36.
+ * - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
+ *   between digit and exponent sign `'e'`.
+ * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
+ *   between digit and exponent sign `'p'`.
+ */
+pub fn float_to_str_bytes_common<T: Primitive + Float, U>(
+    num: T,
+    radix: uint,
+    negative_zero: bool,
+    sign: SignFormat,
+    digits: SignificantDigits,
+    exp_format: ExponentFormat,
+    exp_upper: bool,
+    f: |&[u8]| -> U
+) -> U {
+    assert!(2 <= radix && radix <= 36);
+    match exp_format {
+        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
+          => fail!("float_to_str_bytes_common: radix {} incompatible with \
+                    use of 'e' as decimal exponent", radix),
+        ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
+          => fail!("float_to_str_bytes_common: radix {} incompatible with \
+                    use of 'p' as binary exponent", radix),
+        _ => ()
+    }
+
+    let _0: T = Zero::zero();
+    let _1: T = One::one();
+
+    match num.classify() {
+        FPNaN => return f("NaN".as_bytes()),
+        FPInfinite if num > _0 => {
+            return match sign {
+                SignAll => return f("+inf".as_bytes()),
+                _       => return f("inf".as_bytes()),
+            };
+        }
+        FPInfinite if num < _0 => {
+            return match sign {
+                SignNone => return f("inf".as_bytes()),
+                _        => return f("-inf".as_bytes()),
+            };
+        }
+        _ => {}
+    }
+
+    let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
+    // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so
+    // we may have up to that many digits. Give ourselves some extra wiggle room
+    // otherwise as well.
+    let mut buf = [0u8, ..1536];
+    let mut end = 0;
+    let radix_gen: T = cast(radix as int).unwrap();
+
+    let (num, exp) = match exp_format {
+        ExpNone => (num, 0i32),
+        ExpDec | ExpBin if num == _0 => (num, 0i32),
+        ExpDec | ExpBin => {
+            let (exp, exp_base) = match exp_format {
+                ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
+                ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
+                ExpNone => fail!("unreachable"),
+            };
+
+            (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
+        }
+    };
+
+    // First emit the non-fractional part, looping at least once to make
+    // sure at least a `0` gets emitted.
+    let mut deccum = num.trunc();
+    loop {
+        // Calculate the absolute value of each digit instead of only
+        // doing it once for the whole number because a
+        // representable negative number doesn't necessary have an
+        // representable additive inverse of the same type
+        // (See twos complement). But we assume that for the
+        // numbers [-35 .. 0] we always have [0 .. 35].
+        let current_digit = (deccum % radix_gen).abs();
+
+        // Decrease the deccumulator one digit at a time
+        deccum = deccum / radix_gen;
+        deccum = deccum.trunc();
+
+        let c = char::from_digit(current_digit.to_int().unwrap() as uint, radix);
+        buf[end] = c.unwrap() as u8;
+        end += 1;
+
+        // No more digits to calculate for the non-fractional part -> break
+        if deccum == _0 { break; }
+    }
+
+    // If limited digits, calculate one digit more for rounding.
+    let (limit_digits, digit_count, exact) = match digits {
+        DigAll          => (false, 0u,      false),
+        DigMax(count)   => (true,  count+1, false),
+        DigExact(count) => (true,  count+1, true)
+    };
+
+    // Decide what sign to put in front
+    match sign {
+        SignNeg | SignAll if neg => {
+            buf[end] = '-' as u8;
+            end += 1;
+        }
+        SignAll => {
+            buf[end] = '+' as u8;
+            end += 1;
+        }
+        _ => ()
+    }
+
+    buf.mut_slice_to(end).reverse();
+
+    // Remember start of the fractional digits.
+    // Points one beyond end of buf if none get generated,
+    // or at the '.' otherwise.
+    let start_fractional_digits = end;
+
+    // Now emit the fractional part, if any
+    deccum = num.fract();
+    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
+        buf[end] = '.' as u8;
+        end += 1;
+        let mut dig = 0u;
+
+        // calculate new digits while
+        // - there is no limit and there are digits left
+        // - or there is a limit, it's not reached yet and
+        //   - it's exact
+        //   - or it's a maximum, and there are still digits left
+        while (!limit_digits && deccum != _0)
+           || (limit_digits && dig < digit_count && (
+                   exact
+                || (!exact && deccum != _0)
+              )
+        ) {
+            // Shift first fractional digit into the integer part
+            deccum = deccum * radix_gen;
+
+            // Calculate the absolute value of each digit.
+            // See note in first loop.
+            let current_digit = deccum.trunc().abs();
+
+            let c = char::from_digit(current_digit.to_int().unwrap() as uint,
+                                     radix);
+            buf[end] = c.unwrap() as u8;
+            end += 1;
+
+            // Decrease the deccumulator one fractional digit at a time
+            deccum = deccum.fract();
+            dig += 1u;
+        }
+
+        // If digits are limited, and that limit has been reached,
+        // cut off the one extra digit, and depending on its value
+        // round the remaining ones.
+        if limit_digits && dig == digit_count {
+            let ascii2value = |chr: u8| {
+                char::to_digit(chr as char, radix).unwrap()
+            };
+            let value2ascii = |val: uint| {
+                char::from_digit(val, radix).unwrap() as u8
+            };
+
+            let extra_digit = ascii2value(buf[end - 1]);
+            end -= 1;
+            if extra_digit >= radix / 2 { // -> need to round
+                let mut i: int = end as int - 1;
+                loop {
+                    // If reached left end of number, have to
+                    // insert additional digit:
+                    if i < 0
+                    || buf[i as uint] == '-' as u8
+                    || buf[i as uint] == '+' as u8 {
+                        for j in range(i as uint + 1, end).rev() {
+                            buf[j + 1] = buf[j];
+                        }
+                        buf[(i + 1) as uint] = value2ascii(1);
+                        end += 1;
+                        break;
+                    }
+
+                    // Skip the '.'
+                    if buf[i as uint] == '.' as u8 { i -= 1; continue; }
+
+                    // Either increment the digit,
+                    // or set to 0 if max and carry the 1.
+                    let current_digit = ascii2value(buf[i as uint]);
+                    if current_digit < (radix - 1) {
+                        buf[i as uint] = value2ascii(current_digit+1);
+                        break;
+                    } else {
+                        buf[i as uint] = value2ascii(0);
+                        i -= 1;
+                    }
+                }
+            }
+        }
+    }
+
+    // if number of digits is not exact, remove all trailing '0's up to
+    // and including the '.'
+    if !exact {
+        let buf_max_i = end - 1;
+
+        // index to truncate from
+        let mut i = buf_max_i;
+
+        // discover trailing zeros of fractional part
+        while i > start_fractional_digits && buf[i] == '0' as u8 {
+            i -= 1;
+        }
+
+        // Only attempt to truncate digits if buf has fractional digits
+        if i >= start_fractional_digits {
+            // If buf ends with '.', cut that too.
+            if buf[i] == '.' as u8 { i -= 1 }
+
+            // only resize buf if we actually remove digits
+            if i < buf_max_i {
+                end = i + 1;
+            }
+        }
+    } // If exact and trailing '.', just cut that
+    else {
+        let max_i = end - 1;
+        if buf[max_i] == '.' as u8 {
+            end = max_i;
+        }
+    }
+
+    match exp_format {
+        ExpNone => {},
+        _ => {
+            buf[end] = match exp_format {
+                ExpDec if exp_upper => 'E',
+                ExpDec if !exp_upper => 'e',
+                ExpBin if exp_upper => 'P',
+                ExpBin if !exp_upper => 'p',
+                _ => fail!("unreachable"),
+            } as u8;
+            end += 1;
+
+            struct Filler<'a> {
+                buf: &'a mut [u8],
+                end: &'a mut uint,
+            }
+
+            impl<'a> fmt::FormatWriter for Filler<'a> {
+                fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+                    slice::bytes::copy_memory(self.buf.mut_slice_from(*self.end),
+                                              bytes);
+                    *self.end += bytes.len();
+                    Ok(())
+                }
+            }
+
+            let mut filler = Filler { buf: buf, end: &mut end };
+            match sign {
+                SignNeg => {
+                    let _ = format_args!(|args| {
+                        fmt::write(&mut filler, args)
+                    }, "{:-}", exp);
+                }
+                SignNone | SignAll => {
+                    let _ = format_args!(|args| {
+                        fmt::write(&mut filler, args)
+                    }, "{}", exp);
+                }
+            }
+        }
+    }
+
+    f(buf.slice_to(end))
+}
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
new file mode 100644 (file)
index 0000000..979928c
--- /dev/null
@@ -0,0 +1,834 @@
+// Copyright 2013-2014 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.
+
+//! Utilities for formatting and printing strings
+
+#![allow(unused_variable)]
+
+use any;
+use cell::Cell;
+use char::Char;
+use container::Container;
+use iter::{Iterator, range};
+use kinds::Copy;
+use mem;
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use result;
+use slice::{Vector, ImmutableVector};
+use slice;
+use str::StrSlice;
+use str;
+
+pub use self::num::radix;
+pub use self::num::Radix;
+pub use self::num::RadixFmt;
+
+macro_rules! write(
+    ($dst:expr, $($arg:tt)*) => ({
+        format_args!(|args| { $dst.write_fmt(args) }, $($arg)*)
+    })
+)
+
+mod num;
+mod float;
+pub mod rt;
+
+pub type Result = result::Result<(), FormatError>;
+
+/// dox
+pub enum FormatError {
+    /// dox
+    WriteError,
+}
+
+/// dox
+pub trait FormatWriter {
+    /// dox
+    fn write(&mut self, bytes: &[u8]) -> Result;
+}
+
+/// A struct to represent both where to emit formatting strings to and how they
+/// should be formatted. A mutable version of this is passed to all formatting
+/// traits.
+pub struct Formatter<'a> {
+    /// Flags for formatting (packed version of rt::Flag)
+    pub flags: uint,
+    /// Character used as 'fill' whenever there is alignment
+    pub fill: char,
+    /// Boolean indication of whether the output should be left-aligned
+    pub align: rt::Alignment,
+    /// Optionally specified integer width that the output should be
+    pub width: Option<uint>,
+    /// Optionally specified precision for numeric types
+    pub precision: Option<uint>,
+
+    #[allow(missing_doc)]
+    #[cfg(stage0)]
+    pub buf: &'a mut FormatWriter,
+    #[cfg(not(stage0))]
+    buf: &'a mut FormatWriter,
+    curarg: slice::Items<'a, Argument<'a>>,
+    args: &'a [Argument<'a>],
+}
+
+enum CurrentlyFormatting<'a> {
+    Nothing,
+    RawString(&'a str),
+    Number(uint),
+}
+
+/// This struct represents the generic "argument" which is taken by the Xprintf
+/// family of functions. It contains a function to format the given value. At
+/// compile time it is ensured that the function and the value have the correct
+/// types, and then this struct is used to canonicalize arguments to one type.
+pub struct Argument<'a> {
+    formatter: extern "Rust" fn(&any::Void, &mut Formatter) -> Result,
+    value: &'a any::Void,
+}
+
+impl<'a> Arguments<'a> {
+    /// When using the format_args!() macro, this function is used to generate the
+    /// Arguments structure. The compiler inserts an `unsafe` block to call this,
+    /// which is valid because the compiler performs all necessary validation to
+    /// ensure that the resulting call to format/write would be safe.
+    #[doc(hidden)] #[inline]
+    pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
+                          args: &'a [Argument<'a>]) -> Arguments<'a> {
+        Arguments{ fmt: mem::transmute(fmt), args: args }
+    }
+}
+
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done so, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The `format_args!` macro will safely create an instance of this structure
+/// and pass it to a user-supplied function. The macro validates the format
+/// string at compile-time so usage of the `write` and `format` functions can
+/// be safely performed.
+pub struct Arguments<'a> {
+    fmt: &'a [rt::Piece<'a>],
+    args: &'a [Argument<'a>],
+}
+
+impl<'a> Show for Arguments<'a> {
+    fn fmt(&self, fmt: &mut Formatter) -> Result {
+        write(fmt.buf, self)
+    }
+}
+
+/// When a format is not otherwise specified, types are formatted by ascribing
+/// to this trait. There is not an explicit way of selecting this trait to be
+/// used for formatting, it is only if no other format is specified.
+pub trait Show {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `b` character
+pub trait Bool {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `c` character
+pub trait Char {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `i` and `d` characters
+pub trait Signed {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `u` character
+pub trait Unsigned {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `o` character
+pub trait Octal {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `t` character
+pub trait Binary {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `x` character
+pub trait LowerHex {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `X` character
+pub trait UpperHex {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `s` character
+pub trait String {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `p` character
+pub trait Pointer {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `f` character
+pub trait Float {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `e` character
+pub trait LowerExp {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `E` character
+pub trait UpperExp {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+// FIXME #11938 - UFCS would make us able call the above methods
+// directly Show::show(x, fmt).
+macro_rules! uniform_fn_call_workaround {
+    ($( $name: ident, $trait_: ident; )*) => {
+        $(
+            #[doc(hidden)]
+            pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) -> Result {
+                x.fmt(fmt)
+            }
+            )*
+    }
+}
+uniform_fn_call_workaround! {
+    secret_show, Show;
+    secret_bool, Bool;
+    secret_char, Char;
+    secret_signed, Signed;
+    secret_unsigned, Unsigned;
+    secret_octal, Octal;
+    secret_binary, Binary;
+    secret_lower_hex, LowerHex;
+    secret_upper_hex, UpperHex;
+    secret_string, String;
+    secret_pointer, Pointer;
+    secret_float, Float;
+    secret_lower_exp, LowerExp;
+    secret_upper_exp, UpperExp;
+}
+
+/// The `write` function takes an output stream, a precompiled format string,
+/// and a list of arguments. The arguments will be formatted according to the
+/// specified format string into the output stream provided.
+///
+/// # Arguments
+///
+///   * output - the buffer to write output to
+///   * args - the precompiled arguments generated by `format_args!`
+pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
+    let mut formatter = Formatter {
+        flags: 0,
+        width: None,
+        precision: None,
+        buf: output,
+        align: rt::AlignUnknown,
+        fill: ' ',
+        args: args.args,
+        curarg: args.args.iter(),
+    };
+    for piece in args.fmt.iter() {
+        try!(formatter.run(piece, Nothing));
+    }
+    Ok(())
+}
+
+impl<'a> Formatter<'a> {
+
+    // First up is the collection of functions used to execute a format string
+    // at runtime. This consumes all of the compile-time statics generated by
+    // the format! syntax extension.
+
+    fn run(&mut self, piece: &rt::Piece, cur: CurrentlyFormatting) -> Result {
+        match *piece {
+            rt::String(s) => self.buf.write(s.as_bytes()),
+            rt::CurrentArgument(()) => {
+                match cur {
+                    Nothing => Ok(()),
+                    Number(n) => secret_show(&radix(n, 10), self),
+                    RawString(s) => self.buf.write(s.as_bytes()),
+                }
+            }
+            rt::Argument(ref arg) => {
+                // Fill in the format parameters into the formatter
+                self.fill = arg.format.fill;
+                self.align = arg.format.align;
+                self.flags = arg.format.flags;
+                self.width = self.getcount(&arg.format.width);
+                self.precision = self.getcount(&arg.format.precision);
+
+                // Extract the correct argument
+                let value = match arg.position {
+                    rt::ArgumentNext => { *self.curarg.next().unwrap() }
+                    rt::ArgumentIs(i) => self.args[i],
+                };
+
+                // Then actually do some printing
+                match arg.method {
+                    None => (value.formatter)(value.value, self),
+                    Some(ref method) => self.execute(*method, value)
+                }
+            }
+        }
+    }
+
+    fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
+        match *cnt {
+            rt::CountIs(n) => { Some(n) }
+            rt::CountImplied => { None }
+            rt::CountIsParam(i) => {
+                let v = self.args[i].value;
+                unsafe { Some(*(v as *any::Void as *uint)) }
+            }
+            rt::CountIsNextParam => {
+                let v = self.curarg.next().unwrap().value;
+                unsafe { Some(*(v as *any::Void as *uint)) }
+            }
+        }
+    }
+
+    fn execute(&mut self, method: &rt::Method, arg: Argument) -> Result {
+        match *method {
+            // Pluralization is selection upon a numeric value specified as the
+            // parameter.
+            rt::Plural(offset, ref selectors, ref default) => {
+                // This is validated at compile-time to be a pointer to a
+                // '&uint' value.
+                let value: &uint = unsafe { mem::transmute(arg.value) };
+                let value = *value;
+
+                // First, attempt to match against explicit values without the
+                // offsetted value
+                for s in selectors.iter() {
+                    match s.selector {
+                        rt::Literal(val) if value == val => {
+                            return self.runplural(value, s.result);
+                        }
+                        _ => {}
+                    }
+                }
+
+                // Next, offset the value and attempt to match against the
+                // keyword selectors.
+                let value = value - match offset { Some(i) => i, None => 0 };
+                for s in selectors.iter() {
+                    let run = match s.selector {
+                        rt::Keyword(rt::Zero) => value == 0,
+                        rt::Keyword(rt::One) => value == 1,
+                        rt::Keyword(rt::Two) => value == 2,
+
+                        // FIXME: Few/Many should have a user-specified boundary
+                        //      One possible option would be in the function
+                        //      pointer of the 'arg: Argument' struct.
+                        rt::Keyword(rt::Few) => value < 8,
+                        rt::Keyword(rt::Many) => value >= 8,
+
+                        rt::Literal(..) => false
+                    };
+                    if run {
+                        return self.runplural(value, s.result);
+                    }
+                }
+
+                self.runplural(value, *default)
+            }
+
+            // Select is just a matching against the string specified.
+            rt::Select(ref selectors, ref default) => {
+                // This is validated at compile-time to be a pointer to a
+                // string slice,
+                let value: & &str = unsafe { mem::transmute(arg.value) };
+                let value = *value;
+
+                for s in selectors.iter() {
+                    if s.selector == value {
+                        for piece in s.result.iter() {
+                            try!(self.run(piece, RawString(value)));
+                        }
+                        return Ok(());
+                    }
+                }
+                for piece in default.iter() {
+                    try!(self.run(piece, RawString(value)));
+                }
+                Ok(())
+            }
+        }
+    }
+
+    fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) -> Result {
+        for piece in pieces.iter() {
+            try!(self.run(piece, Number(value)));
+        }
+        Ok(())
+    }
+
+    // Helper methods used for padding and processing formatting arguments that
+    // all formatting traits can use.
+
+    /// Performs the correct padding for an integer which has already been
+    /// emitted into a byte-array. The byte-array should *not* contain the sign
+    /// for the integer, that will be added by this method.
+    ///
+    /// # Arguments
+    ///
+    /// * is_positive - whether the original integer was positive or not.
+    /// * prefix - if the '#' character (FlagAlternate) is provided, this
+    ///   is the prefix to put in front of the number.
+    /// * buf - the byte array that the number has been formatted into
+    ///
+    /// This function will correctly account for the flags provided as well as
+    /// the minimum width. It will not take precision into account.
+    pub fn pad_integral(&mut self, is_positive: bool, prefix: &str,
+                        buf: &[u8]) -> Result {
+        use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
+
+        let mut width = buf.len();
+
+        let mut sign = None;
+        if !is_positive {
+            sign = Some('-'); width += 1;
+        } else if self.flags & (1 << (FlagSignPlus as uint)) != 0 {
+            sign = Some('+'); width += 1;
+        }
+
+        let mut prefixed = false;
+        if self.flags & (1 << (FlagAlternate as uint)) != 0 {
+            prefixed = true; width += prefix.len();
+        }
+
+        // Writes the sign if it exists, and then the prefix if it was requested
+        let write_prefix = |f: &mut Formatter| {
+            for c in sign.move_iter() {
+                let mut b = [0, ..4];
+                let n = c.encode_utf8(b);
+                try!(f.buf.write(b.slice_to(n)));
+            }
+            if prefixed { f.buf.write(prefix.as_bytes()) }
+            else { Ok(()) }
+        };
+
+        // The `width` field is more of a `min-width` parameter at this point.
+        match self.width {
+            // If there's no minimum length requirements then we can just
+            // write the bytes.
+            None => {
+                try!(write_prefix(self)); self.buf.write(buf)
+            }
+            // Check if we're over the minimum width, if so then we can also
+            // just write the bytes.
+            Some(min) if width >= min => {
+                try!(write_prefix(self)); self.buf.write(buf)
+            }
+            // The sign and prefix goes before the padding if the fill character
+            // is zero
+            Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
+                self.fill = '0';
+                try!(write_prefix(self));
+                self.with_padding(min - width, rt::AlignRight, |f| f.buf.write(buf))
+            }
+            // Otherwise, the sign and prefix goes after the padding
+            Some(min) => {
+                self.with_padding(min - width, rt::AlignRight, |f| {
+                    try!(write_prefix(f)); f.buf.write(buf)
+                })
+            }
+        }
+    }
+
+    /// This function takes a string slice and emits it to the internal buffer
+    /// after applying the relevant formatting flags specified. The flags
+    /// recognized for generic strings are:
+    ///
+    /// * width - the minimum width of what to emit
+    /// * fill/align - what to emit and where to emit it if the string
+    ///                provided needs to be padded
+    /// * precision - the maximum length to emit, the string is truncated if it
+    ///               is longer than this length
+    ///
+    /// Notably this function ignored the `flag` parameters
+    pub fn pad(&mut self, s: &str) -> Result {
+        // Make sure there's a fast path up front
+        if self.width.is_none() && self.precision.is_none() {
+            return self.buf.write(s.as_bytes());
+        }
+        // The `precision` field can be interpreted as a `max-width` for the
+        // string being formatted
+        match self.precision {
+            Some(max) => {
+                // If there's a maximum width and our string is longer than
+                // that, then we must always have truncation. This is the only
+                // case where the maximum length will matter.
+                let char_len = s.char_len();
+                if char_len >= max {
+                    let nchars = ::cmp::min(max, char_len);
+                    return self.buf.write(s.slice_chars(0, nchars).as_bytes());
+                }
+            }
+            None => {}
+        }
+        // The `width` field is more of a `min-width` parameter at this point.
+        match self.width {
+            // If we're under the maximum length, and there's no minimum length
+            // requirements, then we can just emit the string
+            None => self.buf.write(s.as_bytes()),
+            // If we're under the maximum width, check if we're over the minimum
+            // width, if so it's as easy as just emitting the string.
+            Some(width) if s.char_len() >= width => {
+                self.buf.write(s.as_bytes())
+            }
+            // If we're under both the maximum and the minimum width, then fill
+            // up the minimum width with the specified string + some alignment.
+            Some(width) => {
+                self.with_padding(width - s.len(), rt::AlignLeft, |me| {
+                    me.buf.write(s.as_bytes())
+                })
+            }
+        }
+    }
+
+    /// Runs a callback, emitting the correct padding either before or
+    /// afterwards depending on whether right or left alingment is requested.
+    fn with_padding(&mut self,
+                    padding: uint,
+                    default: rt::Alignment,
+                    f: |&mut Formatter| -> Result) -> Result {
+        let align = match self.align {
+            rt::AlignUnknown => default,
+            rt::AlignLeft | rt::AlignRight => self.align
+        };
+        if align == rt::AlignLeft {
+            try!(f(self));
+        }
+        let mut fill = [0u8, ..4];
+        let len = self.fill.encode_utf8(fill);
+        for _ in range(0, padding) {
+            try!(self.buf.write(fill.slice_to(len)));
+        }
+        if align == rt::AlignRight {
+            try!(f(self));
+        }
+        Ok(())
+    }
+
+    /// Writes some data to the underlying buffer contained within this
+    /// formatter.
+    pub fn write(&mut self, data: &[u8]) -> Result {
+        self.buf.write(data)
+    }
+
+    /// Writes some formatted information into this instance
+    pub fn write_fmt(&mut self, fmt: &Arguments) -> Result {
+        write(self.buf, fmt)
+    }
+}
+
+/// This is a function which calls are emitted to by the compiler itself to
+/// create the Argument structures that are passed into the `format` function.
+#[doc(hidden)] #[inline]
+pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result,
+                       t: &'a T) -> Argument<'a> {
+    unsafe {
+        Argument {
+            formatter: mem::transmute(f),
+            value: mem::transmute(t)
+        }
+    }
+}
+
+#[cfg(test)]
+pub fn format(args: &Arguments) -> ~str {
+    use str;
+    use realstd::str::StrAllocating;
+    use realstd::io::MemWriter;
+
+    fn mywrite<T: ::realstd::io::Writer>(t: &mut T, b: &[u8]) {
+        use realstd::io::Writer;
+        let _ = t.write(b);
+    }
+
+    impl FormatWriter for MemWriter {
+        fn write(&mut self, bytes: &[u8]) -> Result {
+            mywrite(self, bytes);
+            Ok(())
+        }
+    }
+
+    let mut i = MemWriter::new();
+    let _ = write(&mut i, args);
+    str::from_utf8(i.get_ref()).unwrap().to_owned()
+}
+
+/// When the compiler determines that the type of an argument *must* be a string
+/// (such as for select), then it invokes this method.
+#[doc(hidden)] #[inline]
+pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
+    argument(secret_string, s)
+}
+
+/// When the compiler determines that the type of an argument *must* be a uint
+/// (such as for plural), then it invokes this method.
+#[doc(hidden)] #[inline]
+pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
+    argument(secret_unsigned, s)
+}
+
+// Implementations of the core formatting traits
+
+impl<T: Show> Show for @T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
+}
+impl<'a, T: Show> Show for &'a T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
+}
+impl<'a, T: Show> Show for &'a mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
+}
+
+impl Bool for bool {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_string(&(if *self {"true"} else {"false"}), f)
+    }
+}
+
+impl<'a, T: str::Str> String for T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.pad(self.as_slice())
+    }
+}
+
+impl Char for char {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        let mut utf8 = [0u8, ..4];
+        let amt = self.encode_utf8(utf8);
+        let s: &str = unsafe { mem::transmute(utf8.slice_to(amt)) };
+        secret_string(&s, f)
+    }
+}
+
+impl<T> Pointer for *T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.flags |= 1 << (rt::FlagAlternate as uint);
+        secret_lower_hex::<uint>(&(*self as uint), f)
+    }
+}
+impl<T> Pointer for *mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(*self as *T), f)
+    }
+}
+impl<'a, T> Pointer for &'a T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(&**self as *T), f)
+    }
+}
+impl<'a, T> Pointer for &'a mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(&**self as *T), f)
+    }
+}
+
+macro_rules! floating(($ty:ident) => {
+    impl Float for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpNone,
+                                             false,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+
+    impl LowerExp for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpDec,
+                                             false,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+
+    impl UpperExp for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpDec,
+                                             true,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+})
+floating!(f32)
+floating!(f64)
+
+// Implementation of Show for various core types
+
+macro_rules! delegate(($ty:ty to $other:ident) => {
+    impl<'a> Show for $ty {
+        fn fmt(&self, f: &mut Formatter) -> Result {
+            (concat_idents!(secret_, $other)(self, f))
+        }
+    }
+})
+delegate!(~str to string)
+delegate!(&'a str to string)
+delegate!(bool to bool)
+delegate!(char to char)
+delegate!(f32 to float)
+delegate!(f64 to float)
+
+impl<T> Show for *T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
+}
+impl<T> Show for *mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
+}
+
+macro_rules! peel(($name:ident, $($other:ident,)*) => (tuple!($($other,)*)))
+
+macro_rules! tuple (
+    () => ();
+    ( $($name:ident,)+ ) => (
+        impl<$($name:Show),*> Show for ($($name,)*) {
+            #[allow(uppercase_variables, dead_assignment)]
+            fn fmt(&self, f: &mut Formatter) -> Result {
+                try!(write!(f, "("));
+                let ($(ref $name,)*) = *self;
+                let mut n = 0;
+                $(
+                    if n > 0 {
+                        try!(write!(f, ", "));
+                    }
+                    try!(write!(f, "{}", *$name));
+                    n += 1;
+                )*
+                if n == 1 {
+                    try!(write!(f, ","));
+                }
+                write!(f, ")")
+            }
+        }
+        peel!($($name,)*)
+    )
+)
+
+tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
+
+impl<'a> Show for &'a any::Any {
+    fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
+}
+
+impl<'a, T: Show> Show for &'a [T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
+            try!(write!(f, "["));
+        }
+        let mut is_first = true;
+        for x in self.iter() {
+            if is_first {
+                is_first = false;
+            } else {
+                try!(write!(f, ", "));
+            }
+            try!(write!(f, "{}", *x))
+        }
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
+            try!(write!(f, "]"));
+        }
+        Ok(())
+    }
+}
+
+impl<'a, T: Show> Show for &'a mut [T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_show(&self.as_slice(), f)
+    }
+}
+
+impl<T: Show> Show for ~[T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_show(&self.as_slice(), f)
+    }
+}
+
+impl Show for () {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.pad("()")
+    }
+}
+
+impl<T: Copy + Show> Show for Cell<T> {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        write!(f, r"Cell \{ value: {} \}", self.get())
+    }
+}
+
+// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
+// it's a lot easier than creating all of the rt::Piece structures here.
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
new file mode 100644 (file)
index 0000000..d9a3271
--- /dev/null
@@ -0,0 +1,470 @@
+// Copyright 2014 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.
+
+//! Integer and floating-point number formatting
+
+// FIXME: #6220 Implement floating point formatting
+
+#![allow(unsigned_negate)]
+
+use container::Container;
+use fmt;
+use iter::{Iterator, DoubleEndedIterator};
+use num::{Int, cast, zero};
+use option::{Some, None};
+use slice::{ImmutableVector, MutableVector};
+
+/// A type that represents a specific radix
+trait GenericRadix {
+    /// The number of digits.
+    fn base(&self) -> u8;
+
+    /// A radix-specific prefix string.
+    fn prefix(&self) -> &'static str { "" }
+
+    /// Converts an integer to corresponding radix digit.
+    fn digit(&self, x: u8) -> u8;
+
+    /// Format an integer using the radix using a formatter.
+    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
+        // The radix can be as low as 2, so we need a buffer of at least 64
+        // characters for a base 2 number.
+        let mut buf = [0u8, ..64];
+        let base = cast(self.base()).unwrap();
+        let mut curr = buf.len();
+        let is_positive = x >= zero();
+        if is_positive {
+            // Accumulate each digit of the number from the least significant
+            // to the most significant figure.
+            for byte in buf.mut_iter().rev() {
+                let n = x % base;                         // Get the current place value.
+                x = x / base;                             // Deaccumulate the number.
+                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
+                curr -= 1;
+                if x == zero() { break; }                 // No more digits left to accumulate.
+            }
+        } else {
+            // Do the same as above, but accounting for two's complement.
+            for byte in buf.mut_iter().rev() {
+                let n = -(x % base);                      // Get the current place value.
+                x = x / base;                             // Deaccumulate the number.
+                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
+                curr -= 1;
+                if x == zero() { break; }                 // No more digits left to accumulate.
+            }
+        }
+        f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr))
+    }
+}
+
+/// A binary (base 2) radix
+#[deriving(Clone, Eq)]
+struct Binary;
+
+/// An octal (base 8) radix
+#[deriving(Clone, Eq)]
+struct Octal;
+
+/// A decimal (base 10) radix
+#[deriving(Clone, Eq)]
+struct Decimal;
+
+/// A hexadecimal (base 16) radix, formatted with lower-case characters
+#[deriving(Clone, Eq)]
+struct LowerHex;
+
+/// A hexadecimal (base 16) radix, formatted with upper-case characters
+#[deriving(Clone, Eq)]
+pub struct UpperHex;
+
+macro_rules! radix {
+    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
+        impl GenericRadix for $T {
+            fn base(&self) -> u8 { $base }
+            fn prefix(&self) -> &'static str { $prefix }
+            fn digit(&self, x: u8) -> u8 {
+                match x {
+                    $($x => $conv,)+
+                    x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
+                }
+            }
+        }
+    }
+}
+
+radix!(Binary,    2, "0b", x @  0 .. 2 => '0' as u8 + x)
+radix!(Octal,     8, "0o", x @  0 .. 7 => '0' as u8 + x)
+radix!(Decimal,  10, "",   x @  0 .. 9 => '0' as u8 + x)
+radix!(LowerHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
+                           x @ 10 ..15 => 'a' as u8 + (x - 10))
+radix!(UpperHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
+                           x @ 10 ..15 => 'A' as u8 + (x - 10))
+
+/// A radix with in the range of `2..36`.
+#[deriving(Clone, Eq)]
+pub struct Radix {
+    base: u8,
+}
+
+impl Radix {
+    fn new(base: u8) -> Radix {
+        assert!(2 <= base && base <= 36, "the base must be in the range of 0..36: {}", base);
+        Radix { base: base }
+    }
+}
+
+impl GenericRadix for Radix {
+    fn base(&self) -> u8 { self.base }
+    fn digit(&self, x: u8) -> u8 {
+        match x {
+            x @  0 ..9 => '0' as u8 + x,
+            x if x < self.base() => 'a' as u8 + (x - 10),
+            x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
+        }
+    }
+}
+
+/// A helper type for formatting radixes.
+pub struct RadixFmt<T, R>(T, R);
+
+/// Constructs a radix formatter in the range of `2..36`.
+///
+/// # Example
+///
+/// ~~~
+/// use std::fmt::radix;
+/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
+/// ~~~
+pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
+    RadixFmt(x, Radix::new(base))
+}
+
+macro_rules! radix_fmt {
+    ($T:ty as $U:ty, $fmt:ident) => {
+        impl fmt::Show for RadixFmt<$T, Radix> {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
+            }
+        }
+    }
+}
+macro_rules! int_base {
+    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
+        impl fmt::$Trait for $T {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                $Radix.fmt_int(*self as $U, f)
+            }
+        }
+    }
+}
+macro_rules! integer {
+    ($Int:ident, $Uint:ident) => {
+        int_base!(Show     for $Int as $Int   -> Decimal)
+        int_base!(Signed   for $Int as $Int   -> Decimal)
+        int_base!(Binary   for $Int as $Uint  -> Binary)
+        int_base!(Octal    for $Int as $Uint  -> Octal)
+        int_base!(LowerHex for $Int as $Uint  -> LowerHex)
+        int_base!(UpperHex for $Int as $Uint  -> UpperHex)
+        radix_fmt!($Int as $Int, fmt_int)
+
+        int_base!(Show     for $Uint as $Uint -> Decimal)
+        int_base!(Unsigned for $Uint as $Uint -> Decimal)
+        int_base!(Binary   for $Uint as $Uint -> Binary)
+        int_base!(Octal    for $Uint as $Uint -> Octal)
+        int_base!(LowerHex for $Uint as $Uint -> LowerHex)
+        int_base!(UpperHex for $Uint as $Uint -> UpperHex)
+        radix_fmt!($Uint as $Uint, fmt_int)
+    }
+}
+integer!(int, uint)
+integer!(i8, u8)
+integer!(i16, u16)
+integer!(i32, u32)
+integer!(i64, u64)
+
+#[cfg(test)]
+mod tests {
+    use fmt::radix;
+    use super::{Binary, Octal, Decimal, LowerHex, UpperHex};
+    use super::{GenericRadix, Radix};
+    use realstd::str::StrAllocating;
+
+    #[test]
+    fn test_radix_base() {
+        assert_eq!(Binary.base(), 2);
+        assert_eq!(Octal.base(), 8);
+        assert_eq!(Decimal.base(), 10);
+        assert_eq!(LowerHex.base(), 16);
+        assert_eq!(UpperHex.base(), 16);
+        assert_eq!(Radix { base: 36 }.base(), 36);
+    }
+
+    #[test]
+    fn test_radix_prefix() {
+        assert_eq!(Binary.prefix(), "0b");
+        assert_eq!(Octal.prefix(), "0o");
+        assert_eq!(Decimal.prefix(), "");
+        assert_eq!(LowerHex.prefix(), "0x");
+        assert_eq!(UpperHex.prefix(), "0x");
+        assert_eq!(Radix { base: 36 }.prefix(), "");
+    }
+
+    #[test]
+    fn test_radix_digit() {
+        assert_eq!(Binary.digit(0), '0' as u8);
+        assert_eq!(Binary.digit(2), '2' as u8);
+        assert_eq!(Octal.digit(0), '0' as u8);
+        assert_eq!(Octal.digit(7), '7' as u8);
+        assert_eq!(Decimal.digit(0), '0' as u8);
+        assert_eq!(Decimal.digit(9), '9' as u8);
+        assert_eq!(LowerHex.digit(0), '0' as u8);
+        assert_eq!(LowerHex.digit(10), 'a' as u8);
+        assert_eq!(LowerHex.digit(15), 'f' as u8);
+        assert_eq!(UpperHex.digit(0), '0' as u8);
+        assert_eq!(UpperHex.digit(10), 'A' as u8);
+        assert_eq!(UpperHex.digit(15), 'F' as u8);
+        assert_eq!(Radix { base: 36 }.digit(0), '0' as u8);
+        assert_eq!(Radix { base: 36 }.digit(15), 'f' as u8);
+        assert_eq!(Radix { base: 36 }.digit(35), 'z' as u8);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_hex_radix_digit_overflow() {
+        let _ = LowerHex.digit(16);
+    }
+
+    #[test]
+    fn test_format_int() {
+        // Formatting integers should select the right implementation based off
+        // the type of the argument. Also, hex/octal/binary should be defined
+        // for integers, but they shouldn't emit the negative sign.
+        assert_eq!(format!("{}", 1i), "1".to_owned());
+        assert_eq!(format!("{}", 1i8), "1".to_owned());
+        assert_eq!(format!("{}", 1i16), "1".to_owned());
+        assert_eq!(format!("{}", 1i32), "1".to_owned());
+        assert_eq!(format!("{}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:d}", -1i), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i8), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i16), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i32), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i64), "-1".to_owned());
+        assert_eq!(format!("{:t}", 1i), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i64), "1".to_owned());
+
+        assert_eq!(format!("{}", 1u), "1".to_owned());
+        assert_eq!(format!("{}", 1u8), "1".to_owned());
+        assert_eq!(format!("{}", 1u16), "1".to_owned());
+        assert_eq!(format!("{}", 1u32), "1".to_owned());
+        assert_eq!(format!("{}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u64), "1".to_owned());
+
+        // Test a larger number
+        assert_eq!(format!("{:t}", 55), "110111".to_owned());
+        assert_eq!(format!("{:o}", 55), "67".to_owned());
+        assert_eq!(format!("{:d}", 55), "55".to_owned());
+        assert_eq!(format!("{:x}", 55), "37".to_owned());
+        assert_eq!(format!("{:X}", 55), "37".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_zero() {
+        assert_eq!(format!("{}", 0i), "0".to_owned());
+        assert_eq!(format!("{:d}", 0i), "0".to_owned());
+        assert_eq!(format!("{:t}", 0i), "0".to_owned());
+        assert_eq!(format!("{:o}", 0i), "0".to_owned());
+        assert_eq!(format!("{:x}", 0i), "0".to_owned());
+        assert_eq!(format!("{:X}", 0i), "0".to_owned());
+
+        assert_eq!(format!("{}", 0u), "0".to_owned());
+        assert_eq!(format!("{:u}", 0u), "0".to_owned());
+        assert_eq!(format!("{:t}", 0u), "0".to_owned());
+        assert_eq!(format!("{:o}", 0u), "0".to_owned());
+        assert_eq!(format!("{:x}", 0u), "0".to_owned());
+        assert_eq!(format!("{:X}", 0u), "0".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_flags() {
+        assert_eq!(format!("{:3d}", 1), "  1".to_owned());
+        assert_eq!(format!("{:>3d}", 1), "  1".to_owned());
+        assert_eq!(format!("{:>+3d}", 1), " +1".to_owned());
+        assert_eq!(format!("{:<3d}", 1), "1  ".to_owned());
+        assert_eq!(format!("{:#d}", 1), "1".to_owned());
+        assert_eq!(format!("{:#x}", 10), "0xa".to_owned());
+        assert_eq!(format!("{:#X}", 10), "0xA".to_owned());
+        assert_eq!(format!("{:#5x}", 10), "  0xa".to_owned());
+        assert_eq!(format!("{:#o}", 10), "0o12".to_owned());
+        assert_eq!(format!("{:08x}", 10), "0000000a".to_owned());
+        assert_eq!(format!("{:8x}", 10), "       a".to_owned());
+        assert_eq!(format!("{:<8x}", 10), "a       ".to_owned());
+        assert_eq!(format!("{:>8x}", 10), "       a".to_owned());
+        assert_eq!(format!("{:#08x}", 10), "0x00000a".to_owned());
+        assert_eq!(format!("{:08d}", -10), "-0000010".to_owned());
+        assert_eq!(format!("{:x}", -1u8), "ff".to_owned());
+        assert_eq!(format!("{:X}", -1u8), "FF".to_owned());
+        assert_eq!(format!("{:t}", -1u8), "11111111".to_owned());
+        assert_eq!(format!("{:o}", -1u8), "377".to_owned());
+        assert_eq!(format!("{:#x}", -1u8), "0xff".to_owned());
+        assert_eq!(format!("{:#X}", -1u8), "0xFF".to_owned());
+        assert_eq!(format!("{:#t}", -1u8), "0b11111111".to_owned());
+        assert_eq!(format!("{:#o}", -1u8), "0o377".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_sign_padding() {
+        assert_eq!(format!("{:+5d}", 1), "   +1".to_owned());
+        assert_eq!(format!("{:+5d}", -1), "   -1".to_owned());
+        assert_eq!(format!("{:05d}", 1), "00001".to_owned());
+        assert_eq!(format!("{:05d}", -1), "-0001".to_owned());
+        assert_eq!(format!("{:+05d}", 1), "+0001".to_owned());
+        assert_eq!(format!("{:+05d}", -1), "-0001".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_twos_complement() {
+        use {i8, i16, i32, i64};
+        assert_eq!(format!("{}", i8::MIN), "-128".to_owned());
+        assert_eq!(format!("{}", i16::MIN), "-32768".to_owned());
+        assert_eq!(format!("{}", i32::MIN), "-2147483648".to_owned());
+        assert_eq!(format!("{}", i64::MIN), "-9223372036854775808".to_owned());
+    }
+
+    #[test]
+    fn test_format_radix() {
+        assert_eq!(format!("{:04}", radix(3, 2)), "0011".to_owned());
+        assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_radix_base_too_large() {
+        let _ = radix(55, 37);
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    extern crate test;
+
+    mod uint {
+        use super::test::Bencher;
+        use fmt::radix;
+        use rand::{XorShiftRng, Rng};
+
+        #[bench]
+        fn format_bin(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:t}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_oct(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:o}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_dec(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:u}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_hex(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:x}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_base_36(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{}", radix(rng.gen::<uint>(), 36)); })
+        }
+    }
+
+    mod int {
+        use super::test::Bencher;
+        use fmt::radix;
+        use rand::{XorShiftRng, Rng};
+
+        #[bench]
+        fn format_bin(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:t}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_oct(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:o}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_dec(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:d}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_hex(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:x}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_base_36(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{}", radix(rng.gen::<int>(), 36)); })
+        }
+    }
+}
diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs
new file mode 100644 (file)
index 0000000..00c8661
--- /dev/null
@@ -0,0 +1,91 @@
+// 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 is an internal module used by the ifmt! runtime. These structures are
+//! emitted to static arrays to precompile format strings ahead of time.
+//!
+//! These definitions are similar to their `ct` equivalents, but differ in that
+//! these can be statically allocated and are slightly optimized for the runtime
+
+#![allow(missing_doc)]
+#![doc(hidden)]
+
+use option::Option;
+
+pub enum Piece<'a> {
+    String(&'a str),
+    // FIXME(#8259): this shouldn't require the unit-value here
+    CurrentArgument(()),
+    Argument(Argument<'a>),
+}
+
+pub struct Argument<'a> {
+    pub position: Position,
+    pub format: FormatSpec,
+    pub method: Option<&'a Method<'a>>
+}
+
+pub struct FormatSpec {
+    pub fill: char,
+    pub align: Alignment,
+    pub flags: uint,
+    pub precision: Count,
+    pub width: Count,
+}
+
+#[deriving(Eq)]
+pub enum Alignment {
+    AlignLeft,
+    AlignRight,
+    AlignUnknown,
+}
+
+pub enum Count {
+    CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
+}
+
+pub enum Position {
+    ArgumentNext, ArgumentIs(uint)
+}
+
+pub enum Flag {
+    FlagSignPlus,
+    FlagSignMinus,
+    FlagAlternate,
+    FlagSignAwareZeroPad,
+}
+
+pub enum Method<'a> {
+    Plural(Option<uint>, &'a [PluralArm<'a>], &'a [Piece<'a>]),
+    Select(&'a [SelectArm<'a>], &'a [Piece<'a>]),
+}
+
+pub enum PluralSelector {
+    Keyword(PluralKeyword),
+    Literal(uint),
+}
+
+pub enum PluralKeyword {
+    Zero,
+    One,
+    Two,
+    Few,
+    Many,
+}
+
+pub struct PluralArm<'a> {
+    pub selector: PluralSelector,
+    pub result: &'a [Piece<'a>],
+}
+
+pub struct SelectArm<'a> {
+    pub selector: &'a str,
+    pub result: &'a [Piece<'a>],
+}
index 2828c9bdc231dfdca4347ab1531008215926925d..a5003a1458e119a7bf14776bcd52f13e1a16dc2f 100644 (file)
@@ -471,7 +471,7 @@ fn visit_leave_fn(&mut self, purity: uint, proto: uint,
 /// `TypeId` represents a globally unique identifier for a type
 #[lang="type_id"] // This needs to be kept in lockstep with the code in trans/intrinsic.rs and
                   // middle/lang_items.rs
-#[deriving(Eq, TotalEq)]
+#[deriving(Eq, TotalEq, Show)]
 #[cfg(not(test))]
 pub struct TypeId {
     t: u64,
index f6a77d6decae048c278ef1de1d7fac4695c0d7f6..d40701860f46eb09ed85117e205ef3fe0fec0623 100644 (file)
@@ -969,7 +969,7 @@ fn min_max(&mut self) -> MinMaxResult<A> {
 }
 
 /// `MinMaxResult` is an enum returned by `min_max`. See `OrdIterator::min_max` for more detail.
-#[deriving(Clone, Eq)]
+#[deriving(Clone, Eq, Show)]
 pub enum MinMaxResult<T> {
     /// Empty iterator
     NoElements,
@@ -2329,19 +2329,48 @@ fn test_lt() {
 
 #[cfg(test)]
 mod tests {
-    use realstd::prelude::*;
-    use realstd::iter::*;
-    use realstd::num;
+    use prelude::*;
+    use iter::*;
+    use num;
+    use realstd::vec::Vec;
+    use realstd::slice::Vector;
 
     use cmp;
     use realstd::owned::Box;
     use uint;
 
+    impl<T> FromIterator<T> for Vec<T> {
+        fn from_iter<I: Iterator<T>>(mut iterator: I) -> Vec<T> {
+            let mut v = Vec::new();
+            for e in iterator {
+                v.push(e);
+            }
+            return v;
+        }
+    }
+
+    impl<'a, T> Iterator<&'a T> for ::realcore::slice::Items<'a, T> {
+        fn next(&mut self) -> Option<&'a T> {
+            use RealSome = realcore::option::Some;
+            use RealNone = realcore::option::None;
+            fn mynext<T, I: ::realcore::iter::Iterator<T>>(i: &mut I)
+                -> ::realcore::option::Option<T>
+            {
+                use realcore::iter::Iterator;
+                i.next()
+            }
+            match mynext(self) {
+                RealSome(t) => Some(t),
+                RealNone => None,
+            }
+        }
+    }
+
     #[test]
     fn test_counter_from_iter() {
         let it = count(0, 5).take(10);
         let xs: Vec<int> = FromIterator::from_iter(it);
-        assert_eq!(xs, vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
+        assert!(xs == vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
     }
 
     #[test]
@@ -2371,7 +2400,7 @@ fn test_iterator_chain() {
     fn test_filter_map() {
         let mut it = count(0u, 1u).take(10)
             .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
-        assert_eq!(it.collect::<Vec<uint>>(), vec![0*0, 2*2, 4*4, 6*6, 8*8]);
+        assert!(it.collect::<Vec<uint>>() == vec![0*0, 2*2, 4*4, 6*6, 8*8]);
     }
 
     #[test]
@@ -2630,7 +2659,7 @@ fn test_iterator_size_hint() {
     fn test_collect() {
         let a = vec![1, 2, 3, 4, 5];
         let b: Vec<int> = a.iter().map(|&x| x).collect();
-        assert_eq!(a, b);
+        assert!(a == b);
     }
 
     #[test]
@@ -2702,7 +2731,8 @@ fn test_rev() {
         let mut it = xs.iter();
         it.next();
         it.next();
-        assert_eq!(it.rev().map(|&x| x).collect::<Vec<int>>(), vec![16, 14, 12, 10, 8, 6]);
+        assert!(it.rev().map(|&x| x).collect::<Vec<int>>() ==
+                vec![16, 14, 12, 10, 8, 6]);
     }
 
     #[test]
@@ -2940,12 +2970,12 @@ fn test_random_access_cycle() {
 
     #[test]
     fn test_double_ended_range() {
-        assert_eq!(range(11i, 14).rev().collect::<Vec<int>>(), vec![13i, 12, 11]);
+        assert!(range(11i, 14).rev().collect::<Vec<int>>() == vec![13i, 12, 11]);
         for _ in range(10i, 0).rev() {
             fail!("unreachable");
         }
 
-        assert_eq!(range(11u, 14).rev().collect::<Vec<uint>>(), vec![13u, 12, 11]);
+        assert!(range(11u, 14).rev().collect::<Vec<uint>>() == vec![13u, 12, 11]);
         for _ in range(10u, 0).rev() {
             fail!("unreachable");
         }
@@ -2997,14 +3027,14 @@ fn one() -> Foo {
             }
         }
 
-        assert_eq!(range(0i, 5).collect::<Vec<int>>(), vec![0i, 1, 2, 3, 4]);
-        assert_eq!(range(-10i, -1).collect::<Vec<int>>(),
+        assert!(range(0i, 5).collect::<Vec<int>>() == vec![0i, 1, 2, 3, 4]);
+        assert!(range(-10i, -1).collect::<Vec<int>>() ==
                    vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
-        assert_eq!(range(0i, 5).rev().collect::<Vec<int>>(), vec![4, 3, 2, 1, 0]);
-        assert_eq!(range(200, -5).collect::<Vec<int>>(), vec![]);
-        assert_eq!(range(200, -5).rev().collect::<Vec<int>>(), vec![]);
-        assert_eq!(range(200, 200).collect::<Vec<int>>(), vec![]);
-        assert_eq!(range(200, 200).rev().collect::<Vec<int>>(), vec![]);
+        assert!(range(0i, 5).rev().collect::<Vec<int>>() == vec![4, 3, 2, 1, 0]);
+        assert_eq!(range(200, -5).len(), 0);
+        assert_eq!(range(200, -5).rev().len(), 0);
+        assert_eq!(range(200, 200).len(), 0);
+        assert_eq!(range(200, 200).rev().len(), 0);
 
         assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
         // this test is only meaningful when sizeof uint < sizeof u64
@@ -3015,32 +3045,44 @@ fn one() -> Foo {
 
     #[test]
     fn test_range_inclusive() {
-        assert_eq!(range_inclusive(0i, 5).collect::<Vec<int>>(), vec![0i, 1, 2, 3, 4, 5]);
-        assert_eq!(range_inclusive(0i, 5).rev().collect::<Vec<int>>(), vec![5i, 4, 3, 2, 1, 0]);
-        assert_eq!(range_inclusive(200, -5).collect::<Vec<int>>(), vec![]);
-        assert_eq!(range_inclusive(200, -5).rev().collect::<Vec<int>>(), vec![]);
-        assert_eq!(range_inclusive(200, 200).collect::<Vec<int>>(), vec![200]);
-        assert_eq!(range_inclusive(200, 200).rev().collect::<Vec<int>>(), vec![200]);
+        assert!(range_inclusive(0i, 5).collect::<Vec<int>>() ==
+                vec![0i, 1, 2, 3, 4, 5]);
+        assert!(range_inclusive(0i, 5).rev().collect::<Vec<int>>() ==
+                vec![5i, 4, 3, 2, 1, 0]);
+        assert_eq!(range_inclusive(200, -5).len(), 0);
+        assert_eq!(range_inclusive(200, -5).rev().len(), 0);
+        assert!(range_inclusive(200, 200).collect::<Vec<int>>() == vec![200]);
+        assert!(range_inclusive(200, 200).rev().collect::<Vec<int>>() == vec![200]);
     }
 
     #[test]
     fn test_range_step() {
-        assert_eq!(range_step(0i, 20, 5).collect::<Vec<int>>(), vec![0, 5, 10, 15]);
-        assert_eq!(range_step(20i, 0, -5).collect::<Vec<int>>(), vec![20, 15, 10, 5]);
-        assert_eq!(range_step(20i, 0, -6).collect::<Vec<int>>(), vec![20, 14, 8, 2]);
-        assert_eq!(range_step(200u8, 255, 50).collect::<Vec<u8>>(), vec![200u8, 250]);
-        assert_eq!(range_step(200, -5, 1).collect::<Vec<int>>(), vec![]);
-        assert_eq!(range_step(200, 200, 1).collect::<Vec<int>>(), vec![]);
+        assert!(range_step(0i, 20, 5).collect::<Vec<int>>() ==
+                vec![0, 5, 10, 15]);
+        assert!(range_step(20i, 0, -5).collect::<Vec<int>>() ==
+                vec![20, 15, 10, 5]);
+        assert!(range_step(20i, 0, -6).collect::<Vec<int>>() ==
+                vec![20, 14, 8, 2]);
+        assert!(range_step(200u8, 255, 50).collect::<Vec<u8>>() ==
+                vec![200u8, 250]);
+        assert!(range_step(200, -5, 1).collect::<Vec<int>>() == vec![]);
+        assert!(range_step(200, 200, 1).collect::<Vec<int>>() == vec![]);
     }
 
     #[test]
     fn test_range_step_inclusive() {
-        assert_eq!(range_step_inclusive(0i, 20, 5).collect::<Vec<int>>(), vec![0, 5, 10, 15, 20]);
-        assert_eq!(range_step_inclusive(20i, 0, -5).collect::<Vec<int>>(), vec![20, 15, 10, 5, 0]);
-        assert_eq!(range_step_inclusive(20i, 0, -6).collect::<Vec<int>>(), vec![20, 14, 8, 2]);
-        assert_eq!(range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>(), vec![200u8, 250]);
-        assert_eq!(range_step_inclusive(200, -5, 1).collect::<Vec<int>>(), vec![]);
-        assert_eq!(range_step_inclusive(200, 200, 1).collect::<Vec<int>>(), vec![200]);
+        assert!(range_step_inclusive(0i, 20, 5).collect::<Vec<int>>() ==
+                vec![0, 5, 10, 15, 20]);
+        assert!(range_step_inclusive(20i, 0, -5).collect::<Vec<int>>() ==
+                vec![20, 15, 10, 5, 0]);
+        assert!(range_step_inclusive(20i, 0, -6).collect::<Vec<int>>() ==
+                vec![20, 14, 8, 2]);
+        assert!(range_step_inclusive(200u8, 255, 50).collect::<Vec<u8>>() ==
+                vec![200u8, 250]);
+        assert!(range_step_inclusive(200, -5, 1).collect::<Vec<int>>() ==
+                vec![]);
+        assert!(range_step_inclusive(200, 200, 1).collect::<Vec<int>>() ==
+                vec![200]);
     }
 
     #[test]
index 4eab7e9d45d351c2b83881ff6e8be7d95a546312..05b314b6998478a998fad6e2fc6b947cb5474ec0 100644 (file)
 //! The Rust core library
 //!
 //! This library is meant to represent the core functionality of rust that is
-//! maximally portable to other platforms. To that exent, this library has no
+//! maximally portable to other platforms. To that extent, this library has no
 //! knowledge of things like allocation, threads, I/O, etc. This library is
 //! built on the assumption of a few existing symbols:
 //!
 //! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are
 //!   often generated by LLVM. Additionally, this library can make explicit
 //!   calls to these funcitons. Their signatures are the same as found in C.
+//!   These functions are often provided by the system libc, but can also be
+//!   provided by `librlibc` which is distributed with the standard rust
+//!   distribution.
 //!
 //! * `rust_begin_unwind` - This function takes three arguments, a
 //!   `&fmt::Arguments`, a `&str`, and a `uint. These three arguments dictate
 #[cfg(test)] extern crate realcore = "core";
 #[cfg(test)] extern crate libc;
 #[cfg(test)] extern crate native;
-#[phase(syntax, link)] #[cfg(test)] extern crate realstd = "std";
-#[phase(syntax, link)] #[cfg(test)] extern crate log;
+#[cfg(test)] extern crate rand;
+#[cfg(test)] extern crate realstd = "std";
 
 #[cfg(test)] pub use cmp = realcore::cmp;
 #[cfg(test)] pub use kinds = realcore::kinds;
 #[cfg(test)] pub use ops = realcore::ops;
 #[cfg(test)] pub use ty = realcore::ty;
 
-#[cfg(not(test))]
 mod macros;
 
 #[path = "num/float_macros.rs"] mod float_macros;
 /* Core types and methods on primitives */
 
 mod unicode;
-mod unit;
 pub mod any;
 pub mod atomics;
 pub mod bool;
 pub mod slice;
 pub mod str;
 pub mod tuple;
-
-#[cfg(stage0, not(test))]
-pub mod owned;
+pub mod fmt;
 
 // FIXME: this module should not exist. Once owned allocations are no longer a
 //        language type, this module can move outside to the owned allocation
@@ -132,10 +131,12 @@ mod std {
     pub use clone;
     pub use cmp;
     pub use kinds;
+    pub use option;
+    pub use fmt;
 
-    #[cfg(test)] pub use realstd::fmt;    // needed for fail!()
     #[cfg(test)] pub use realstd::rt;     // needed for fail!()
-    #[cfg(test)] pub use realstd::option; // needed for assert!()
+    // #[cfg(test)] pub use realstd::option; // needed for fail!()
+    // #[cfg(test)] pub use realstd::fmt;    // needed for fail!()
     #[cfg(test)] pub use realstd::os;     // needed for tests
     #[cfg(test)] pub use realstd::slice;  // needed for tests
     #[cfg(test)] pub use realstd::vec;    // needed for vec![]
index 69be68a34a130eef16c8d8e5e41d80395cb6062e..6474c5e37a44b46cb6930a35fef275ee3f085526 100644 (file)
 #[macro_export]
 macro_rules! fail(
     () => (
-        fail!("explicit failure")
+        fail!("{}", "explicit failure")
     );
     ($msg:expr) => (
-        ::core::failure::begin_unwind($msg, file!(), line!())
+        fail!("{}", $msg)
     );
+    ($fmt:expr, $($arg:tt)*) => ({
+        // a closure can't have return type !, so we need a full
+        // function to pass to format_args!, *and* we need the
+        // file and line numbers right here; so an inner bare fn
+        // is our only choice.
+        //
+        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
+        // is #[cold] and #[inline(never)] and because this is flagged as cold
+        // as returning !. We really do want this to be inlined, however,
+        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
+        // were seen when forcing this to be inlined, and that number just goes
+        // up with the number of calls to fail!()
+        #[inline(always)]
+        fn run_fmt(fmt: &::std::fmt::Arguments) -> ! {
+            ::core::failure::begin_unwind(fmt, file!(), line!())
+        }
+        format_args!(run_fmt, $fmt, $($arg)*)
+    });
 )
 
 /// Runtime assertion, for details see std::macros
@@ -29,6 +47,22 @@ macro_rules! assert(
             fail!(concat!("assertion failed: ", stringify!($cond)))
         }
     );
+    ($cond:expr, $($arg:tt)*) => (
+        if !$cond {
+            fail!($($arg)*)
+        }
+    );
+)
+
+/// Runtime assertion for equality, for details see std::macros
+macro_rules! assert_eq(
+    ($cond1:expr, $cond2:expr) => ({
+        let c1 = $cond1;
+        let c2 = $cond2;
+        if c1 != c2 || c2 != c1 {
+            fail!("expressions not equal, left: {}, right: {}", c1, c2);
+        }
+    })
 )
 
 /// Runtime assertion, disableable at compile time
@@ -36,3 +70,19 @@ macro_rules! assert(
 macro_rules! debug_assert(
     ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
 )
+
+/// Short circuiting evaluation on Err
+#[macro_export]
+macro_rules! try(
+    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
+)
+
+#[cfg(test)]
+macro_rules! vec( ($($e:expr),*) => ({
+    let mut _v = ::std::vec::Vec::new();
+    $(_v.push($e);)*
+    _v
+}) )
+
+#[cfg(test)]
+macro_rules! format( ($($arg:tt)*) => (format_args!(::fmt::format, $($arg)*)) )
index c4cdc5a0a4017e90d3ce7af9d2c18b99b11cdbbe..694f3e9fbd1f90ee2292975927d140421c4009a3 100644 (file)
 
 use default::Default;
 use intrinsics;
-use num::{Zero, One, Bounded, Signed, Num, Primitive};
+use mem;
+use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
+use num::{Zero, One, Bounded, Signed, Num, Primitive, Float};
+use option::Option;
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
 #[cfg(not(test))] use ops::{Add, Sub, Mul, Div, Rem, Neg};
@@ -225,3 +228,270 @@ fn min_value() -> f32 { -MAX_VALUE }
     #[inline]
     fn max_value() -> f32 { MAX_VALUE }
 }
+
+impl Float for f32 {
+    #[inline]
+    fn nan() -> f32 { NAN }
+
+    #[inline]
+    fn infinity() -> f32 { INFINITY }
+
+    #[inline]
+    fn neg_infinity() -> f32 { NEG_INFINITY }
+
+    #[inline]
+    fn neg_zero() -> f32 { -0.0 }
+
+    /// Returns `true` if the number is NaN
+    #[inline]
+    fn is_nan(self) -> bool { self != self }
+
+    /// Returns `true` if the number is infinite
+    #[inline]
+    fn is_infinite(self) -> bool {
+        self == Float::infinity() || self == Float::neg_infinity()
+    }
+
+    /// Returns `true` if the number is neither infinite or NaN
+    #[inline]
+    fn is_finite(self) -> bool {
+        !(self.is_nan() || self.is_infinite())
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+    #[inline]
+    fn is_normal(self) -> bool {
+        self.classify() == FPNormal
+    }
+
+    /// Returns the floating point category of the number. If only one property
+    /// is going to be tested, it is generally faster to use the specific
+    /// predicate instead.
+    fn classify(self) -> FPCategory {
+        static EXP_MASK: u32 = 0x7f800000;
+        static MAN_MASK: u32 = 0x007fffff;
+
+        let bits: u32 = unsafe { mem::transmute(self) };
+        match (bits & MAN_MASK, bits & EXP_MASK) {
+            (0, 0)        => FPZero,
+            (_, 0)        => FPSubnormal,
+            (0, EXP_MASK) => FPInfinite,
+            (_, EXP_MASK) => FPNaN,
+            _             => FPNormal,
+        }
+    }
+
+    #[inline]
+    fn mantissa_digits(_: Option<f32>) -> uint { MANTISSA_DIGITS }
+
+    #[inline]
+    fn digits(_: Option<f32>) -> uint { DIGITS }
+
+    #[inline]
+    fn epsilon() -> f32 { EPSILON }
+
+    #[inline]
+    fn min_exp(_: Option<f32>) -> int { MIN_EXP }
+
+    #[inline]
+    fn max_exp(_: Option<f32>) -> int { MAX_EXP }
+
+    #[inline]
+    fn min_10_exp(_: Option<f32>) -> int { MIN_10_EXP }
+
+    #[inline]
+    fn max_10_exp(_: Option<f32>) -> int { MAX_10_EXP }
+
+    #[inline]
+    fn min_pos_value(_: Option<f32>) -> f32 { MIN_POS_VALUE }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u32 = unsafe { mem::transmute(self) };
+        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0x7fffff) << 1
+        } else {
+            (bits & 0x7fffff) | 0x800000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 127 + 23;
+        (mantissa as u64, exponent, sign)
+    }
+
+    /// Round half-way cases toward `NEG_INFINITY`
+    #[inline]
+    fn floor(self) -> f32 {
+        unsafe { intrinsics::floorf32(self) }
+    }
+
+    /// Round half-way cases toward `INFINITY`
+    #[inline]
+    fn ceil(self) -> f32 {
+        unsafe { intrinsics::ceilf32(self) }
+    }
+
+    /// Round half-way cases away from `0.0`
+    #[inline]
+    fn round(self) -> f32 {
+        unsafe { intrinsics::roundf32(self) }
+    }
+
+    /// The integer part of the number (rounds towards `0.0`)
+    #[inline]
+    fn trunc(self) -> f32 {
+        unsafe { intrinsics::truncf32(self) }
+    }
+
+    /// The fractional part of the number, satisfying:
+    ///
+    /// ```rust
+    /// let x = 1.65f32;
+    /// assert!(x == x.trunc() + x.fract())
+    /// ```
+    #[inline]
+    fn fract(self) -> f32 { self - self.trunc() }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error. This produces a more accurate result with better performance than
+    /// a separate multiplication operation followed by an add.
+    #[inline]
+    fn mul_add(self, a: f32, b: f32) -> f32 {
+        unsafe { intrinsics::fmaf32(self, a, b) }
+    }
+
+    /// The reciprocal (multiplicative inverse) of the number
+    #[inline]
+    fn recip(self) -> f32 { 1.0 / self }
+
+    fn powi(self, n: i32) -> f32 {
+        unsafe { intrinsics::powif32(self, n) }
+    }
+
+    #[inline]
+    fn powf(self, n: f32) -> f32 {
+        unsafe { intrinsics::powf32(self, n) }
+    }
+
+    /// sqrt(2.0)
+    #[inline]
+    fn sqrt2() -> f32 { consts::SQRT2 }
+
+    /// 1.0 / sqrt(2.0)
+    #[inline]
+    fn frac_1_sqrt2() -> f32 { consts::FRAC_1_SQRT2 }
+
+    #[inline]
+    fn sqrt(self) -> f32 {
+        unsafe { intrinsics::sqrtf32(self) }
+    }
+
+    #[inline]
+    fn rsqrt(self) -> f32 { self.sqrt().recip() }
+
+    /// Archimedes' constant
+    #[inline]
+    fn pi() -> f32 { consts::PI }
+
+    /// 2.0 * pi
+    #[inline]
+    fn two_pi() -> f32 { consts::PI_2 }
+
+    /// pi / 2.0
+    #[inline]
+    fn frac_pi_2() -> f32 { consts::FRAC_PI_2 }
+
+    /// pi / 3.0
+    #[inline]
+    fn frac_pi_3() -> f32 { consts::FRAC_PI_3 }
+
+    /// pi / 4.0
+    #[inline]
+    fn frac_pi_4() -> f32 { consts::FRAC_PI_4 }
+
+    /// pi / 6.0
+    #[inline]
+    fn frac_pi_6() -> f32 { consts::FRAC_PI_6 }
+
+    /// pi / 8.0
+    #[inline]
+    fn frac_pi_8() -> f32 { consts::FRAC_PI_8 }
+
+    /// 1 .0/ pi
+    #[inline]
+    fn frac_1_pi() -> f32 { consts::FRAC_1_PI }
+
+    /// 2.0 / pi
+    #[inline]
+    fn frac_2_pi() -> f32 { consts::FRAC_2_PI }
+
+    /// 2.0 / sqrt(pi)
+    #[inline]
+    fn frac_2_sqrtpi() -> f32 { consts::FRAC_2_SQRTPI }
+
+    /// Euler's number
+    #[inline]
+    fn e() -> f32 { consts::E }
+
+    /// log2(e)
+    #[inline]
+    fn log2_e() -> f32 { consts::LOG2_E }
+
+    /// log10(e)
+    #[inline]
+    fn log10_e() -> f32 { consts::LOG10_E }
+
+    /// ln(2.0)
+    #[inline]
+    fn ln_2() -> f32 { consts::LN_2 }
+
+    /// ln(10.0)
+    #[inline]
+    fn ln_10() -> f32 { consts::LN_10 }
+
+    /// Returns the exponential of the number
+    #[inline]
+    fn exp(self) -> f32 {
+        unsafe { intrinsics::expf32(self) }
+    }
+
+    /// Returns 2 raised to the power of the number
+    #[inline]
+    fn exp2(self) -> f32 {
+        unsafe { intrinsics::exp2f32(self) }
+    }
+
+    /// Returns the natural logarithm of the number
+    #[inline]
+    fn ln(self) -> f32 {
+        unsafe { intrinsics::logf32(self) }
+    }
+
+    /// Returns the logarithm of the number with respect to an arbitrary base
+    #[inline]
+    fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
+
+    /// Returns the base 2 logarithm of the number
+    #[inline]
+    fn log2(self) -> f32 {
+        unsafe { intrinsics::log2f32(self) }
+    }
+
+    /// Returns the base 10 logarithm of the number
+    #[inline]
+    fn log10(self) -> f32 {
+        unsafe { intrinsics::log10f32(self) }
+    }
+
+    /// Converts to degrees, assuming the number is in radians
+    #[inline]
+    fn to_degrees(self) -> f32 { self * (180.0f32 / Float::pi()) }
+
+    /// Converts to radians, assuming the number is in degrees
+    #[inline]
+    fn to_radians(self) -> f32 {
+        let value: f32 = Float::pi();
+        self * (value / 180.0f32)
+    }
+}
index b15b4566cdd689e9f1648fa0d96d7550d22d0137..2c802f5d059f1f3dcb7226321f0142a887b16396 100644 (file)
 
 use default::Default;
 use intrinsics;
-use num::{Zero, One, Bounded, Signed, Num, Primitive};
+use mem;
+use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};
+use num::{Zero, One, Bounded, Signed, Num, Primitive, Float};
+use option::Option;
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
 #[cfg(not(test))] use ops::{Add, Sub, Mul, Div, Rem, Neg};
@@ -225,3 +228,273 @@ fn min_value() -> f64 { -MAX_VALUE }
     #[inline]
     fn max_value() -> f64 { MAX_VALUE }
 }
+
+impl Float for f64 {
+    #[inline]
+    fn nan() -> f64 { NAN }
+
+    #[inline]
+    fn infinity() -> f64 { INFINITY }
+
+    #[inline]
+    fn neg_infinity() -> f64 { NEG_INFINITY }
+
+    #[inline]
+    fn neg_zero() -> f64 { -0.0 }
+
+    /// Returns `true` if the number is NaN
+    #[inline]
+    fn is_nan(self) -> bool { self != self }
+
+    /// Returns `true` if the number is infinite
+    #[inline]
+    fn is_infinite(self) -> bool {
+        self == Float::infinity() || self == Float::neg_infinity()
+    }
+
+    /// Returns `true` if the number is neither infinite or NaN
+    #[inline]
+    fn is_finite(self) -> bool {
+        !(self.is_nan() || self.is_infinite())
+    }
+
+    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
+    #[inline]
+    fn is_normal(self) -> bool {
+        self.classify() == FPNormal
+    }
+
+    /// Returns the floating point category of the number. If only one property
+    /// is going to be tested, it is generally faster to use the specific
+    /// predicate instead.
+    fn classify(self) -> FPCategory {
+        static EXP_MASK: u64 = 0x7ff0000000000000;
+        static MAN_MASK: u64 = 0x000fffffffffffff;
+
+        let bits: u64 = unsafe { mem::transmute(self) };
+        match (bits & MAN_MASK, bits & EXP_MASK) {
+            (0, 0)        => FPZero,
+            (_, 0)        => FPSubnormal,
+            (0, EXP_MASK) => FPInfinite,
+            (_, EXP_MASK) => FPNaN,
+            _             => FPNormal,
+        }
+    }
+
+    #[inline]
+    fn mantissa_digits(_: Option<f64>) -> uint { MANTISSA_DIGITS }
+
+    #[inline]
+    fn digits(_: Option<f64>) -> uint { DIGITS }
+
+    #[inline]
+    fn epsilon() -> f64 { EPSILON }
+
+    #[inline]
+    fn min_exp(_: Option<f64>) -> int { MIN_EXP }
+
+    #[inline]
+    fn max_exp(_: Option<f64>) -> int { MAX_EXP }
+
+    #[inline]
+    fn min_10_exp(_: Option<f64>) -> int { MIN_10_EXP }
+
+    #[inline]
+    fn max_10_exp(_: Option<f64>) -> int { MAX_10_EXP }
+
+    #[inline]
+    fn min_pos_value(_: Option<f64>) -> f64 { MIN_POS_VALUE }
+
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u64 = unsafe { mem::transmute(self) };
+        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0xfffffffffffff) << 1
+        } else {
+            (bits & 0xfffffffffffff) | 0x10000000000000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 1023 + 52;
+        (mantissa, exponent, sign)
+    }
+
+    /// Round half-way cases toward `NEG_INFINITY`
+    #[inline]
+    fn floor(self) -> f64 {
+        unsafe { intrinsics::floorf64(self) }
+    }
+
+    /// Round half-way cases toward `INFINITY`
+    #[inline]
+    fn ceil(self) -> f64 {
+        unsafe { intrinsics::ceilf64(self) }
+    }
+
+    /// Round half-way cases away from `0.0`
+    #[inline]
+    fn round(self) -> f64 {
+        unsafe { intrinsics::roundf64(self) }
+    }
+
+    /// The integer part of the number (rounds towards `0.0`)
+    #[inline]
+    fn trunc(self) -> f64 {
+        unsafe { intrinsics::truncf64(self) }
+    }
+
+    /// The fractional part of the number, satisfying:
+    ///
+    /// ```rust
+    /// let x = 1.65f64;
+    /// assert!(x == x.trunc() + x.fract())
+    /// ```
+    #[inline]
+    fn fract(self) -> f64 { self - self.trunc() }
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error. This produces a more accurate result with better performance than
+    /// a separate multiplication operation followed by an add.
+    #[inline]
+    fn mul_add(self, a: f64, b: f64) -> f64 {
+        unsafe { intrinsics::fmaf64(self, a, b) }
+    }
+
+    /// The reciprocal (multiplicative inverse) of the number
+    #[inline]
+    fn recip(self) -> f64 { 1.0 / self }
+
+    #[inline]
+    fn powf(self, n: f64) -> f64 {
+        unsafe { intrinsics::powf64(self, n) }
+    }
+
+    #[inline]
+    fn powi(self, n: i32) -> f64 {
+        unsafe { intrinsics::powif64(self, n) }
+    }
+
+    /// sqrt(2.0)
+    #[inline]
+    fn sqrt2() -> f64 { consts::SQRT2 }
+
+    /// 1.0 / sqrt(2.0)
+    #[inline]
+    fn frac_1_sqrt2() -> f64 { consts::FRAC_1_SQRT2 }
+
+    #[inline]
+    fn sqrt(self) -> f64 {
+        unsafe { intrinsics::sqrtf64(self) }
+    }
+
+    #[inline]
+    fn rsqrt(self) -> f64 { self.sqrt().recip() }
+
+    /// Archimedes' constant
+    #[inline]
+    fn pi() -> f64 { consts::PI }
+
+    /// 2.0 * pi
+    #[inline]
+    fn two_pi() -> f64 { consts::PI_2 }
+
+    /// pi / 2.0
+    #[inline]
+    fn frac_pi_2() -> f64 { consts::FRAC_PI_2 }
+
+    /// pi / 3.0
+    #[inline]
+    fn frac_pi_3() -> f64 { consts::FRAC_PI_3 }
+
+    /// pi / 4.0
+    #[inline]
+    fn frac_pi_4() -> f64 { consts::FRAC_PI_4 }
+
+    /// pi / 6.0
+    #[inline]
+    fn frac_pi_6() -> f64 { consts::FRAC_PI_6 }
+
+    /// pi / 8.0
+    #[inline]
+    fn frac_pi_8() -> f64 { consts::FRAC_PI_8 }
+
+    /// 1.0 / pi
+    #[inline]
+    fn frac_1_pi() -> f64 { consts::FRAC_1_PI }
+
+    /// 2.0 / pi
+    #[inline]
+    fn frac_2_pi() -> f64 { consts::FRAC_2_PI }
+
+    /// 2.0 / sqrt(pi)
+    #[inline]
+    fn frac_2_sqrtpi() -> f64 { consts::FRAC_2_SQRTPI }
+
+    /// Euler's number
+    #[inline]
+    fn e() -> f64 { consts::E }
+
+    /// log2(e)
+    #[inline]
+    fn log2_e() -> f64 { consts::LOG2_E }
+
+    /// log10(e)
+    #[inline]
+    fn log10_e() -> f64 { consts::LOG10_E }
+
+    /// ln(2.0)
+    #[inline]
+    fn ln_2() -> f64 { consts::LN_2 }
+
+    /// ln(10.0)
+    #[inline]
+    fn ln_10() -> f64 { consts::LN_10 }
+
+    /// Returns the exponential of the number
+    #[inline]
+    fn exp(self) -> f64 {
+        unsafe { intrinsics::expf64(self) }
+    }
+
+    /// Returns 2 raised to the power of the number
+    #[inline]
+    fn exp2(self) -> f64 {
+        unsafe { intrinsics::exp2f64(self) }
+    }
+
+    /// Returns the natural logarithm of the number
+    #[inline]
+    fn ln(self) -> f64 {
+        unsafe { intrinsics::logf64(self) }
+    }
+
+    /// Returns the logarithm of the number with respect to an arbitrary base
+    #[inline]
+    fn log(self, base: f64) -> f64 { self.ln() / base.ln() }
+
+    /// Returns the base 2 logarithm of the number
+    #[inline]
+    fn log2(self) -> f64 {
+        unsafe { intrinsics::log2f64(self) }
+    }
+
+    /// Returns the base 10 logarithm of the number
+    #[inline]
+    fn log10(self) -> f64 {
+        unsafe { intrinsics::log10f64(self) }
+    }
+
+
+    /// Converts to degrees, assuming the number is in radians
+    #[inline]
+    fn to_degrees(self) -> f64 { self * (180.0f64 / Float::pi()) }
+
+    /// Converts to radians, assuming the number is in degrees
+    #[inline]
+    fn to_radians(self) -> f64 {
+        let value: f64 = Float::pi();
+        self * (value / 180.0)
+    }
+}
+
index 22411fef3b26801884c5a5d94ae81274c08c9dac..47be5df67eabdb345c963e9cc58ccd9dfcaf8c39 100644 (file)
@@ -874,3 +874,157 @@ pub fn test_num<T:Num + NumCast + ::std::fmt::Show>(ten: T, two: T) {
     assert_eq!(ten.div(&two),  ten / two);
     assert_eq!(ten.rem(&two),  ten % two);
 }
+
+/// Used for representing the classification of floating point numbers
+#[deriving(Eq, Show)]
+pub enum FPCategory {
+    /// "Not a Number", often obtained by dividing by zero
+    FPNaN,
+    /// Positive or negative infinity
+    FPInfinite ,
+    /// Positive or negative zero
+    FPZero,
+    /// De-normalized floating point representation (less precise than `FPNormal`)
+    FPSubnormal,
+    /// A regular floating point number
+    FPNormal,
+}
+
+/// Operations on primitive floating point numbers.
+// FIXME(#5527): In a future version of Rust, many of these functions will
+//               become constants.
+//
+// FIXME(#8888): Several of these functions have a parameter named
+//               `unused_self`. Removing it requires #8888 to be fixed.
+pub trait Float: Signed + Primitive {
+    /// Returns the NaN value.
+    fn nan() -> Self;
+    /// Returns the infinite value.
+    fn infinity() -> Self;
+    /// Returns the negative infinite value.
+    fn neg_infinity() -> Self;
+    /// Returns -0.0.
+    fn neg_zero() -> Self;
+
+    /// Returns true if this value is NaN and false otherwise.
+    fn is_nan(self) -> bool;
+    /// Returns true if this value is positive infinity or negative infinity and
+    /// false otherwise.
+    fn is_infinite(self) -> bool;
+    /// Returns true if this number is neither infinite nor NaN.
+    fn is_finite(self) -> bool;
+    /// Returns true if this number is neither zero, infinite, denormal, or NaN.
+    fn is_normal(self) -> bool;
+    /// Returns the category that this number falls into.
+    fn classify(self) -> FPCategory;
+
+    // FIXME (#5527): These should be associated constants
+
+    /// Returns the number of binary digits of mantissa that this type supports.
+    fn mantissa_digits(unused_self: Option<Self>) -> uint;
+    /// Returns the number of base-10 digits of precision that this type supports.
+    fn digits(unused_self: Option<Self>) -> uint;
+    /// Returns the difference between 1.0 and the smallest representable number larger than 1.0.
+    fn epsilon() -> Self;
+    /// Returns the minimum binary exponent that this type can represent.
+    fn min_exp(unused_self: Option<Self>) -> int;
+    /// Returns the maximum binary exponent that this type can represent.
+    fn max_exp(unused_self: Option<Self>) -> int;
+    /// Returns the minimum base-10 exponent that this type can represent.
+    fn min_10_exp(unused_self: Option<Self>) -> int;
+    /// Returns the maximum base-10 exponent that this type can represent.
+    fn max_10_exp(unused_self: Option<Self>) -> int;
+    /// Returns the smallest normalized positive number that this type can represent.
+    fn min_pos_value(unused_self: Option<Self>) -> Self;
+
+    /// Returns the mantissa, exponent and sign as integers, respectively.
+    fn integer_decode(self) -> (u64, i16, i8);
+
+    /// Return the largest integer less than or equal to a number.
+    fn floor(self) -> Self;
+    /// Return the smallest integer greater than or equal to a number.
+    fn ceil(self) -> Self;
+    /// Return the nearest integer to a number. Round half-way cases away from
+    /// `0.0`.
+    fn round(self) -> Self;
+    /// Return the integer part of a number.
+    fn trunc(self) -> Self;
+    /// Return the fractional part of a number.
+    fn fract(self) -> Self;
+
+    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
+    /// error. This produces a more accurate result with better performance than
+    /// a separate multiplication operation followed by an add.
+    fn mul_add(self, a: Self, b: Self) -> Self;
+    /// Take the reciprocal (inverse) of a number, `1/x`.
+    fn recip(self) -> Self;
+
+    /// Raise a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`
+    fn powi(self, n: i32) -> Self;
+    /// Raise a number to a floating point power.
+    fn powf(self, n: Self) -> Self;
+
+    /// sqrt(2.0).
+    fn sqrt2() -> Self;
+    /// 1.0 / sqrt(2.0).
+    fn frac_1_sqrt2() -> Self;
+
+    /// Take the square root of a number.
+    fn sqrt(self) -> Self;
+    /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
+    fn rsqrt(self) -> Self;
+
+    // FIXME (#5527): These should be associated constants
+
+    /// Archimedes' constant.
+    fn pi() -> Self;
+    /// 2.0 * pi.
+    fn two_pi() -> Self;
+    /// pi / 2.0.
+    fn frac_pi_2() -> Self;
+    /// pi / 3.0.
+    fn frac_pi_3() -> Self;
+    /// pi / 4.0.
+    fn frac_pi_4() -> Self;
+    /// pi / 6.0.
+    fn frac_pi_6() -> Self;
+    /// pi / 8.0.
+    fn frac_pi_8() -> Self;
+    /// 1.0 / pi.
+    fn frac_1_pi() -> Self;
+    /// 2.0 / pi.
+    fn frac_2_pi() -> Self;
+    /// 2.0 / sqrt(pi).
+    fn frac_2_sqrtpi() -> Self;
+
+    /// Euler's number.
+    fn e() -> Self;
+    /// log2(e).
+    fn log2_e() -> Self;
+    /// log10(e).
+    fn log10_e() -> Self;
+    /// ln(2.0).
+    fn ln_2() -> Self;
+    /// ln(10.0).
+    fn ln_10() -> Self;
+
+    /// Returns `e^(self)`, (the exponential function).
+    fn exp(self) -> Self;
+    /// Returns 2 raised to the power of the number, `2^(self)`.
+    fn exp2(self) -> Self;
+    /// Returns the natural logarithm of the number.
+    fn ln(self) -> Self;
+    /// Returns the logarithm of the number with respect to an arbitrary base.
+    fn log(self, base: Self) -> Self;
+    /// Returns the base 2 logarithm of the number.
+    fn log2(self) -> Self;
+    /// Returns the base 10 logarithm of the number.
+    fn log10(self) -> Self;
+
+    /// Convert radians to degrees.
+    fn to_degrees(self) -> Self;
+    /// Convert degrees to radians.
+    fn to_radians(self) -> Self;
+}
index 886b7315152b8e1eb54bbe94f32051ebf9adbf80..00f21ee4c9cedee495cd2d9dfd8e400cdc95d223 100644 (file)
 use slice;
 
 /// The `Option`
-#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
+#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show)]
 pub enum Option<T> {
     /// No value
     None,
@@ -595,9 +595,11 @@ pub fn collect<T, Iter: Iterator<Option<T>>, V: FromIterator<T>>(iter: Iter) ->
 
 #[cfg(test)]
 mod tests {
-    use realstd::option::collect;
-    use realstd::prelude::*;
-    use realstd::iter::range;
+    use realstd::vec::Vec;
+    use realstd::str::StrAllocating;
+    use option::collect;
+    use prelude::*;
+    use iter::range;
 
     use str::StrSlice;
     use kinds::marker;
@@ -638,7 +640,7 @@ struct R {
         impl ::ops::Drop for R {
            fn drop(&mut self) {
                 let ii = &*self.i;
-                let i = ii.borrow().clone();
+                let i = *ii.borrow();
                 *ii.borrow_mut() = i + 1;
             }
         }
@@ -649,9 +651,14 @@ fn R(i: Rc<RefCell<int>>) -> R {
             }
         }
 
+        fn realclone<T: ::realstd::clone::Clone>(t: &T) -> T {
+            use realstd::clone::Clone;
+            t.clone()
+        }
+
         let i = Rc::new(RefCell::new(0));
         {
-            let x = R(i.clone());
+            let x = R(realclone(&i));
             let opt = Some(x);
             let _y = opt.unwrap();
         }
@@ -849,21 +856,21 @@ fn test_mutate() {
     fn test_collect() {
         let v: Option<Vec<int>> = collect(range(0, 0)
                                           .map(|_| Some(0)));
-        assert_eq!(v, Some(vec![]));
+        assert!(v == Some(vec![]));
 
         let v: Option<Vec<int>> = collect(range(0, 3)
                                           .map(|x| Some(x)));
-        assert_eq!(v, Some(vec![0, 1, 2]));
+        assert!(v == Some(vec![0, 1, 2]));
 
         let v: Option<Vec<int>> = collect(range(0, 3)
                                           .map(|x| if x > 1 { None } else { Some(x) }));
-        assert_eq!(v, None);
+        assert!(v == None);
 
         // test that it does not take more elements than it needs
         let mut functions = [|| Some(()), || None, || fail!()];
 
         let v: Option<Vec<()>> = collect(functions.mut_iter().map(|f| (*f)()));
 
-        assert_eq!(v, None);
+        assert!(v == None);
     }
 }
diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs
deleted file mode 100644 (file)
index 3af12c5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// 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.
-
-//! Operations on unique pointer types
-
-use any::{Any, AnyRefExt};
-use clone::Clone;
-use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
-use default::Default;
-use intrinsics;
-use mem;
-use raw::TraitObject;
-use result::{Ok, Err, Result};
-
-/// A value that represents the global exchange heap. This is the default
-/// place that the `box` keyword allocates into when no place is supplied.
-///
-/// The following two examples are equivalent:
-///
-///     let foo = box(HEAP) Bar::new(...);
-///     let foo = box Bar::new(...);
-#[lang="exchange_heap"]
-pub static HEAP: () = ();
-
-/// A type that represents a uniquely-owned value.
-#[lang="owned_box"]
-pub struct Box<T>(*T);
-
-impl<T: Default> Default for Box<T> {
-    fn default() -> Box<T> { box Default::default() }
-}
-
-impl<T: Clone> Clone for Box<T> {
-    /// Return a copy of the owned box.
-    #[inline]
-    fn clone(&self) -> Box<T> { box {(**self).clone()} }
-
-    /// Perform copy-assignment from `source` by reusing the existing allocation.
-    #[inline]
-    fn clone_from(&mut self, source: &Box<T>) {
-        (**self).clone_from(&(**source));
-    }
-}
-
-// box pointers
-impl<T:Eq> Eq for Box<T> {
-    #[inline]
-    fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) }
-    #[inline]
-    fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) }
-}
-impl<T:Ord> Ord for Box<T> {
-    #[inline]
-    fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) }
-    #[inline]
-    fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) }
-    #[inline]
-    fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) }
-    #[inline]
-    fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) }
-}
-impl<T: TotalOrd> TotalOrd for Box<T> {
-    #[inline]
-    fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) }
-}
-impl<T: TotalEq> TotalEq for Box<T> {}
-
-/// Extension methods for an owning `Any` trait object
-pub trait AnyOwnExt {
-    /// Returns the boxed value if it is of type `T`, or
-    /// `Err(Self)` if it isn't.
-    fn move<T: 'static>(self) -> Result<Box<T>, Self>;
-}
-
-impl AnyOwnExt for Box<Any> {
-    #[inline]
-    fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
-        if self.is::<T>() {
-            unsafe {
-                // Get the raw representation of the trait object
-                let to: TraitObject =
-                    *mem::transmute::<&Box<Any>, &TraitObject>(&self);
-
-                // Prevent destructor on self being run
-                intrinsics::forget(self);
-
-                // Extract the data pointer
-                Ok(mem::transmute(to.data))
-            }
-        } else {
-            Err(self)
-        }
-    }
-}
index efd6732f6530a80360419c2a434bad6aa0eb29e4..2c6b0af8d94e6b34d2bc62d809c519c4ae90b11d 100644 (file)
@@ -35,7 +35,7 @@
 pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
 pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
 pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
-pub use num::{Signed, Unsigned};
+pub use num::{Signed, Unsigned, Float};
 pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
 pub use ptr::RawPtr;
 pub use str::{Str, StrSlice};
index 438e18d999b6c77b5369b8b01aafa02b16e07688..acdf0bf06589f6a7dcaa1874f1ad9b0316b1650b 100644 (file)
@@ -480,7 +480,7 @@ fn lt(&self, other: &*mut T) -> bool { *self < *other }
 #[cfg(test)]
 pub mod ptr_tests {
     use super::*;
-    use realstd::prelude::*;
+    use prelude::*;
 
     use realstd::c_str::ToCStr;
     use mem;
@@ -660,9 +660,6 @@ fn test_ptr_array_each_with_len() {
                     let expected = expected_arr[ctr].with_ref(|buf| {
                             str::raw::from_c_str(buf)
                         });
-                    debug!(
-                        "test_ptr_array_each_with_len e: {}, a: {}",
-                        expected, actual);
                     assert_eq!(actual, expected);
                     ctr += 1;
                     iteration_count += 1;
@@ -696,9 +693,6 @@ fn test_ptr_array_each() {
                     let expected = expected_arr[ctr].with_ref(|buf| {
                         str::raw::from_c_str(buf)
                     });
-                    debug!(
-                        "test_ptr_array_each e: {}, a: {}",
-                        expected, actual);
                     assert_eq!(actual, expected);
                     ctr += 1;
                     iteration_count += 1;
index cced502846032f0ac3713079898fd9a7762e55a3..3237269e4a64fb0dbe8a22e9822055c327e4ae29 100644 (file)
 
 use clone::Clone;
 use cmp::Eq;
+use std::fmt::Show;
 use iter::{Iterator, FromIterator};
 use option::{None, Option, Some};
 
 /// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
 ///
 /// See the [`std::result`](index.html) module documentation for details.
-#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
+#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show)]
 #[must_use]
 pub enum Result<T, E> {
     /// Contains the success value
@@ -515,6 +516,34 @@ pub fn unwrap_or_handle(self, op: |E| -> T) -> T {
     }
 }
 
+impl<T, E: Show> Result<T, E> {
+    /// Unwraps a result, yielding the content of an `Ok`.
+    ///
+    /// Fails if the value is an `Err`.
+    #[inline]
+    pub fn unwrap(self) -> T {
+        match self {
+            Ok(t) => t,
+            Err(e) =>
+                fail!("called `Result::unwrap()` on an `Err` value: {}", e)
+        }
+    }
+}
+
+impl<T: Show, E> Result<T, E> {
+    /// Unwraps a result, yielding the content of an `Err`.
+    ///
+    /// Fails if the value is an `Ok`.
+    #[inline]
+    pub fn unwrap_err(self) -> E {
+        match self {
+            Ok(t) =>
+                fail!("called `Result::unwrap_err()` on an `Ok` value: {}", t),
+            Err(e) => e
+        }
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // Free functions
 /////////////////////////////////////////////////////////////////////////////
@@ -592,9 +621,12 @@ pub fn fold_<T,E,Iter:Iterator<Result<T,E>>>(iterator: Iter) -> Result<(),E> {
 
 #[cfg(test)]
 mod tests {
-    use realstd::result::{collect, fold, fold_};
-    use realstd::prelude::*;
-    use realstd::iter::range;
+    use realstd::vec::Vec;
+    use realstd::str::StrAllocating;
+
+    use result::{collect, fold, fold_};
+    use prelude::*;
+    use iter::range;
 
     pub fn op1() -> Result<int, ~str> { Ok(666) }
     pub fn op2() -> Result<int, ~str> { Err("sadface".to_owned()) }
@@ -641,33 +673,37 @@ pub fn test_or_else() {
 
     #[test]
     pub fn test_impl_map() {
-        assert_eq!(Ok::<~str, ~str>("a".to_owned()).map(|x| x + "b"), Ok("ab".to_owned()));
-        assert_eq!(Err::<~str, ~str>("a".to_owned()).map(|x| x + "b"), Err("a".to_owned()));
+        assert_eq!(Ok::<~str, ~str>("a".to_owned()).map(|x| x + "b"),
+                   Ok("ab".to_owned()));
+        assert_eq!(Err::<~str, ~str>("a".to_owned()).map(|x| x + "b"),
+                   Err("a".to_owned()));
     }
 
     #[test]
     pub fn test_impl_map_err() {
-        assert_eq!(Ok::<~str, ~str>("a".to_owned()).map_err(|x| x + "b"), Ok("a".to_owned()));
-        assert_eq!(Err::<~str, ~str>("a".to_owned()).map_err(|x| x + "b"), Err("ab".to_owned()));
+        assert_eq!(Ok::<~str, ~str>("a".to_owned()).map_err(|x| x + "b"),
+                   Ok("a".to_owned()));
+        assert_eq!(Err::<~str, ~str>("a".to_owned()).map_err(|x| x + "b"),
+                   Err("ab".to_owned()));
     }
 
     #[test]
     fn test_collect() {
         let v: Result<Vec<int>, ()> = collect(range(0, 0).map(|_| Ok::<int, ()>(0)));
-        assert_eq!(v, Ok(vec![]));
+        assert!(v == Ok(vec![]));
 
         let v: Result<Vec<int>, ()> = collect(range(0, 3).map(|x| Ok::<int, ()>(x)));
-        assert_eq!(v, Ok(vec![0, 1, 2]));
+        assert!(v == Ok(vec![0, 1, 2]));
 
         let v: Result<Vec<int>, int> = collect(range(0, 3)
                                                .map(|x| if x > 1 { Err(x) } else { Ok(x) }));
-        assert_eq!(v, Err(2));
+        assert!(v == Err(2));
 
         // test that it does not take more elements than it needs
         let mut functions = [|| Ok(()), || Err(1), || fail!()];
 
         let v: Result<Vec<()>, int> = collect(functions.mut_iter().map(|f| (*f)()));
-        assert_eq!(v, Err(1));
+        assert!(v == Err(1));
     }
 
     #[test]
@@ -691,15 +727,6 @@ fn test_fold() {
                    Err(1));
     }
 
-    #[test]
-    pub fn test_to_str() {
-        let ok: Result<int, ~str> = Ok(100);
-        let err: Result<int, ~str> = Err("Err".to_owned());
-
-        assert_eq!(ok.to_str(), "Ok(100)".to_owned());
-        assert_eq!(err.to_str(), "Err(Err)".to_owned());
-    }
-
     #[test]
     pub fn test_fmt_default() {
         let ok: Result<int, ~str> = Ok(100);
index 9272f24da9d40f83b179efa70d72adc3304f9313..b55952e70598a85a069f8ab6c7015802bb4630a7 100644 (file)
@@ -20,7 +20,7 @@
 //      1. Implement DST
 //      2. Make `Box<T>` not a language feature
 //      3. Move `Box<T>` to a separate crate, liballoc.
-//      4. Implement relevant trais in liballoc, not libcore
+//      4. Implement relevant traits in liballoc, not libcore
 //
 // Currently, no progress has been made on this list.
 
index 1481759297868a8be3095241f6c34783f75277ae..0d820836377d395dc95fdc77f4c0fe040dd996ba 100644 (file)
 use mem;
 use char;
 use clone::Clone;
+use cmp;
 use cmp::{Eq, TotalEq};
 use container::Container;
 use default::Default;
 use iter::{Filter, Map, Iterator};
 use iter::{Rev, DoubleEndedIterator, ExactSize};
+use iter::range;
 use num::Saturating;
 use option::{None, Option, Some};
 use raw::Repr;
 use slice::{ImmutableVector, Vector};
 use slice;
+use uint;
 
 /*
 Section: Creating a string
@@ -316,13 +319,207 @@ fn next(&mut self) -> Option<&'a str> {
     }
 }
 
+/// The internal state of an iterator that searches for matches of a substring
+/// within a larger string using naive search
+#[deriving(Clone)]
+struct NaiveSearcher {
+    position: uint
+}
+
+impl NaiveSearcher {
+    fn new() -> NaiveSearcher {
+        NaiveSearcher { position: 0 }
+    }
+
+    fn next(&mut self, haystack: &[u8], needle: &[u8]) -> Option<(uint, uint)> {
+        while self.position + needle.len() <= haystack.len() {
+            if haystack.slice(self.position, self.position + needle.len()) == needle {
+                let matchPos = self.position;
+                self.position += needle.len(); // add 1 for all matches
+                return Some((matchPos, matchPos + needle.len()));
+            } else {
+                self.position += 1;
+            }
+        }
+        None
+    }
+}
+
+/// The internal state of an iterator that searches for matches of a substring
+/// within a larger string using two-way search
+#[deriving(Clone)]
+struct TwoWaySearcher {
+    // constants
+    critPos: uint,
+    period: uint,
+    byteset: u64,
+
+    // variables
+    position: uint,
+    memory: uint
+}
+
+impl TwoWaySearcher {
+    fn new(needle: &[u8]) -> TwoWaySearcher {
+        let (critPos1, period1) = TwoWaySearcher::maximal_suffix(needle, false);
+        let (critPos2, period2) = TwoWaySearcher::maximal_suffix(needle, true);
+
+        let critPos;
+        let period;
+        if critPos1 > critPos2 {
+            critPos = critPos1;
+            period = period1;
+        } else {
+            critPos = critPos2;
+            period = period2;
+        }
+
+        let byteset = needle.iter().fold(0, |a, &b| (1 << (b & 0x3f)) | a);
+
+        if needle.slice_to(critPos) == needle.slice_from(needle.len() - critPos) {
+            TwoWaySearcher {
+                critPos: critPos,
+                period: period,
+                byteset: byteset,
+
+                position: 0,
+                memory: 0
+            }
+        } else {
+            TwoWaySearcher {
+                critPos: critPos,
+                period: cmp::max(critPos, needle.len() - critPos) + 1,
+                byteset: byteset,
+
+                position: 0,
+                memory: uint::MAX // Dummy value to signify that the period is long
+            }
+        }
+    }
+
+    #[inline]
+    fn next(&mut self, haystack: &[u8], needle: &[u8], longPeriod: bool) -> Option<(uint, uint)> {
+        'search: loop {
+            // Check that we have room to search in
+            if self.position + needle.len() > haystack.len() {
+                return None;
+            }
+
+            // Quickly skip by large portions unrelated to our substring
+            if (self.byteset >> (haystack[self.position + needle.len() - 1] & 0x3f)) & 1 == 0 {
+                self.position += needle.len();
+                continue 'search;
+            }
+
+            // See if the right part of the needle matches
+            let start = if longPeriod { self.critPos } else { cmp::max(self.critPos, self.memory) };
+            for i in range(start, needle.len()) {
+                if needle[i] != haystack[self.position + i] {
+                    self.position += i - self.critPos + 1;
+                    if !longPeriod {
+                        self.memory = 0;
+                    }
+                    continue 'search;
+                }
+            }
+
+            // See if the left part of the needle matches
+            let start = if longPeriod { 0 } else { self.memory };
+            for i in range(start, self.critPos).rev() {
+                if needle[i] != haystack[self.position + i] {
+                    self.position += self.period;
+                    if !longPeriod {
+                        self.memory = needle.len() - self.period;
+                    }
+                    continue 'search;
+                }
+            }
+
+            // We have found a match!
+            let matchPos = self.position;
+            self.position += needle.len(); // add self.period for all matches
+            if !longPeriod {
+                self.memory = 0; // set to needle.len() - self.period for all matches
+            }
+            return Some((matchPos, matchPos + needle.len()));
+        }
+    }
+
+    #[inline]
+    fn maximal_suffix(arr: &[u8], reversed: bool) -> (uint, uint) {
+        let mut left = -1; // Corresponds to i in the paper
+        let mut right = 0; // Corresponds to j in the paper
+        let mut offset = 1; // Corresponds to k in the paper
+        let mut period = 1; // Corresponds to p in the paper
+
+        while right + offset < arr.len() {
+            let a;
+            let b;
+            if reversed {
+                a = arr[left + offset];
+                b = arr[right + offset];
+            } else {
+                a = arr[right + offset];
+                b = arr[left + offset];
+            }
+            if a < b {
+                // Suffix is smaller, period is entire prefix so far.
+                right += offset;
+                offset = 1;
+                period = right - left;
+            } else if a == b {
+                // Advance through repetition of the current period.
+                if offset == period {
+                    right += offset;
+                    offset = 1;
+                } else {
+                    offset += 1;
+                }
+            } else {
+                // Suffix is larger, start over from current location.
+                left = right;
+                right += 1;
+                offset = 1;
+                period = 1;
+            }
+        }
+        (left + 1, period)
+    }
+}
+
+/// The internal state of an iterator that searches for matches of a substring
+/// within a larger string using a dynamically chosed search algorithm
+#[deriving(Clone)]
+enum Searcher {
+    Naive(NaiveSearcher),
+    TwoWay(TwoWaySearcher),
+    TwoWayLong(TwoWaySearcher)
+}
+
+impl Searcher {
+    fn new(haystack: &[u8], needle: &[u8]) -> Searcher {
+        // FIXME: Tune this.
+        if needle.len() > haystack.len() - 20 {
+            Naive(NaiveSearcher::new())
+        } else {
+            let searcher = TwoWaySearcher::new(needle);
+            if searcher.memory == uint::MAX { // If the period is long
+                TwoWayLong(searcher)
+            } else {
+                TwoWay(searcher)
+            }
+        }
+    }
+}
+
 /// An iterator over the start and end indices of the matches of a
 /// substring within a larger string
 #[deriving(Clone)]
 pub struct MatchIndices<'a> {
+    // constants
     haystack: &'a str,
     needle: &'a str,
-    position: uint,
+    searcher: Searcher
 }
 
 /// An iterator over the substrings of a string separated by a given
@@ -337,31 +534,14 @@ pub struct StrSplits<'a> {
 impl<'a> Iterator<(uint, uint)> for MatchIndices<'a> {
     #[inline]
     fn next(&mut self) -> Option<(uint, uint)> {
-        // See Issue #1932 for why this is a naive search
-        let (h_len, n_len) = (self.haystack.len(), self.needle.len());
-        let mut match_start = 0;
-        let mut match_i = 0;
-
-        while self.position < h_len {
-            if self.haystack[self.position] == self.needle[match_i] {
-                if match_i == 0 { match_start = self.position; }
-                match_i += 1;
-                self.position += 1;
-
-                if match_i == n_len {
-                    // found a match!
-                    return Some((match_start, self.position));
-                }
-            } else {
-                // failed match, backtrack
-                if match_i > 0 {
-                    match_i = 0;
-                    self.position = match_start;
-                }
-                self.position += 1;
-            }
+        match self.searcher {
+            Naive(ref mut searcher)
+                => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes()),
+            TwoWay(ref mut searcher)
+                => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false),
+            TwoWayLong(ref mut searcher)
+                => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true)
         }
-        None
     }
 }
 
@@ -542,7 +722,7 @@ pub struct UTF16Items<'a> {
     iter: slice::Items<'a, u16>
 }
 /// The possibilities for values decoded from a `u16` stream.
-#[deriving(Eq, TotalEq, Clone)]
+#[deriving(Eq, TotalEq, Clone, Show)]
 pub enum UTF16Item {
     /// A valid codepoint.
     ScalarValue(char),
@@ -1581,7 +1761,7 @@ fn match_indices(&self, sep: &'a str) -> MatchIndices<'a> {
         MatchIndices {
             haystack: *self,
             needle: sep,
-            position: 0
+            searcher: Searcher::new(self.as_bytes(), sep.as_bytes())
         }
     }
 
diff --git a/src/libcore/unit.rs b/src/libcore/unit.rs
deleted file mode 100644 (file)
index f55cb2d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.
-
-//! Functions for the unit type.
-
-#[cfg(not(test))]
-use default::Default;
-#[cfg(not(test))]
-use cmp::{Eq, Equal, Ord, Ordering, TotalEq, TotalOrd};
-
-#[cfg(not(test))]
-impl Eq for () {
-    #[inline]
-    fn eq(&self, _other: &()) -> bool { true }
-    #[inline]
-    fn ne(&self, _other: &()) -> bool { false }
-}
-
-#[cfg(not(test))]
-impl Ord for () {
-    #[inline]
-    fn lt(&self, _other: &()) -> bool { false }
-}
-
-#[cfg(not(test))]
-impl TotalOrd for () {
-    #[inline]
-    fn cmp(&self, _other: &()) -> Ordering { Equal }
-}
-
-#[cfg(not(test))]
-impl TotalEq for () {}
-
-#[cfg(not(test))]
-impl Default for () {
-    #[inline]
-    fn default() -> () { () }
-}
index 391dd01e80812e01c35cc864f2ade345d7f6668f..03050794d212ce21400c88e165da7a3084f6ca3c 100644 (file)
 
 /*!
 
-Simple compression
+Simple [DEFLATE][def]-based compression. This is a wrapper around the
+[`miniz`][mz] library, which is a one-file pure-C implementation of zlib.
+
+[def]: https://en.wikipedia.org/wiki/DEFLATE
+[mz]: https://code.google.com/p/miniz/
 
 */
 
 use std::c_vec::CVec;
 use libc::{c_void, size_t, c_int};
 
-
-pub mod rustrt {
-    use libc::{c_void, size_t, c_int};
-    #[link(name = "miniz", kind = "static")]
-    extern {
-        pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
-                                          src_buf_len: size_t,
-                                          pout_len: *mut size_t,
-                                          flags: c_int)
-                                          -> *mut c_void;
-
-        pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
-                                            src_buf_len: size_t,
-                                            pout_len: *mut size_t,
-                                            flags: c_int)
-                                            -> *mut c_void;
-    }
+#[link(name = "miniz", kind = "static")]
+extern {
+    /// Raw miniz compression function.
+    fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
+                                      src_buf_len: size_t,
+                                      pout_len: *mut size_t,
+                                      flags: c_int)
+                                      -> *mut c_void;
+
+    /// Raw miniz decompression function.
+    fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
+                                        src_buf_len: size_t,
+                                        pout_len: *mut size_t,
+                                        flags: c_int)
+                                        -> *mut c_void;
 }
 
 static LZ_NORM : c_int = 0x80;  // LZ with 128 probes, "normal"
@@ -57,7 +59,7 @@ pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
 fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
     unsafe {
         let mut outsz : size_t = 0;
-        let res = rustrt::tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void,
+        let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *c_void,
                                                      bytes.len() as size_t,
                                                      &mut outsz,
                                                      flags);
@@ -69,10 +71,12 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
     }
 }
 
+/// Compress a buffer, without writing any sort of header on the output.
 pub fn deflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
     deflate_bytes_internal(bytes, LZ_NORM)
 }
 
+/// Compress a buffer, using a header that zlib can understand.
 pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
     deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
 }
@@ -80,7 +84,7 @@ pub fn deflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
 fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
     unsafe {
         let mut outsz : size_t = 0;
-        let res = rustrt::tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void,
+        let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *c_void,
                                                        bytes.len() as size_t,
                                                        &mut outsz,
                                                        flags);
@@ -92,10 +96,12 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Option<CVec<u8>> {
     }
 }
 
+/// Decompress a buffer, without parsing any sort of header on the input.
 pub fn inflate_bytes(bytes: &[u8]) -> Option<CVec<u8>> {
     inflate_bytes_internal(bytes, 0)
 }
 
+/// Decompress a buffer that starts with a zlib header.
 pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<CVec<u8>> {
     inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
 }
index 2151e53548008afa05a619826dae6d7fb094278a..e12026340d8285b06e4fde2bfa32c2f313755f76 100644 (file)
@@ -203,7 +203,7 @@ pub struct Parser<'a> {
     cur: str::CharOffsets<'a>,
     depth: uint,
     /// Error messages accumulated during parsing
-    pub errors: Vec<~str>,
+    pub errors: Vec<StrBuf>,
 }
 
 impl<'a> Iterator<Piece<'a>> for Parser<'a> {
@@ -246,10 +246,10 @@ pub fn new<'a>(s: &'a str) -> Parser<'a> {
     }
 
     /// Notifies of an error. The message doesn't actually need to be of type
-    /// ~str, but I think it does when this eventually uses conditions so it
+    /// StrBuf, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
     fn err(&mut self, msg: &str) {
-        self.errors.push(msg.to_owned());
+        self.errors.push(msg.to_strbuf());
     }
 
     /// Optionally consumes the specified character. If the character is not at
index 3ac01681be1a7082b88b4c107fd14cd8bffbfce2..ba30e1a2e986bb12e8874627bb44a728acf316f0 100644 (file)
@@ -34,7 +34,7 @@
 //! use getopts::{optopt,optflag,getopts,OptGroup};
 //! use std::os;
 //!
-//! fn do_work(inp: &str, out: Option<~str>) {
+//! fn do_work(inp: &str, out: Option<StrBuf>) {
 //!     println!("{}", inp);
 //!     match out {
 //!         Some(x) => println!("{}", x),
@@ -49,7 +49,9 @@
 //! }
 //!
 //! fn main() {
-//!     let args = os::args();
+//!     let args: Vec<StrBuf> = os::args().iter()
+//!                                       .map(|x| x.to_strbuf())
+//!                                       .collect();
 //!
 //!     let program = args.get(0).clone();
 //!
 //!         Err(f) => { fail!(f.to_err_msg()) }
 //!     };
 //!     if matches.opt_present("h") {
-//!         print_usage(program, opts);
+//!         print_usage(program.as_slice(), opts);
 //!         return;
 //!     }
 //!     let output = matches.opt_str("o");
-//!     let input: &str = if !matches.free.is_empty() {
+//!     let input = if !matches.free.is_empty() {
 //!         (*matches.free.get(0)).clone()
 //!     } else {
-//!         print_usage(program, opts);
+//!         print_usage(program.as_slice(), opts);
 //!         return;
 //!     };
-//!     do_work(input, output);
+//!     do_work(input.as_slice(), output);
 //! }
 //! ~~~
 
 pub enum Name {
     /// A string representing the long name of an option.
     /// For example: "help"
-    Long(~str),
+    Long(StrBuf),
     /// A char representing the short name of an option.
     /// For example: 'h'
     Short(char),
@@ -145,13 +147,13 @@ pub struct Opt {
 #[deriving(Clone, Eq)]
 pub struct OptGroup {
     /// Short Name of the `OptGroup`
-    pub short_name: ~str,
+    pub short_name: StrBuf,
     /// Long Name of the `OptGroup`
-    pub long_name: ~str,
+    pub long_name: StrBuf,
     /// Hint
-    pub hint: ~str,
+    pub hint: StrBuf,
     /// Description
-    pub desc: ~str,
+    pub desc: StrBuf,
     /// Whether it has an argument
     pub hasarg: HasArg,
     /// How often it can occur
@@ -161,7 +163,7 @@ pub struct OptGroup {
 /// Describes wether an option is given at all or has a value.
 #[deriving(Clone, Eq)]
 enum Optval {
-    Val(~str),
+    Val(StrBuf),
     Given,
 }
 
@@ -174,7 +176,7 @@ pub struct Matches {
     /// Values of the Options that matched
     vals: Vec<Vec<Optval> > ,
     /// Free string fragments
-    pub free: Vec<~str>,
+    pub free: Vec<StrBuf>,
 }
 
 /// The type returned when the command line does not conform to the
@@ -183,15 +185,15 @@ pub struct Matches {
 #[deriving(Clone, Eq, Show)]
 pub enum Fail_ {
     /// The option requires an argument but none was passed.
-    ArgumentMissing(~str),
+    ArgumentMissing(StrBuf),
     /// The passed option is not declared among the possible options.
-    UnrecognizedOption(~str),
+    UnrecognizedOption(StrBuf),
     /// A required option is not present.
-    OptionMissing(~str),
+    OptionMissing(StrBuf),
     /// A single occurence option is being used multiple times.
-    OptionDuplicated(~str),
+    OptionDuplicated(StrBuf),
     /// There's an argument being passed to a non-argument option.
-    UnexpectedArgument(~str),
+    UnexpectedArgument(StrBuf),
 }
 
 /// The type of failure that occurred.
@@ -213,14 +215,14 @@ fn from_str(nm: &str) -> Name {
         if nm.len() == 1u {
             Short(nm.char_at(0u))
         } else {
-            Long(nm.to_owned())
+            Long(nm.to_strbuf())
         }
     }
 
-    fn to_str(&self) -> ~str {
+    fn to_str(&self) -> StrBuf {
         match *self {
-            Short(ch) => ch.to_str(),
-            Long(ref s) => s.to_owned()
+            Short(ch) => ch.to_str().to_strbuf(),
+            Long(ref s) => s.to_strbuf()
         }
     }
 }
@@ -246,7 +248,7 @@ pub fn long_to_short(&self) -> Opt {
                 aliases: Vec::new()
             },
             (1,0) => Opt {
-                name: Short(short_name.char_at(0)),
+                name: Short(short_name.as_slice().char_at(0)),
                 hasarg: hasarg,
                 occur: occur,
                 aliases: Vec::new()
@@ -257,7 +259,7 @@ pub fn long_to_short(&self) -> Opt {
                 occur:  occur,
                 aliases: vec!(
                     Opt {
-                        name: Short(short_name.char_at(0)),
+                        name: Short(short_name.as_slice().char_at(0)),
                         hasarg: hasarg,
                         occur:  occur,
                         aliases: Vec::new()
@@ -297,9 +299,10 @@ pub fn opt_count(&self, nm: &str) -> uint {
     }
 
     /// Returns true if any of several options were matched.
-    pub fn opts_present(&self, names: &[~str]) -> bool {
+    pub fn opts_present(&self, names: &[StrBuf]) -> bool {
         for nm in names.iter() {
-            match find_opt(self.opts.as_slice(), Name::from_str(*nm)) {
+            match find_opt(self.opts.as_slice(),
+                           Name::from_str(nm.as_slice())) {
                 Some(id) if !self.vals.get(id).is_empty() => return true,
                 _ => (),
             };
@@ -308,9 +311,9 @@ pub fn opts_present(&self, names: &[~str]) -> bool {
     }
 
     /// Returns the string argument supplied to one of several matching options or `None`.
-    pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
+    pub fn opts_str(&self, names: &[StrBuf]) -> Option<StrBuf> {
         for nm in names.iter() {
-            match self.opt_val(*nm) {
+            match self.opt_val(nm.as_slice()) {
                 Some(Val(ref s)) => return Some(s.clone()),
                 _ => ()
             }
@@ -322,8 +325,8 @@ pub fn opts_str(&self, names: &[~str]) -> Option<~str> {
     /// option.
     ///
     /// Used when an option accepts multiple values.
-    pub fn opt_strs(&self, nm: &str) -> Vec<~str> {
-        let mut acc: Vec<~str> = Vec::new();
+    pub fn opt_strs(&self, nm: &str) -> Vec<StrBuf> {
+        let mut acc: Vec<StrBuf> = Vec::new();
         let r = self.opt_vals(nm);
         for v in r.iter() {
             match *v {
@@ -335,10 +338,10 @@ pub fn opt_strs(&self, nm: &str) -> Vec<~str> {
     }
 
     /// Returns the string argument supplied to a matching option or `None`.
-    pub fn opt_str(&self, nm: &str) -> Option<~str> {
+    pub fn opt_str(&self, nm: &str) -> Option<StrBuf> {
         let vals = self.opt_vals(nm);
         if vals.is_empty() {
-            return None::<~str>;
+            return None::<StrBuf>;
         }
         match vals.get(0) {
             &Val(ref s) => Some((*s).clone()),
@@ -352,12 +355,14 @@ pub fn opt_str(&self, nm: &str) -> Option<~str> {
     /// Returns none if the option was not present, `def` if the option was
     /// present but no argument was provided, and the argument if the option was
     /// present and an argument was provided.
-    pub fn opt_default(&self, nm: &str, def: &str) -> Option<~str> {
+    pub fn opt_default(&self, nm: &str, def: &str) -> Option<StrBuf> {
         let vals = self.opt_vals(nm);
-        if vals.is_empty() { return None; }
+        if vals.is_empty() {
+            return None;
+        }
         match vals.get(0) {
             &Val(ref s) => Some((*s).clone()),
-            _ => Some(def.to_owned())
+            _ => Some(def.to_strbuf())
         }
     }
 
@@ -389,10 +394,10 @@ pub fn reqopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptG
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: hint.to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: hint.to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: Yes,
         occur: Req
     }
@@ -403,10 +408,10 @@ pub fn optopt(short_name: &str, long_name: &str, desc: &str, hint: &str) -> OptG
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: hint.to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: hint.to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: Yes,
         occur: Optional
     }
@@ -417,10 +422,10 @@ pub fn optflag(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: "".to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: "".to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: No,
         occur: Optional
     }
@@ -432,10 +437,10 @@ pub fn optflagmulti(short_name: &str, long_name: &str, desc: &str) -> OptGroup {
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: "".to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: "".to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: No,
         occur: Multi
     }
@@ -446,10 +451,10 @@ pub fn optflagopt(short_name: &str, long_name: &str, desc: &str, hint: &str) ->
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: hint.to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: hint.to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: Maybe,
         occur: Optional
     }
@@ -461,10 +466,10 @@ pub fn optmulti(short_name: &str, long_name: &str, desc: &str, hint: &str) -> Op
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: hint.to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: hint.to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: Yes,
         occur: Multi
     }
@@ -480,10 +485,10 @@ pub fn opt(short_name: &str,
     let len = short_name.len();
     assert!(len == 1 || len == 0);
     OptGroup {
-        short_name: short_name.to_owned(),
-        long_name: long_name.to_owned(),
-        hint: hint.to_owned(),
-        desc: desc.to_owned(),
+        short_name: short_name.to_strbuf(),
+        long_name: long_name.to_strbuf(),
+        hint: hint.to_strbuf(),
+        desc: desc.to_strbuf(),
         hasarg: hasarg,
         occur: occur
     }
@@ -491,22 +496,22 @@ pub fn opt(short_name: &str,
 
 impl Fail_ {
     /// Convert a `Fail_` enum into an error string.
-    pub fn to_err_msg(self) -> ~str {
+    pub fn to_err_msg(self) -> StrBuf {
         match self {
             ArgumentMissing(ref nm) => {
-                format!("Argument to option '{}' missing.", *nm)
+                format_strbuf!("Argument to option '{}' missing.", *nm)
             }
             UnrecognizedOption(ref nm) => {
-                format!("Unrecognized option: '{}'.", *nm)
+                format_strbuf!("Unrecognized option: '{}'.", *nm)
             }
             OptionMissing(ref nm) => {
-                format!("Required option '{}' missing.", *nm)
+                format_strbuf!("Required option '{}' missing.", *nm)
             }
             OptionDuplicated(ref nm) => {
-                format!("Option '{}' given more than once.", *nm)
+                format_strbuf!("Option '{}' given more than once.", *nm)
             }
             UnexpectedArgument(ref nm) => {
-                format!("Option '{}' does not take an argument.", *nm)
+                format_strbuf!("Option '{}' does not take an argument.", *nm)
             }
         }
     }
@@ -517,44 +522,44 @@ pub fn to_err_msg(self) -> ~str {
 /// On success returns `Ok(Opt)`. Use methods such as `opt_present`
 /// `opt_str`, etc. to interrogate results.  Returns `Err(Fail_)` on failure.
 /// Use `to_err_msg` to get an error message.
-pub fn getopts(args: &[~str], optgrps: &[OptGroup]) -> Result {
+pub fn getopts(args: &[StrBuf], optgrps: &[OptGroup]) -> Result {
     let opts: Vec<Opt> = optgrps.iter().map(|x| x.long_to_short()).collect();
     let n_opts = opts.len();
 
     fn f(_x: uint) -> Vec<Optval> { return Vec::new(); }
 
     let mut vals = Vec::from_fn(n_opts, f);
-    let mut free: Vec<~str> = Vec::new();
+    let mut free: Vec<StrBuf> = Vec::new();
     let l = args.len();
     let mut i = 0;
     while i < l {
         let cur = args[i].clone();
         let curlen = cur.len();
-        if !is_arg(cur) {
+        if !is_arg(cur.as_slice()) {
             free.push(cur);
-        } else if cur == "--".to_owned() {
+        } else if cur.as_slice() == "--" {
             let mut j = i + 1;
             while j < l { free.push(args[j].clone()); j += 1; }
             break;
         } else {
             let mut names;
             let mut i_arg = None;
-            if cur[1] == '-' as u8 {
-                let tail = cur.slice(2, curlen);
+            if cur.as_slice()[1] == '-' as u8 {
+                let tail = cur.as_slice().slice(2, curlen);
                 let tail_eq: Vec<&str> = tail.split('=').collect();
                 if tail_eq.len() <= 1 {
-                    names = vec!(Long(tail.to_owned()));
+                    names = vec!(Long(tail.to_strbuf()));
                 } else {
                     names =
-                        vec!(Long((*tail_eq.get(0)).to_owned()));
-                    i_arg = Some((*tail_eq.get(1)).to_owned());
+                        vec!(Long((*tail_eq.get(0)).to_strbuf()));
+                    i_arg = Some((*tail_eq.get(1)).to_strbuf());
                 }
             } else {
                 let mut j = 1;
                 let mut last_valid_opt_id = None;
                 names = Vec::new();
                 while j < curlen {
-                    let range = cur.char_range_at(j);
+                    let range = cur.as_slice().char_range_at(j);
                     let opt = Short(range.ch);
 
                     /* In a series of potential options (eg. -aheJ), if we
@@ -576,7 +581,8 @@ pub fn getopts(args: &[~str], optgrps: &[OptGroup]) -> Result {
                               No => false
                             };
                         if arg_follows && j < curlen {
-                            i_arg = Some(cur.slice(j, curlen).to_owned());
+                            i_arg = Some(cur.as_slice()
+                                            .slice(j, curlen).to_strbuf());
                             break;
                         } else {
                             last_valid_opt_id = None;
@@ -606,8 +612,8 @@ pub fn getopts(args: &[~str], optgrps: &[OptGroup]) -> Result {
                         vals.get_mut(optid)
                             .push(Val((i_arg.clone())
                             .unwrap()));
-                    } else if name_pos < names.len() ||
-                                  i + 1 == l || is_arg(args[i + 1]) {
+                    } else if name_pos < names.len() || i + 1 == l ||
+                            is_arg(args[i + 1].as_slice()) {
                         vals.get_mut(optid).push(Given);
                     } else {
                         i += 1;
@@ -653,7 +659,7 @@ pub fn getopts(args: &[~str], optgrps: &[OptGroup]) -> Result {
 }
 
 /// Derive a usage message from a set of long options.
-pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
+pub fn usage(brief: &str, opts: &[OptGroup]) -> StrBuf {
 
     let desc_sep = "\n" + " ".repeat(24);
 
@@ -672,7 +678,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
             0 => {}
             1 => {
                 row.push_char('-');
-                row.push_str(short_name);
+                row.push_str(short_name.as_slice());
                 row.push_char(' ');
             }
             _ => fail!("the short name should only be 1 ascii char long"),
@@ -683,7 +689,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
             0 => {}
             _ => {
                 row.push_str("--");
-                row.push_str(long_name);
+                row.push_str(long_name.as_slice());
                 row.push_char(' ');
             }
         }
@@ -691,10 +697,10 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
         // arg
         match hasarg {
             No => {}
-            Yes => row.push_str(hint),
+            Yes => row.push_str(hint.as_slice()),
             Maybe => {
                 row.push_char('[');
-                row.push_str(hint);
+                row.push_str(hint.as_slice());
                 row.push_char(']');
             }
         }
@@ -712,7 +718,7 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
 
         // Normalize desc to contain words separated by one space character
         let mut desc_normalized_whitespace = StrBuf::new();
-        for word in desc.words() {
+        for word in desc.as_slice().words() {
             desc_normalized_whitespace.push_str(word);
             desc_normalized_whitespace.push_char(' ');
         }
@@ -730,13 +736,15 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> ~str {
         // wrapped description
         row.push_str(desc_rows.connect(desc_sep));
 
-        row.into_owned()
+        row
     });
 
-    format!("{}\n\nOptions:\n{}\n", brief, rows.collect::<Vec<~str> >().connect("\n"))
+    format_strbuf!("{}\n\nOptions:\n{}\n",
+                   brief,
+                   rows.collect::<Vec<StrBuf>>().connect("\n"))
 }
 
-fn format_option(opt: &OptGroup) -> ~str {
+fn format_option(opt: &OptGroup) -> StrBuf {
     let mut line = StrBuf::new();
 
     if opt.occur != Req {
@@ -746,10 +754,10 @@ fn format_option(opt: &OptGroup) -> ~str {
     // Use short_name is possible, but fallback to long_name.
     if opt.short_name.len() > 0 {
         line.push_char('-');
-        line.push_str(opt.short_name);
+        line.push_str(opt.short_name.as_slice());
     } else {
         line.push_str("--");
-        line.push_str(opt.long_name);
+        line.push_str(opt.long_name.as_slice());
     }
 
     if opt.hasarg != No {
@@ -757,7 +765,7 @@ fn format_option(opt: &OptGroup) -> ~str {
         if opt.hasarg == Maybe {
             line.push_char('[');
         }
-        line.push_str(opt.hint);
+        line.push_str(opt.hint.as_slice());
         if opt.hasarg == Maybe {
             line.push_char(']');
         }
@@ -770,14 +778,14 @@ fn format_option(opt: &OptGroup) -> ~str {
         line.push_str("..");
     }
 
-    line.into_owned()
+    line
 }
 
 /// Derive a short one-line usage summary from a set of long options.
-pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> ~str {
-    let mut line = StrBuf::from_str("Usage: " + program_name + " ");
-    line.push_str(opts.iter().map(format_option).collect::<Vec<~str>>().connect(" "));
-    line.into_owned()
+pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> StrBuf {
+    let mut line = format_strbuf!("Usage: {} ", program_name);
+    line.push_str(opts.iter().map(format_option).collect::<Vec<StrBuf>>().connect(" "));
+    line
 }
 
 
@@ -886,18 +894,21 @@ enum LengthLimit {
 
 #[test]
 fn test_split_within() {
-    fn t(s: &str, i: uint, u: &[~str]) {
+    fn t(s: &str, i: uint, u: &[StrBuf]) {
         let mut v = Vec::new();
-        each_split_within(s, i, |s| { v.push(s.to_owned()); true });
+        each_split_within(s, i, |s| { v.push(s.to_strbuf()); true });
         assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
     }
     t("", 0, []);
     t("", 15, []);
-    t("hello", 15, ["hello".to_owned()]);
-    t("\nMary had a little lamb\nLittle lamb\n", 15,
-        ["Mary had a".to_owned(), "little lamb".to_owned(), "Little lamb".to_owned()]);
+    t("hello", 15, ["hello".to_strbuf()]);
+    t("\nMary had a little lamb\nLittle lamb\n", 15, [
+        "Mary had a".to_strbuf(),
+        "little lamb".to_strbuf(),
+        "Little lamb".to_strbuf()
+    ]);
     t("\nMary had a little lamb\nLittle lamb\n", ::std::uint::MAX,
-        ["Mary had a little lamb\nLittle lamb".to_owned()]);
+        ["Mary had a little lamb\nLittle lamb".to_strbuf()]);
 }
 
 #[cfg(test)]
@@ -920,25 +931,25 @@ fn check_fail_type(f: Fail_, ft: FailType) {
     // Tests for reqopt
     #[test]
     fn test_reqopt() {
-        let long_args = vec!("--test=20".to_owned());
+        let long_args = vec!("--test=20".to_strbuf());
         let opts = vec!(reqopt("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
             assert!(m.opt_present("test"));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!(m.opt_present("t"));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => { fail!("test_reqopt failed (long arg)"); }
         }
-        let short_args = vec!("-t".to_owned(), "20".to_owned());
+        let short_args = vec!("-t".to_strbuf(), "20".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Ok(ref m) => {
             assert!((m.opt_present("test")));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!((m.opt_present("t")));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => { fail!("test_reqopt failed (short arg)"); }
         }
@@ -946,7 +957,7 @@ fn test_reqopt() {
 
     #[test]
     fn test_reqopt_missing() {
-        let args = vec!("blah".to_owned());
+        let args = vec!("blah".to_strbuf());
         let opts = vec!(reqopt("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -957,14 +968,14 @@ fn test_reqopt_missing() {
 
     #[test]
     fn test_reqopt_no_arg() {
-        let long_args = vec!("--test".to_owned());
+        let long_args = vec!("--test".to_strbuf());
         let opts = vec!(reqopt("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned());
+        let short_args = vec!("-t".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
@@ -973,7 +984,7 @@ fn test_reqopt_no_arg() {
 
     #[test]
     fn test_reqopt_multi() {
-        let args = vec!("--test=20".to_owned(), "-t".to_owned(), "30".to_owned());
+        let args = vec!("--test=20".to_strbuf(), "-t".to_strbuf(), "30".to_strbuf());
         let opts = vec!(reqopt("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -985,25 +996,25 @@ fn test_reqopt_multi() {
     // Tests for optopt
     #[test]
     fn test_optopt() {
-        let long_args = vec!("--test=20".to_owned());
+        let long_args = vec!("--test=20".to_strbuf());
         let opts = vec!(optopt("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
             assert!(m.opt_present("test"));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!((m.opt_present("t")));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned(), "20".to_owned());
+        let short_args = vec!("-t".to_strbuf(), "20".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Ok(ref m) => {
             assert!((m.opt_present("test")));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!((m.opt_present("t")));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => fail!()
         }
@@ -1011,7 +1022,7 @@ fn test_optopt() {
 
     #[test]
     fn test_optopt_missing() {
-        let args = vec!("blah".to_owned());
+        let args = vec!("blah".to_strbuf());
         let opts = vec!(optopt("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1025,14 +1036,14 @@ fn test_optopt_missing() {
 
     #[test]
     fn test_optopt_no_arg() {
-        let long_args = vec!("--test".to_owned());
+        let long_args = vec!("--test".to_strbuf());
         let opts = vec!(optopt("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned());
+        let short_args = vec!("-t".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
@@ -1041,7 +1052,7 @@ fn test_optopt_no_arg() {
 
     #[test]
     fn test_optopt_multi() {
-        let args = vec!("--test=20".to_owned(), "-t".to_owned(), "30".to_owned());
+        let args = vec!("--test=20".to_strbuf(), "-t".to_strbuf(), "30".to_strbuf());
         let opts = vec!(optopt("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1053,7 +1064,7 @@ fn test_optopt_multi() {
     // Tests for optflag
     #[test]
     fn test_optflag() {
-        let long_args = vec!("--test".to_owned());
+        let long_args = vec!("--test".to_strbuf());
         let opts = vec!(optflag("t", "test", "testing"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
@@ -1063,7 +1074,7 @@ fn test_optflag() {
           }
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned());
+        let short_args = vec!("-t".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Ok(ref m) => {
             assert!(m.opt_present("test"));
@@ -1075,7 +1086,7 @@ fn test_optflag() {
 
     #[test]
     fn test_optflag_missing() {
-        let args = vec!("blah".to_owned());
+        let args = vec!("blah".to_strbuf());
         let opts = vec!(optflag("t", "test", "testing"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1089,7 +1100,7 @@ fn test_optflag_missing() {
 
     #[test]
     fn test_optflag_long_arg() {
-        let args = vec!("--test=20".to_owned());
+        let args = vec!("--test=20".to_strbuf());
         let opts = vec!(optflag("t", "test", "testing"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1103,7 +1114,7 @@ fn test_optflag_long_arg() {
 
     #[test]
     fn test_optflag_multi() {
-        let args = vec!("--test".to_owned(), "-t".to_owned());
+        let args = vec!("--test".to_strbuf(), "-t".to_strbuf());
         let opts = vec!(optflag("t", "test", "testing"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1114,14 +1125,14 @@ fn test_optflag_multi() {
 
     #[test]
     fn test_optflag_short_arg() {
-        let args = vec!("-t".to_owned(), "20".to_owned());
+        let args = vec!("-t".to_strbuf(), "20".to_strbuf());
         let opts = vec!(optflag("t", "test", "testing"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
             // The next variable after the flag is just a free argument
 
-            assert!(*m.free.get(0) == "20".to_owned());
+            assert!(*m.free.get(0) == "20".to_strbuf());
           }
           _ => fail!()
         }
@@ -1130,7 +1141,7 @@ fn test_optflag_short_arg() {
     // Tests for optflagmulti
     #[test]
     fn test_optflagmulti_short1() {
-        let args = vec!("-v".to_owned());
+        let args = vec!("-v".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1143,7 +1154,7 @@ fn test_optflagmulti_short1() {
 
     #[test]
     fn test_optflagmulti_short2a() {
-        let args = vec!("-v".to_owned(), "-v".to_owned());
+        let args = vec!("-v".to_strbuf(), "-v".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1156,7 +1167,7 @@ fn test_optflagmulti_short2a() {
 
     #[test]
     fn test_optflagmulti_short2b() {
-        let args = vec!("-vv".to_owned());
+        let args = vec!("-vv".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1169,7 +1180,7 @@ fn test_optflagmulti_short2b() {
 
     #[test]
     fn test_optflagmulti_long1() {
-        let args = vec!("--verbose".to_owned());
+        let args = vec!("--verbose".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1182,7 +1193,7 @@ fn test_optflagmulti_long1() {
 
     #[test]
     fn test_optflagmulti_long2() {
-        let args = vec!("--verbose".to_owned(), "--verbose".to_owned());
+        let args = vec!("--verbose".to_strbuf(), "--verbose".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1195,8 +1206,8 @@ fn test_optflagmulti_long2() {
 
     #[test]
     fn test_optflagmulti_mix() {
-        let args = vec!("--verbose".to_owned(), "-v".to_owned(),
-                        "-vv".to_owned(), "verbose".to_owned());
+        let args = vec!("--verbose".to_strbuf(), "-v".to_strbuf(),
+                        "-vv".to_strbuf(), "verbose".to_strbuf());
         let opts = vec!(optflagmulti("v", "verbose", "verbosity"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1211,25 +1222,25 @@ fn test_optflagmulti_mix() {
     // Tests for optmulti
     #[test]
     fn test_optmulti() {
-        let long_args = vec!("--test=20".to_owned());
+        let long_args = vec!("--test=20".to_strbuf());
         let opts = vec!(optmulti("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
             assert!((m.opt_present("test")));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!((m.opt_present("t")));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned(), "20".to_owned());
+        let short_args = vec!("-t".to_strbuf(), "20".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Ok(ref m) => {
             assert!((m.opt_present("test")));
-            assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
             assert!((m.opt_present("t")));
-            assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+            assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
           }
           _ => fail!()
         }
@@ -1237,7 +1248,7 @@ fn test_optmulti() {
 
     #[test]
     fn test_optmulti_missing() {
-        let args = vec!("blah".to_owned());
+        let args = vec!("blah".to_strbuf());
         let opts = vec!(optmulti("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
@@ -1251,14 +1262,14 @@ fn test_optmulti_missing() {
 
     #[test]
     fn test_optmulti_no_arg() {
-        let long_args = vec!("--test".to_owned());
+        let long_args = vec!("--test".to_strbuf());
         let opts = vec!(optmulti("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
         }
-        let short_args = vec!("-t".to_owned());
+        let short_args = vec!("-t".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Err(f) => check_fail_type(f, ArgumentMissing_),
           _ => fail!()
@@ -1267,18 +1278,18 @@ fn test_optmulti_no_arg() {
 
     #[test]
     fn test_optmulti_multi() {
-        let args = vec!("--test=20".to_owned(), "-t".to_owned(), "30".to_owned());
+        let args = vec!("--test=20".to_strbuf(), "-t".to_strbuf(), "30".to_strbuf());
         let opts = vec!(optmulti("t", "test", "testing", "TEST"));
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
               assert!(m.opt_present("test"));
-              assert_eq!(m.opt_str("test").unwrap(), "20".to_owned());
+              assert_eq!(m.opt_str("test").unwrap(), "20".to_strbuf());
               assert!(m.opt_present("t"));
-              assert_eq!(m.opt_str("t").unwrap(), "20".to_owned());
+              assert_eq!(m.opt_str("t").unwrap(), "20".to_strbuf());
               let pair = m.opt_strs("test");
-              assert!(*pair.get(0) == "20".to_owned());
-              assert!(*pair.get(1) == "30".to_owned());
+              assert!(*pair.get(0) == "20".to_strbuf());
+              assert!(*pair.get(1) == "30".to_strbuf());
           }
           _ => fail!()
         }
@@ -1286,14 +1297,14 @@ fn test_optmulti_multi() {
 
     #[test]
     fn test_unrecognized_option() {
-        let long_args = vec!("--untest".to_owned());
+        let long_args = vec!("--untest".to_strbuf());
         let opts = vec!(optmulti("t", "test", "testing", "TEST"));
         let rs = getopts(long_args.as_slice(), opts.as_slice());
         match rs {
           Err(f) => check_fail_type(f, UnrecognizedOption_),
           _ => fail!()
         }
-        let short_args = vec!("-u".to_owned());
+        let short_args = vec!("-u".to_strbuf());
         match getopts(short_args.as_slice(), opts.as_slice()) {
           Err(f) => check_fail_type(f, UnrecognizedOption_),
           _ => fail!()
@@ -1303,10 +1314,22 @@ fn test_unrecognized_option() {
     #[test]
     fn test_combined() {
         let args =
-            vec!("prog".to_owned(), "free1".to_owned(), "-s".to_owned(), "20".to_owned(),
-            "free2".to_owned(), "--flag".to_owned(), "--long=30".to_owned(), "-f".to_owned(),
-            "-m".to_owned(), "40".to_owned(), "-m".to_owned(), "50".to_owned(), "-n".to_owned(),
-            "-A B".to_owned(), "-n".to_owned(), "-60 70".to_owned());
+            vec!("prog".to_strbuf(),
+                 "free1".to_strbuf(),
+                 "-s".to_strbuf(),
+                 "20".to_strbuf(),
+                 "free2".to_strbuf(),
+                 "--flag".to_strbuf(),
+                 "--long=30".to_strbuf(),
+                 "-f".to_strbuf(),
+                 "-m".to_strbuf(),
+                 "40".to_strbuf(),
+                 "-m".to_strbuf(),
+                 "50".to_strbuf(),
+                 "-n".to_strbuf(),
+                 "-A B".to_strbuf(),
+                 "-n".to_strbuf(),
+                 "-60 70".to_strbuf());
         let opts =
             vec!(optopt("s", "something", "something", "SOMETHING"),
               optflag("", "flag", "a flag"),
@@ -1318,19 +1341,19 @@ fn test_combined() {
         let rs = getopts(args.as_slice(), opts.as_slice());
         match rs {
           Ok(ref m) => {
-            assert!(*m.free.get(0) == "prog".to_owned());
-            assert!(*m.free.get(1) == "free1".to_owned());
-            assert_eq!(m.opt_str("s").unwrap(), "20".to_owned());
-            assert!(*m.free.get(2) == "free2".to_owned());
+            assert!(*m.free.get(0) == "prog".to_strbuf());
+            assert!(*m.free.get(1) == "free1".to_strbuf());
+            assert_eq!(m.opt_str("s").unwrap(), "20".to_strbuf());
+            assert!(*m.free.get(2) == "free2".to_strbuf());
             assert!((m.opt_present("flag")));
-            assert_eq!(m.opt_str("long").unwrap(), "30".to_owned());
+            assert_eq!(m.opt_str("long").unwrap(), "30".to_strbuf());
             assert!((m.opt_present("f")));
             let pair = m.opt_strs("m");
-            assert!(*pair.get(0) == "40".to_owned());
-            assert!(*pair.get(1) == "50".to_owned());
+            assert!(*pair.get(0) == "40".to_strbuf());
+            assert!(*pair.get(1) == "50".to_strbuf());
             let pair = m.opt_strs("n");
-            assert!(*pair.get(0) == "-A B".to_owned());
-            assert!(*pair.get(1) == "-60 70".to_owned());
+            assert!(*pair.get(0) == "-A B".to_strbuf());
+            assert!(*pair.get(1) == "-60 70".to_strbuf());
             assert!((!m.opt_present("notpresent")));
           }
           _ => fail!()
@@ -1343,68 +1366,68 @@ fn test_multi() {
                      optopt("", "encrypt", "encrypt", "ENCRYPT"),
                      optopt("f", "", "flag", "FLAG"));
 
-        let args_single = vec!("-e".to_owned(), "foo".to_owned());
+        let args_single = vec!("-e".to_strbuf(), "foo".to_strbuf());
         let matches_single = &match getopts(args_single.as_slice(),
                                             opts.as_slice()) {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(matches_single.opts_present(["e".to_owned()]));
-        assert!(matches_single.opts_present(["encrypt".to_owned(), "e".to_owned()]));
-        assert!(matches_single.opts_present(["e".to_owned(), "encrypt".to_owned()]));
-        assert!(!matches_single.opts_present(["encrypt".to_owned()]));
-        assert!(!matches_single.opts_present(["thing".to_owned()]));
+        assert!(matches_single.opts_present(["e".to_strbuf()]));
+        assert!(matches_single.opts_present(["encrypt".to_strbuf(), "e".to_strbuf()]));
+        assert!(matches_single.opts_present(["e".to_strbuf(), "encrypt".to_strbuf()]));
+        assert!(!matches_single.opts_present(["encrypt".to_strbuf()]));
+        assert!(!matches_single.opts_present(["thing".to_strbuf()]));
         assert!(!matches_single.opts_present([]));
 
-        assert_eq!(matches_single.opts_str(["e".to_owned()]).unwrap(), "foo".to_owned());
-        assert_eq!(matches_single.opts_str(["e".to_owned(), "encrypt".to_owned()]).unwrap(),
-                   "foo".to_owned());
-        assert_eq!(matches_single.opts_str(["encrypt".to_owned(), "e".to_owned()]).unwrap(),
-                   "foo".to_owned());
+        assert_eq!(matches_single.opts_str(["e".to_strbuf()]).unwrap(), "foo".to_strbuf());
+        assert_eq!(matches_single.opts_str(["e".to_strbuf(), "encrypt".to_strbuf()]).unwrap(),
+                   "foo".to_strbuf());
+        assert_eq!(matches_single.opts_str(["encrypt".to_strbuf(), "e".to_strbuf()]).unwrap(),
+                   "foo".to_strbuf());
 
-        let args_both = vec!("-e".to_owned(), "foo".to_owned(), "--encrypt".to_owned(),
-                             "foo".to_owned());
+        let args_both = vec!("-e".to_strbuf(), "foo".to_strbuf(), "--encrypt".to_strbuf(),
+                             "foo".to_strbuf());
         let matches_both = &match getopts(args_both.as_slice(),
                                           opts.as_slice()) {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(matches_both.opts_present(["e".to_owned()]));
-        assert!(matches_both.opts_present(["encrypt".to_owned()]));
-        assert!(matches_both.opts_present(["encrypt".to_owned(), "e".to_owned()]));
-        assert!(matches_both.opts_present(["e".to_owned(), "encrypt".to_owned()]));
-        assert!(!matches_both.opts_present(["f".to_owned()]));
-        assert!(!matches_both.opts_present(["thing".to_owned()]));
+        assert!(matches_both.opts_present(["e".to_strbuf()]));
+        assert!(matches_both.opts_present(["encrypt".to_strbuf()]));
+        assert!(matches_both.opts_present(["encrypt".to_strbuf(), "e".to_strbuf()]));
+        assert!(matches_both.opts_present(["e".to_strbuf(), "encrypt".to_strbuf()]));
+        assert!(!matches_both.opts_present(["f".to_strbuf()]));
+        assert!(!matches_both.opts_present(["thing".to_strbuf()]));
         assert!(!matches_both.opts_present([]));
 
-        assert_eq!(matches_both.opts_str(["e".to_owned()]).unwrap(), "foo".to_owned());
-        assert_eq!(matches_both.opts_str(["encrypt".to_owned()]).unwrap(), "foo".to_owned());
-        assert_eq!(matches_both.opts_str(["e".to_owned(), "encrypt".to_owned()]).unwrap(),
-                   "foo".to_owned());
-        assert_eq!(matches_both.opts_str(["encrypt".to_owned(), "e".to_owned()]).unwrap(),
-                   "foo".to_owned());
+        assert_eq!(matches_both.opts_str(["e".to_strbuf()]).unwrap(), "foo".to_strbuf());
+        assert_eq!(matches_both.opts_str(["encrypt".to_strbuf()]).unwrap(), "foo".to_strbuf());
+        assert_eq!(matches_both.opts_str(["e".to_strbuf(), "encrypt".to_strbuf()]).unwrap(),
+                   "foo".to_strbuf());
+        assert_eq!(matches_both.opts_str(["encrypt".to_strbuf(), "e".to_strbuf()]).unwrap(),
+                   "foo".to_strbuf());
     }
 
     #[test]
     fn test_nospace() {
-        let args = vec!("-Lfoo".to_owned(), "-M.".to_owned());
+        let args = vec!("-Lfoo".to_strbuf(), "-M.".to_strbuf());
         let opts = vec!(optmulti("L", "", "library directory", "LIB"),
                      optmulti("M", "", "something", "MMMM"));
         let matches = &match getopts(args.as_slice(), opts.as_slice()) {
           result::Ok(m) => m,
           result::Err(_) => fail!()
         };
-        assert!(matches.opts_present(["L".to_owned()]));
-        assert_eq!(matches.opts_str(["L".to_owned()]).unwrap(), "foo".to_owned());
-        assert!(matches.opts_present(["M".to_owned()]));
-        assert_eq!(matches.opts_str(["M".to_owned()]).unwrap(), ".".to_owned());
+        assert!(matches.opts_present(["L".to_strbuf()]));
+        assert_eq!(matches.opts_str(["L".to_strbuf()]).unwrap(), "foo".to_strbuf());
+        assert!(matches.opts_present(["M".to_strbuf()]));
+        assert_eq!(matches.opts_str(["M".to_strbuf()]).unwrap(), ".".to_strbuf());
 
     }
 
     #[test]
     fn test_long_to_short() {
         let mut short = Opt {
-            name: Long("banana".to_owned()),
+            name: Long("banana".to_strbuf()),
             hasarg: Yes,
             occur: Req,
             aliases: Vec::new(),
@@ -1423,7 +1446,7 @@ fn test_aliases_long_and_short() {
         let opts = vec!(
             optflagmulti("a", "apple", "Desc"));
 
-        let args = vec!("-a".to_owned(), "--apple".to_owned(), "-a".to_owned());
+        let args = vec!("-a".to_strbuf(), "--apple".to_strbuf(), "-a".to_strbuf());
 
         let matches = getopts(args.as_slice(), opts.as_slice()).unwrap();
         assert_eq!(3, matches.opt_count("a"));
@@ -1450,7 +1473,7 @@ fn test_usage() {
     -k --kiwi           Desc
     -p [VAL]            Desc
     -l VAL              Desc
-".to_owned();
+".to_strbuf();
 
         let generated_usage = usage("Usage: fruits", optgroups.as_slice());
 
@@ -1477,7 +1500,7 @@ fn test_usage_description_wrapping() {
     -k --kiwi           This is a long description which won't be wrapped..+..
     -a --apple          This is a long description which _will_ be
                         wrapped..+..
-".to_owned();
+".to_strbuf();
 
         let usage = usage("Usage: fruits", optgroups.as_slice());
 
@@ -1503,7 +1526,7 @@ fn test_usage_description_multibyte_handling() {
     -a --apple          This “description” has some characters that could
                         confuse the line wrapping; an apple costs 0.51€ in
                         some parts of Europe.
-".to_owned();
+".to_strbuf();
 
         let usage = usage("Usage: fruits", optgroups.as_slice());
 
@@ -1522,7 +1545,7 @@ fn test_short_usage() {
             optflagopt("p", "", "Desc", "VAL"),
             optmulti("l", "", "Desc", "VAL"));
 
-        let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_owned();
+        let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_strbuf();
         let generated_usage = short_usage("fruits", optgroups.as_slice());
 
         debug!("expected: <<{}>>", expected);
index 34e29b06f76ccb2a16939a838b730dbf5c0791fe..1921eef9f60d46d4d6fa28dc2f22485265ac0e7a 100644 (file)
@@ -51,11 +51,9 @@ macro_rules! rtabort (
 )
 
 pub fn dumb_println(args: &fmt::Arguments) {
-    use std::io;
     use std::rt;
-
     let mut w = rt::Stderr;
-    let _ = fmt::writeln(&mut w as &mut io::Writer, args);
+    let _ = writeln!(&mut w, "{}", args);
 }
 
 pub fn abort(msg: &str) -> ! {
index 8c294fa2928f0a5e35f31e37e6becb8d3069b89b..812e998ad9d901978eba33b7c8bb1c3232077eb4 100644 (file)
@@ -1137,11 +1137,10 @@ fn test_home_sched() {
     fn test_schedule_home_states() {
         use sleeper_list::SleeperList;
         use super::{Shutdown, Scheduler, SchedHandle};
-        use std::unstable::run_in_bare_thread;
         use std::rt::thread::Thread;
         use std::sync::deque::BufferPool;
 
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let sleepers = SleeperList::new();
             let mut pool = BufferPool::new();
             let (normal_worker, normal_stealer) = pool.deque();
@@ -1260,7 +1259,7 @@ fn run(next: Box<GreenTask>) {
 
             normal_thread.join();
             special_thread.join();
-        });
+        }).join();
     }
 
     //#[test]
index 9dd87a38fb63af5d139884bc4537216118ba7359..5981f87b4f2b6fbe988a7ea5fbc762d75ac5fae8 100644 (file)
@@ -188,7 +188,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Signed for LogLevel {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let LogLevel(level) = *self;
-        write!(fmt.buf, "{}", level)
+        write!(fmt, "{}", level)
     }
 }
 
index c2b69483fa1e0d4e206f5de4ddb10216a155478b..046d2875d553101700a56b970ca2c6a72098e52c 100644 (file)
@@ -493,9 +493,7 @@ fn gen(_stat: &libc::stat) -> u64 { 0 }
     io::FileStat {
         size: stat.st_size as u64,
         kind: kind,
-        perm: unsafe {
-            io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions
-        },
+        perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32),
         created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64),
         modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64),
         accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64),
index d721e1d67f1b99bf9d85f79c50c6868b144f3251..3222c912dd0857fe6f3afea505dd7b47c6d7eef8 100644 (file)
@@ -492,9 +492,7 @@ fn mkstat(stat: &libc::stat) -> io::FileStat {
     io::FileStat {
         size: stat.st_size as u64,
         kind: kind,
-        perm: unsafe {
-          io::FilePermission::from_bits(stat.st_mode as u32)  & io::AllPermissions
-        },
+        perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32),
         created: stat.st_ctime as u64,
         modified: stat.st_mtime as u64,
         accessed: stat.st_atime as u64,
index a9aca656319efa7a4263131246c4f3412023c0ad..0c103bc4695fd7bbb1146e69b1f5bac49c2bb761 100644 (file)
 use std::io;
 use std::io::IoError;
 use std::io::net::ip::SocketAddr;
-use std::io::process::ProcessConfig;
 use std::io::signal::Signum;
 use std::os;
 use std::rt::rtio;
 use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket};
 use std::rt::rtio::{RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess};
-use std::rt::rtio::{RtioSignal, RtioTTY, CloseBehavior, RtioTimer};
+use std::rt::rtio::{RtioSignal, RtioTTY, CloseBehavior, RtioTimer, ProcessConfig};
 use ai = std::io::net::addrinfo;
 
 // Local re-exports
@@ -258,10 +257,10 @@ fn fs_utime(&mut self, src: &CString, atime: u64,
     fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>> {
         timer::Timer::new().map(|t| box t as Box<RtioTimer:Send>)
     }
-    fn spawn(&mut self, config: ProcessConfig)
+    fn spawn(&mut self, cfg: ProcessConfig)
             -> IoResult<(Box<RtioProcess:Send>,
                          Vec<Option<Box<RtioPipe:Send>>>)> {
-        process::Process::spawn(config).map(|(p, io)| {
+        process::Process::spawn(cfg).map(|(p, io)| {
             (box p as Box<RtioProcess:Send>,
              io.move_iter().map(|p| p.map(|p| {
                  box p as Box<RtioPipe:Send>
index 799db64e6889775878386af1bf26ceb6b5913662..0eebd3380e626c21953780729dd82e9e11ed3aa1 100644 (file)
 use std::os;
 use std::ptr;
 use std::rt::rtio;
+use std::rt::rtio::ProcessConfig;
+use std::c_str::CString;
 use p = std::io::process;
 
-
 use super::IoResult;
 use super::file;
 use super::util;
@@ -65,27 +66,11 @@ impl Process {
     /// Creates a new process using native process-spawning abilities provided
     /// by the OS. Operations on this process will be blocking instead of using
     /// the runtime for sleeping just this current task.
-    ///
-    /// # Arguments
-    ///
-    /// * prog - the program to run
-    /// * args - the arguments to pass to the program, not including the program
-    ///          itself
-    /// * env - an optional environment to specify for the child process. If
-    ///         this value is `None`, then the child will inherit the parent's
-    ///         environment
-    /// * cwd - an optionally specified current working directory of the child,
-    ///         defaulting to the parent's current working directory
-    /// * stdin, stdout, stderr - These optionally specified file descriptors
-    ///     dictate where the stdin/out/err of the child process will go. If
-    ///     these are `None`, then this module will bind the input/output to an
-    ///     os pipe instead. This process takes ownership of these file
-    ///     descriptors, closing them upon destruction of the process.
-    pub fn spawn(config: p::ProcessConfig)
+    pub fn spawn(cfg: ProcessConfig)
         -> Result<(Process, Vec<Option<file::FileDesc>>), io::IoError>
     {
         // right now we only handle stdin/stdout/stderr.
-        if config.extra_io.len() > 0 {
+        if cfg.extra_io.len() > 0 {
             return Err(super::unimpl());
         }
 
@@ -109,14 +94,11 @@ fn get_io(io: p::StdioContainer, ret: &mut Vec<Option<file::FileDesc>>)
         }
 
         let mut ret_io = Vec::new();
-        let (in_pipe, in_fd) = get_io(config.stdin, &mut ret_io);
-        let (out_pipe, out_fd) = get_io(config.stdout, &mut ret_io);
-        let (err_pipe, err_fd) = get_io(config.stderr, &mut ret_io);
+        let (in_pipe, in_fd) = get_io(cfg.stdin, &mut ret_io);
+        let (out_pipe, out_fd) = get_io(cfg.stdout, &mut ret_io);
+        let (err_pipe, err_fd) = get_io(cfg.stderr, &mut ret_io);
 
-        let env = config.env.map(|a| a.to_owned());
-        let cwd = config.cwd.map(|a| Path::new(a));
-        let res = spawn_process_os(config, env, cwd.as_ref(), in_fd, out_fd,
-                                   err_fd);
+        let res = spawn_process_os(cfg, in_fd, out_fd, err_fd);
 
         unsafe {
             for pipe in in_pipe.iter() { let _ = libc::close(pipe.input); }
@@ -262,11 +244,8 @@ struct SpawnProcessResult {
 }
 
 #[cfg(windows)]
-fn spawn_process_os(config: p::ProcessConfig,
-                    env: Option<~[(~str, ~str)]>,
-                    dir: Option<&Path>,
-                    in_fd: c_int, out_fd: c_int,
-                    err_fd: c_int) -> IoResult<SpawnProcessResult> {
+fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_int)
+                 -> IoResult<SpawnProcessResult> {
     use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
     use libc::consts::os::extra::{
         TRUE, FALSE,
@@ -284,7 +263,7 @@ fn spawn_process_os(config: p::ProcessConfig,
 
     use std::mem;
 
-    if config.gid.is_some() || config.uid.is_some() {
+    if cfg.gid.is_some() || cfg.uid.is_some() {
         return Err(io::IoError {
             kind: io::OtherIoError,
             desc: "unsupported gid/uid requested on windows",
@@ -293,7 +272,6 @@ fn spawn_process_os(config: p::ProcessConfig,
     }
 
     unsafe {
-
         let mut si = zeroed_startupinfo();
         si.cb = mem::size_of::<STARTUPINFO>() as DWORD;
         si.dwFlags = STARTF_USESTDHANDLES;
@@ -333,23 +311,26 @@ fn spawn_process_os(config: p::ProcessConfig,
             }
         }
 
-        let cmd = make_command_line(config.program, config.args);
+        let cmd_str = make_command_line(cfg.program, cfg.args);
         let mut pi = zeroed_process_information();
         let mut create_err = None;
 
         // stolen from the libuv code.
         let mut flags = libc::CREATE_UNICODE_ENVIRONMENT;
-        if config.detach {
+        if cfg.detach {
             flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP;
         }
 
-        with_envp(env, |envp| {
-            with_dirp(dir, |dirp| {
-                os::win32::as_mut_utf16_p(cmd, |cmdp| {
-                    let created = CreateProcessW(ptr::null(), cmdp,
-                                                 ptr::mut_null(), ptr::mut_null(), TRUE,
-                                                 flags, envp, dirp, &mut si,
-                                                 &mut pi);
+        with_envp(cfg.env, |envp| {
+            with_dirp(cfg.cwd, |dirp| {
+                os::win32::as_mut_utf16_p(cmd_str, |cmdp| {
+                    let created = CreateProcessW(ptr::null(),
+                                                 cmdp,
+                                                 ptr::mut_null(),
+                                                 ptr::mut_null(),
+                                                 TRUE,
+                                                 flags, envp, dirp,
+                                                 &mut si, &mut pi);
                     if created == FALSE {
                         create_err = Some(super::last_error());
                     }
@@ -415,12 +396,14 @@ fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMA
 }
 
 #[cfg(windows)]
-fn make_command_line(prog: &str, args: &[~str]) -> ~str {
+fn make_command_line(prog: &CString, args: &[CString]) -> ~str {
     let mut cmd = StrBuf::new();
-    append_arg(&mut cmd, prog);
+    append_arg(&mut cmd, prog.as_str()
+                             .expect("expected program name to be utf-8 encoded"));
     for arg in args.iter() {
         cmd.push_char(' ');
-        append_arg(&mut cmd, *arg);
+        append_arg(&mut cmd, arg.as_str()
+                                .expect("expected argument to be utf-8 encoded"));
     }
     return cmd.into_owned();
 
@@ -468,11 +451,9 @@ fn backslash_run_ends_in_quote(s: &Vec<char>, mut i: uint) -> bool {
 }
 
 #[cfg(unix)]
-fn spawn_process_os(config: p::ProcessConfig,
-                    env: Option<~[(~str, ~str)]>,
-                    dir: Option<&Path>,
-                    in_fd: c_int, out_fd: c_int,
-                    err_fd: c_int) -> IoResult<SpawnProcessResult> {
+fn spawn_process_os(cfg: ProcessConfig, in_fd: c_int, out_fd: c_int, err_fd: c_int)
+                -> IoResult<SpawnProcessResult>
+{
     use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
     use libc::funcs::bsd44::getdtablesize;
     use io::c;
@@ -500,11 +481,10 @@ unsafe fn set_cloexec(fd: c_int) {
         assert_eq!(ret, 0);
     }
 
-    let dirp = dir.map(|p| p.to_c_str());
-    let dirp = dirp.as_ref().map(|c| c.with_ref(|p| p)).unwrap_or(ptr::null());
+    let dirp = cfg.cwd.map(|c| c.with_ref(|p| p)).unwrap_or(ptr::null());
 
-    with_envp(env, proc(envp) {
-        with_argv(config.program, config.args, proc(argv) unsafe {
+    with_envp(cfg.env, proc(envp) {
+        with_argv(cfg.program, cfg.args, proc(argv) unsafe {
             let pipe = os::pipe();
             let mut input = file::FileDesc::new(pipe.input, true);
             let mut output = file::FileDesc::new(pipe.out, true);
@@ -605,7 +585,7 @@ fn fail(output: &mut file::FileDesc) -> ! {
                 }
             }
 
-            match config.gid {
+            match cfg.gid {
                 Some(u) => {
                     if libc::setgid(u as libc::gid_t) != 0 {
                         fail(&mut output);
@@ -613,7 +593,7 @@ fn fail(output: &mut file::FileDesc) -> ! {
                 }
                 None => {}
             }
-            match config.uid {
+            match cfg.uid {
                 Some(u) => {
                     // When dropping privileges from root, the `setgroups` call will
                     // remove any extraneous groups. If we don't call this, then
@@ -633,7 +613,7 @@ fn setgroups(ngroups: libc::c_int,
                 }
                 None => {}
             }
-            if config.detach {
+            if cfg.detach {
                 // Don't check the error of setsid because it fails if we're the
                 // process leader already. We just forked so it shouldn't return
                 // error, but ignore it anyway.
@@ -652,47 +632,47 @@ fn setgroups(ngroups: libc::c_int,
 }
 
 #[cfg(unix)]
-fn with_argv<T>(prog: &str, args: &[~str], cb: proc(**libc::c_char) -> T) -> T {
-    // 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: Vec<_> = tmps.iter().map(|tmp| tmp.with_ref(|buf| buf)).collect();
-
-    // Finally, make sure we add a null pointer.
+fn with_argv<T>(prog: &CString, args: &[CString], cb: proc(**libc::c_char) -> T) -> T {
+    let mut ptrs: Vec<*libc::c_char> = Vec::with_capacity(args.len()+1);
+
+    // Convert the CStrings into an array of pointers. Note: the
+    // lifetime of the various CStrings involved is guaranteed to be
+    // larger than the lifetime of our invocation of cb, but this is
+    // technically unsafe as the callback could leak these pointers
+    // out of our scope.
+    ptrs.push(prog.with_ref(|buf| buf));
+    ptrs.extend(args.iter().map(|tmp| tmp.with_ref(|buf| buf)));
+
+    // Add a terminating null pointer (required by libc).
     ptrs.push(ptr::null());
 
     cb(ptrs.as_ptr())
 }
 
 #[cfg(unix)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: proc(*c_void) -> T) -> T {
+fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: proc(*c_void) -> T) -> T {
     // 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.
+    // null-terminated array of "k=v\0" strings. Since we must create
+    // these strings locally, yet expose a raw pointer to them, we
+    // create a temporary vector to own the CStrings that outlives the
+    // call to cb.
     match env {
         Some(env) => {
             let mut tmps = Vec::with_capacity(env.len());
 
             for pair in env.iter() {
-                let kv = format!("{}={}", *pair.ref0(), *pair.ref1());
-                tmps.push(kv.to_c_str());
+                let mut kv = Vec::new();
+                kv.push_all(pair.ref0().as_bytes_no_nul());
+                kv.push('=' as u8);
+                kv.push_all(pair.ref1().as_bytes()); // includes terminal \0
+                tmps.push(kv);
             }
 
-            // Once again, this is unsafe.
-            let mut ptrs: Vec<*libc::c_char> = tmps.iter()
-                                                   .map(|tmp| tmp.with_ref(|buf| buf))
-                                                   .collect();
+            // As with `with_argv`, this is unsafe, since cb could leak the pointers.
+            let mut ptrs: Vec<*libc::c_char> =
+                tmps.iter()
+                    .map(|tmp| tmp.as_ptr() as *libc::c_char)
+                    .collect();
             ptrs.push(ptr::null());
 
             cb(ptrs.as_ptr() as *c_void)
@@ -702,7 +682,7 @@ fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: proc(*c_void) -> T) -> T {
 }
 
 #[cfg(windows)]
-fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: |*mut c_void| -> T) -> T {
+fn with_envp<T>(env: Option<&[(CString, CString)]>, cb: |*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.
@@ -711,7 +691,9 @@ fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: |*mut c_void| -> T) -> T {
             let mut blk = Vec::new();
 
             for pair in env.iter() {
-                let kv = format!("{}={}", *pair.ref0(), *pair.ref1());
+                let kv = format!("{}={}",
+                                 pair.ref0().as_str().unwrap(),
+                                 pair.ref1().as_str().unwrap());
                 blk.push_all(kv.to_utf16().as_slice());
                 blk.push(0);
             }
@@ -725,11 +707,12 @@ fn with_envp<T>(env: Option<~[(~str, ~str)]>, cb: |*mut c_void| -> T) -> T {
 }
 
 #[cfg(windows)]
-fn with_dirp<T>(d: Option<&Path>, cb: |*u16| -> T) -> T {
+fn with_dirp<T>(d: Option<&CString>, cb: |*u16| -> T) -> T {
     match d {
-      Some(dir) => match dir.as_str() {
-          Some(dir_str) => os::win32::as_utf16_p(dir_str, cb),
-          None => cb(ptr::null())
+      Some(dir) => {
+          let dir_str = dir.as_str()
+                           .expect("expected workingdirectory to be utf-8 encoded");
+          os::win32::as_utf16_p(dir_str, cb)
       },
       None => cb(ptr::null())
     }
@@ -1106,25 +1089,37 @@ mod tests {
 
     #[test] #[cfg(windows)]
     fn test_make_command_line() {
+        use std::str;
+        use std::c_str::CString;
         use super::make_command_line;
+
+        fn test_wrapper(prog: &str, args: &[&str]) -> ~str {
+            make_command_line(&prog.to_c_str(),
+                              args.iter()
+                                  .map(|a| a.to_c_str())
+                                  .collect::<Vec<CString>>()
+                                  .as_slice())
+        }
+
         assert_eq!(
-            make_command_line("prog", ["aaa".to_owned(), "bbb".to_owned(), "ccc".to_owned()]),
+            test_wrapper("prog", ["aaa", "bbb", "ccc"]),
             "prog aaa bbb ccc".to_owned()
         );
+
         assert_eq!(
-            make_command_line("C:\\Program Files\\blah\\blah.exe", ["aaa".to_owned()]),
+            test_wrapper("C:\\Program Files\\blah\\blah.exe", ["aaa"]),
             "\"C:\\Program Files\\blah\\blah.exe\" aaa".to_owned()
         );
         assert_eq!(
-            make_command_line("C:\\Program Files\\test", ["aa\"bb".to_owned()]),
+            test_wrapper("C:\\Program Files\\test", ["aa\"bb"]),
             "\"C:\\Program Files\\test\" aa\\\"bb".to_owned()
         );
         assert_eq!(
-            make_command_line("echo", ["a b c".to_owned()]),
+            test_wrapper("echo", ["a b c"]),
             "echo \"a b c\"".to_owned()
         );
         assert_eq!(
-            make_command_line("\u03c0\u042f\u97f3\u00e6\u221e", []),
+            test_wrapper("\u03c0\u042f\u97f3\u00e6\u221e", []),
             "\u03c0\u042f\u97f3\u00e6\u221e".to_owned()
         );
     }
index 9f66f767f20e70da9a86f7dc0fd8fd64d238c498..ecc48d5569c0e20a3a91f6be9a7c811893d9f67b 100644 (file)
@@ -120,7 +120,7 @@ fn default() -> BigUint { BigUint::new(Vec::new()) }
 
 impl fmt::Show for BigUint {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.to_str_radix(10))
+        write!(f, "{}", self.to_str_radix(10))
     }
 }
 
@@ -843,7 +843,7 @@ fn default() -> BigInt { BigInt::new(Zero, Vec::new()) }
 
 impl fmt::Show for BigInt {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.to_str_radix(10))
+        write!(f, "{}", self.to_str_radix(10))
     }
 }
 
index b82c4d177ba02e18a4dce036930f0f77b812ec75..3bc2408188da00b66dab362f53261a076960c6ea 100644 (file)
@@ -78,7 +78,7 @@ pub fn inv(&self) -> Complex<T> {
     }
 }
 
-impl<T: Clone + Float> Complex<T> {
+impl<T: Clone + FloatMath> Complex<T> {
     /// Calculate |self|
     #[inline]
     pub fn norm(&self) -> T {
@@ -86,7 +86,7 @@ pub fn norm(&self) -> T {
     }
 }
 
-impl<T: Clone + Float> Complex<T> {
+impl<T: Clone + FloatMath> Complex<T> {
     /// Calculate the principal Arg of self.
     #[inline]
     pub fn arg(&self) -> T {
@@ -171,9 +171,9 @@ fn one() -> Complex<T> {
 impl<T: fmt::Show + Num + Ord> fmt::Show for Complex<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.im < Zero::zero() {
-            write!(f.buf, "{}-{}i", self.re, -self.im)
+            write!(f, "{}-{}i", self.re, -self.im)
         } else {
-            write!(f.buf, "{}+{}i", self.re, self.im)
+            write!(f, "{}+{}i", self.re, self.im)
         }
     }
 }
index 20d694d0d09393316afdf647a25fffe76dff1417..85967d4d942be624d804a0325abe6629be16860a 100644 (file)
@@ -8,6 +8,40 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Simple numerics.
+//!
+//! This crate contains arbitrary-sized integer, rational, and complex types.
+//!
+//! ## Example
+//!
+//! This example uses the BigRational type and [Newton's method][newt] to
+//! approximate a square root to arbitrary precision:
+//!
+//! ```
+//! extern crate num;
+//!
+//! use num::bigint::BigInt;
+//! use num::rational::{Ratio, BigRational};
+//!
+//! fn approx_sqrt(number: u64, iterations: uint) -> BigRational {
+//!     let start: Ratio<BigInt> = Ratio::from_integer(FromPrimitive::from_u64(number).unwrap());
+//!     let mut approx = start.clone();
+//!
+//!     for _ in range(0, iterations) {
+//!         approx = (approx + (start / approx)) /
+//!             Ratio::from_integer(FromPrimitive::from_u64(2).unwrap());
+//!     }
+//!
+//!     approx
+//! }
+//!
+//! fn main() {
+//!     println!("{}", approx_sqrt(10, 4)); // prints 4057691201/1283082416
+//! }
+//! ```
+//!
+//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
+
 #![feature(macro_rules)]
 
 #![crate_id = "num#0.11.0-pre"]
index bffca79f351d4d0cc2fadb1ea912a2d4e8b48248..cd5c82acf6e9a17fb11f9395371123231a0b05a9 100644 (file)
@@ -276,7 +276,7 @@ impl<T: Clone + Integer + Ord>
 impl<T: fmt::Show> fmt::Show for Ratio<T> {
     /// Renders as `numer/denom`.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}/{}", self.numer, self.denom)
+        write!(f, "{}/{}", self.numer, self.denom)
     }
 }
 impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
index d1a01cc974f8b3afbe2a3d17dddebfe0cfa6b19f..a695da9fa163e6cc592c585672eaf0f605beffde 100644 (file)
@@ -37,7 +37,7 @@ pub struct Error {
 
 impl fmt::Show for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "Regex syntax error near position {}: {}",
+        write!(f, "Regex syntax error near position {}: {}",
                self.pos, self.msg)
     }
 }
index f22889b22a324b56cf27a5ec561ee109a781d0c7..899c54d601bdb1a9625e23e10db35fda4595e74f 100644 (file)
@@ -117,7 +117,7 @@ pub struct Regex {
 impl fmt::Show for Regex {
     /// Shows the original regular expression.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.original)
+        write!(f, "{}", self.original)
     }
 }
 
diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs
new file mode 100644 (file)
index 0000000..904fbe9
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2014 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.
+
+//! A bare-metal library supplying functions rustc may lower code to
+//!
+//! This library is not intended for general use, and is superseded by a system
+//! libc if one is available. In a freestanding context, however, common
+//! functions such as memset, memcpy, etc are not implemented. This library
+//! provides an implementation of these functions which are either required by
+//! libcore or called by rustc implicitly.
+//!
+//! This library is never included by default, and must be manually included if
+//! necessary. It is an error to include this library when also linking with
+//! the system libc library.
+
+#![crate_id = "rlibc#0.11.0-pre"]
+#![license = "MIT/ASL2"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+       html_root_url = "http://static.rust-lang.org/doc/master")]
+
+#![no_std]
+#![experimental]
+
+// This library is definining the builtin functions, so it would be a shame for
+// LLVM to optimize these function calls to themselves!
+#![no_builtins]
+
+#[cfg(test)] extern crate std;
+#[cfg(test)] extern crate native;
+
+// Require the offset intrinsics for LLVM to properly optimize the
+// implementations below. If pointer arithmetic is done through integers the
+// optimizations start to break down.
+extern "rust-intrinsic" {
+    fn offset<T>(dst: *T, offset: int) -> *T;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
+    let mut i = 0;
+    while i < n {
+        *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
+        i += 1;
+    }
+    return dest;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memmove(dest: *mut u8, src: *u8, n: uint) -> *mut u8 {
+    if src < dest as *u8 { // copy from end
+        let mut i = n;
+        while i != 0 {
+            i -= 1;
+            *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
+        }
+    } else { // copy from beginning
+        let mut i = 0;
+        while i < n {
+            *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int);
+            i += 1;
+        }
+    }
+    return dest;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: uint) -> *mut u8 {
+    let mut i = 0;
+    while i < n {
+        *(offset(s as *u8, i as int) as *mut u8) = c as u8;
+        i += 1;
+    }
+    return s;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn memcmp(s1: *u8, s2: *u8, n: uint) -> i32 {
+    let mut i = 0;
+    while i < n {
+        let a = *offset(s1, i as int);
+        let b = *offset(s2, i as int);
+        if a != b {
+            return (a - b) as i32
+        }
+        i += 1;
+    }
+    return 0;
+}
+
+#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
index 04ce4f88831f4d0cd823b8d1c924bf5f54a10c51..571959d812a45c5210d2b39c2d153c757cf1db39 100644 (file)
@@ -16,7 +16,7 @@
 use lib::llvm::{ArchiveRef, llvm};
 
 use libc;
-use std::io::process::{ProcessConfig, Process, ProcessOutput};
+use std::io::process::{Command, ProcessOutput};
 use std::io::{fs, TempDir};
 use std::io;
 use std::mem;
@@ -39,26 +39,24 @@ pub struct ArchiveRO {
 fn run_ar(sess: &Session, args: &str, cwd: Option<&Path>,
           paths: &[&Path]) -> ProcessOutput {
     let ar = get_ar_prog(sess);
+    let mut cmd = Command::new(ar.as_slice());
+
+    cmd.arg(args).args(paths);
+    debug!("{}", cmd);
 
-    let mut args = vec!(args.to_owned());
-    let paths = paths.iter().map(|p| p.as_str().unwrap().to_owned());
-    args.extend(paths);
-    debug!("{} {}", ar, args.connect(" "));
     match cwd {
-        Some(p) => { debug!("inside {}", p.display()); }
+        Some(p) => {
+            cmd.cwd(p);
+            debug!("inside {}", p.display());
+        }
         None => {}
     }
-    match Process::configure(ProcessConfig {
-        program: ar.as_slice(),
-        args: args.as_slice(),
-        cwd: cwd.map(|a| &*a),
-        .. ProcessConfig::new()
-    }) {
+
+    match cmd.spawn() {
         Ok(prog) => {
             let o = prog.wait_with_output().unwrap();
             if !o.status.success() {
-                sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
-                                 o.status));
+                sess.err(format!("{} failed with: {}", cmd, o.status));
                 sess.note(format!("stdout ---\n{}",
                                   str::from_utf8(o.output.as_slice()).unwrap()));
                 sess.note(format!("stderr ---\n{}",
@@ -68,7 +66,7 @@ fn run_ar(sess: &Session, args: &str, cwd: Option<&Path>,
             o
         },
         Err(e) => {
-            sess.err(format!("could not exec `{}`: {}", ar, e));
+            sess.err(format!("could not exec `{}`: {}", ar.as_slice(), e));
             sess.abort_if_errors();
             fail!("rustc::back::archive::run_ar() should not reach this point");
         }
index de6b5925edbdec8c647a48c6ff74a5747c3e886b..429a8f5be5eb5f54604b862465c7e1fe82e952d1 100644 (file)
@@ -29,7 +29,7 @@
 
 use std::c_str::{ToCStr, CString};
 use std::char;
-use std::io::{fs, TempDir, Process};
+use std::io::{fs, TempDir, Command};
 use std::io;
 use std::ptr;
 use std::str;
@@ -103,7 +103,7 @@ pub mod write {
     use syntax::abi;
 
     use std::c_str::ToCStr;
-    use std::io::Process;
+    use std::io::{Command};
     use libc::{c_uint, c_int};
     use std::str;
 
@@ -212,7 +212,8 @@ pub fn run_passes(sess: &Session,
             if !sess.opts.cg.no_prepopulate_passes {
                 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
                 llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
-                populate_llvm_passes(fpm, mpm, llmod, opt_level);
+                populate_llvm_passes(fpm, mpm, llmod, opt_level,
+                                     trans.no_builtins);
             }
 
             for pass in sess.opts.cg.passes.iter() {
@@ -264,11 +265,11 @@ pub fn run_passes(sess: &Session,
             // escape the closure itself, and the manager should only be
             // used once.
             fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
-                            f: |PassManagerRef|) {
+                            no_builtins: bool, f: |PassManagerRef|) {
                 unsafe {
                     let cpm = llvm::LLVMCreatePassManager();
                     llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
-                    llvm::LLVMRustAddLibraryInfo(cpm, llmod);
+                    llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
                     f(cpm);
                     llvm::LLVMDisposePassManager(cpm);
                 }
@@ -286,7 +287,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                     }
                     OutputTypeLlvmAssembly => {
                         path.with_c_str(|output| {
-                            with_codegen(tm, llmod, |cpm| {
+                            with_codegen(tm, llmod, trans.no_builtins, |cpm| {
                                 llvm::LLVMRustPrintModule(cpm, llmod, output);
                             })
                         })
@@ -303,7 +304,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                             needs_metadata = true;
                             output.temp_path(OutputTypeAssembly)
                         };
-                        with_codegen(tm, llmod, |cpm| {
+                        with_codegen(tm, llmod, trans.no_builtins, |cpm| {
                             WriteOutputFile(sess, tm, cpm, llmod, &path,
                                             lib::llvm::AssemblyFile);
                         });
@@ -321,7 +322,7 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
             time(sess.time_passes(), "codegen passes", (), |()| {
                 match object_file {
                     Some(ref path) => {
-                        with_codegen(tm, llmod, |cpm| {
+                        with_codegen(tm, llmod, trans.no_builtins, |cpm| {
                             WriteOutputFile(sess, tm, cpm, llmod, path,
                                             lib::llvm::ObjectFile);
                         });
@@ -329,7 +330,8 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
                     None => {}
                 }
                 if needs_metadata {
-                    with_codegen(tm, trans.metadata_module, |cpm| {
+                    with_codegen(tm, trans.metadata_module,
+                                 trans.no_builtins, |cpm| {
                         let out = output.temp_path(OutputTypeObject)
                                         .with_extension("metadata.o");
                         WriteOutputFile(sess, tm, cpm,
@@ -348,22 +350,18 @@ fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef,
     }
 
     pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
-        let cc = super::get_cc_prog(sess);
-        let assembly = outputs.temp_path(OutputTypeAssembly);
-        let object = outputs.path(OutputTypeObject);
-
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        let args = [
-            "-c".to_owned(),
-            "-o".to_owned(), object.as_str().unwrap().to_owned(),
-            assembly.as_str().unwrap().to_owned()];
-
-        debug!("{} '{}'", cc, args.connect("' '"));
-        match Process::output(cc.as_slice(), args) {
+        let pname = super::get_cc_prog(sess);
+        let mut cmd = Command::new(pname.as_slice());
+
+        cmd.arg("-c").arg("-o").arg(outputs.path(OutputTypeObject))
+                               .arg(outputs.temp_path(OutputTypeAssembly));
+        debug!("{}", &cmd);
+
+        match cmd.output() {
             Ok(prog) => {
                 if !prog.status.success() {
-                    sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
-                    sess.note(format!("{} arguments: '{}'", cc, args.connect("' '")));
+                    sess.err(format!("linking with `{}` failed: {}", pname, prog.status));
+                    sess.note(format!("{}", &cmd));
                     let mut note = prog.error.clone();
                     note.push_all(prog.output.as_slice());
                     sess.note(str::from_utf8(note.as_slice()).unwrap().to_owned());
@@ -371,7 +369,7 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
                 }
             },
             Err(e) => {
-                sess.err(format!("could not exec the linker `{}`: {}", cc, e));
+                sess.err(format!("could not exec the linker `{}`: {}", pname, e));
                 sess.abort_if_errors();
             }
         }
@@ -441,7 +439,8 @@ unsafe fn configure_llvm(sess: &Session) {
     unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
                                    mpm: lib::llvm::PassManagerRef,
                                    llmod: ModuleRef,
-                                   opt: lib::llvm::CodeGenOptLevel) {
+                                   opt: lib::llvm::CodeGenOptLevel,
+                                   no_builtins: bool) {
         // Create the PassManagerBuilder for LLVM. We configure it with
         // reasonable defaults and prepare it to actually populate the pass
         // manager.
@@ -465,7 +464,7 @@ unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
             }
         }
         llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
-        llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod);
+        llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
 
         // Use the builder to populate the function/module pass managers.
         llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
@@ -527,6 +526,7 @@ unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
  *    system linkers understand.
  */
 
+// FIXME (#9639): This needs to handle non-utf8 `out_filestem` values
 pub fn find_crate_id(attrs: &[ast::Attribute], out_filestem: &str) -> CrateId {
     match attr::find_crateid(attrs) {
         None => from_str(out_filestem).unwrap_or_else(|| {
@@ -547,6 +547,7 @@ pub fn crate_id_hash(crate_id: &CrateId) -> StrBuf {
     truncated_hash_result(&mut s).as_slice().slice_to(8).to_strbuf()
 }
 
+// FIXME (#9639): This needs to handle non-utf8 `out_filestem` values
 pub fn build_link_meta(krate: &ast::Crate, out_filestem: &str) -> LinkMeta {
     let r = LinkMeta {
         crateid: find_crate_id(krate.attrs.as_slice(), out_filestem),
@@ -1026,31 +1027,30 @@ fn link_staticlib(sess: &Session, obj_filename: &Path, out_filename: &Path) {
 fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
                  obj_filename: &Path, out_filename: &Path) {
     let tmpdir = TempDir::new("rustc").expect("needs a temp dir");
+
     // The invocations of cc share some flags across platforms
-    let cc_prog = get_cc_prog(sess);
-    let mut cc_args = sess.targ_cfg.target_strs.cc_args.clone();
-    cc_args.push_all_move(link_args(sess, dylib, tmpdir.path(), trans,
-                                    obj_filename, out_filename));
+    let pname = get_cc_prog(sess);
+    let mut cmd = Command::new(pname.as_slice());
+
+    cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice());
+    link_args(&mut cmd, sess, dylib, tmpdir.path(),
+              trans, obj_filename, out_filename);
+
     if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 {
-        println!("{} link args: '{}'", cc_prog, cc_args.connect("' '"));
+        println!("{}", &cmd);
     }
 
     // May have not found libraries in the right formats.
     sess.abort_if_errors();
 
     // Invoke the system linker
-    debug!("{} {}", cc_prog, cc_args.connect(" "));
-    let prog = time(sess.time_passes(), "running linker", (), |()|
-                    Process::output(cc_prog.as_slice(),
-                                    cc_args.iter()
-                                           .map(|x| (*x).to_owned())
-                                           .collect::<Vec<_>>()
-                                           .as_slice()));
+    debug!("{}", &cmd);
+    let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output());
     match prog {
         Ok(prog) => {
             if !prog.status.success() {
-                sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
-                sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '")));
+                sess.err(format!("linking with `{}` failed: {}", pname, prog.status));
+                sess.note(format!("{}", &cmd));
                 let mut output = prog.error.clone();
                 output.push_all(prog.output.as_slice());
                 sess.note(str::from_utf8(output.as_slice()).unwrap().to_owned());
@@ -1058,7 +1058,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
             }
         },
         Err(e) => {
-            sess.err(format!("could not exec the linker `{}`: {}", cc_prog, e));
+            sess.err(format!("could not exec the linker `{}`: {}", pname, e));
             sess.abort_if_errors();
         }
     }
@@ -1067,9 +1067,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
     // On OSX, debuggers need this utility to get run to do some munging of
     // the symbols
     if sess.targ_cfg.os == abi::OsMacos && (sess.opts.debuginfo != NoDebugInfo) {
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        match Process::status("dsymutil",
-                                  [out_filename.as_str().unwrap().to_owned()]) {
+        match Command::new("dsymutil").arg(out_filename).status() {
             Ok(..) => {}
             Err(e) => {
                 sess.err(format!("failed to run dsymutil: {}", e));
@@ -1079,25 +1077,20 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
     }
 }
 
-fn link_args(sess: &Session,
+fn link_args(cmd: &mut Command,
+             sess: &Session,
              dylib: bool,
              tmpdir: &Path,
              trans: &CrateTranslation,
              obj_filename: &Path,
-             out_filename: &Path) -> Vec<StrBuf> {
+             out_filename: &Path) {
 
     // The default library location, we need this to find the runtime.
     // The location of crates will be determined as needed.
-    // FIXME (#9639): This needs to handle non-utf8 paths
     let lib_path = sess.target_filesearch().get_lib_path();
-    let stage = ("-L".to_owned() + lib_path.as_str().unwrap()).to_strbuf();
+    cmd.arg("-L").arg(lib_path);
 
-    let mut args = vec!(stage);
-
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    args.push_all([
-        "-o".to_strbuf(), out_filename.as_str().unwrap().to_strbuf(),
-        obj_filename.as_str().unwrap().to_strbuf()]);
+    cmd.arg("-o").arg(out_filename).arg(obj_filename);
 
     // Stack growth requires statically linking a __morestack function. Note
     // that this is listed *before* all other libraries, even though it may be
@@ -1114,14 +1107,13 @@ fn link_args(sess: &Session,
     // line, but inserting this farther to the left makes the
     // "rust_stack_exhausted" symbol an outstanding undefined symbol, which
     // flags libstd as a required library (or whatever provides the symbol).
-    args.push("-lmorestack".to_strbuf());
+    cmd.arg("-lmorestack");
 
     // When linking a dynamic library, we put the metadata into a section of the
     // executable. This metadata is in a separate object file from the main
     // object file, so we link that in here.
     if dylib {
-        let metadata = obj_filename.with_extension("metadata.o");
-        args.push(metadata.as_str().unwrap().to_strbuf());
+        cmd.arg(obj_filename.with_extension("metadata.o"));
     }
 
     // We want to prevent the compiler from accidentally leaking in any system
@@ -1132,7 +1124,7 @@ fn link_args(sess: &Session,
     //
     // FIXME(#11937) we should invoke the system linker directly
     if sess.targ_cfg.os != abi::OsWin32 {
-        args.push("-nodefaultlibs".to_strbuf());
+        cmd.arg("-nodefaultlibs");
     }
 
     // If we're building a dylib, we don't use --gc-sections because LLVM has
@@ -1140,20 +1132,20 @@ fn link_args(sess: &Session,
     // metadata. If we're building an executable, however, --gc-sections drops
     // the size of hello world from 1.8MB to 597K, a 67% reduction.
     if !dylib && sess.targ_cfg.os != abi::OsMacos {
-        args.push("-Wl,--gc-sections".to_strbuf());
+        cmd.arg("-Wl,--gc-sections");
     }
 
     if sess.targ_cfg.os == abi::OsLinux {
         // GNU-style linkers will use this to omit linking to libraries which
         // don't actually fulfill any relocations, but only for libraries which
         // follow this flag. Thus, use it before specifying libraries to link to.
-        args.push("-Wl,--as-needed".to_strbuf());
+        cmd.arg("-Wl,--as-needed");
 
         // GNU-style linkers support optimization with -O. GNU ld doesn't need a
         // numeric argument, but other linkers do.
         if sess.opts.optimize == config::Default ||
            sess.opts.optimize == config::Aggressive {
-            args.push("-Wl,-O1".to_strbuf());
+            cmd.arg("-Wl,-O1");
         }
     } else if sess.targ_cfg.os == abi::OsMacos {
         // The dead_strip option to the linker specifies that functions and data
@@ -1166,14 +1158,14 @@ fn link_args(sess: &Session,
         // won't get much benefit from dylibs because LLVM will have already
         // stripped away as much as it could. This has not been seen to impact
         // link times negatively.
-        args.push("-Wl,-dead_strip".to_strbuf());
+        cmd.arg("-Wl,-dead_strip");
     }
 
     if sess.targ_cfg.os == abi::OsWin32 {
         // Make sure that we link to the dynamic libgcc, otherwise cross-module
         // DWARF stack unwinding will not work.
         // This behavior may be overridden by --link-args "-static-libgcc"
-        args.push("-shared-libgcc".to_strbuf());
+        cmd.arg("-shared-libgcc");
 
         // And here, we see obscure linker flags #45. On windows, it has been
         // found to be necessary to have this flag to compile liblibc.
@@ -1200,13 +1192,13 @@ fn link_args(sess: &Session,
         //
         // [1] - https://sourceware.org/bugzilla/show_bug.cgi?id=13130
         // [2] - https://code.google.com/p/go/issues/detail?id=2139
-        args.push("-Wl,--enable-long-section-names".to_strbuf());
+        cmd.arg("-Wl,--enable-long-section-names");
     }
 
     if sess.targ_cfg.os == abi::OsAndroid {
         // Many of the symbols defined in compiler-rt are also defined in libgcc.
         // Android linker doesn't like that by default.
-        args.push("-Wl,--allow-multiple-definition".to_strbuf());
+        cmd.arg("-Wl,--allow-multiple-definition");
     }
 
     // Take careful note of the ordering of the arguments we pass to the linker
@@ -1242,39 +1234,38 @@ fn link_args(sess: &Session,
     // this kind of behavior is pretty platform specific and generally not
     // recommended anyway, so I don't think we're shooting ourself in the foot
     // much with that.
-    add_upstream_rust_crates(&mut args, sess, dylib, tmpdir, trans);
-    add_local_native_libraries(&mut args, sess);
-    add_upstream_native_libraries(&mut args, sess);
+    add_upstream_rust_crates(cmd, sess, dylib, tmpdir, trans);
+    add_local_native_libraries(cmd, sess);
+    add_upstream_native_libraries(cmd, sess);
 
     // # Telling the linker what we're doing
 
     if dylib {
         // On mac we need to tell the linker to let this library be rpathed
         if sess.targ_cfg.os == abi::OsMacos {
-            args.push("-dynamiclib".to_strbuf());
-            args.push("-Wl,-dylib".to_strbuf());
-            // FIXME (#9639): This needs to handle non-utf8 paths
+            cmd.args(["-dynamiclib", "-Wl,-dylib"]);
+
             if !sess.opts.cg.no_rpath {
-                args.push(format_strbuf!("-Wl,-install_name,@rpath/{}",
-                                         out_filename.filename_str()
-                                                     .unwrap()));
+                let mut v = Vec::from_slice("-Wl,-install_name,@rpath/".as_bytes());
+                v.push_all(out_filename.filename().unwrap());
+                cmd.arg(v.as_slice());
             }
         } else {
-            args.push("-shared".to_strbuf())
+            cmd.arg("-shared");
         }
     }
 
     if sess.targ_cfg.os == abi::OsFreebsd {
-        args.push_all(["-L/usr/local/lib".to_strbuf(),
-                       "-L/usr/local/lib/gcc46".to_strbuf(),
-                       "-L/usr/local/lib/gcc44".to_strbuf()]);
+        cmd.args(["-L/usr/local/lib",
+                  "-L/usr/local/lib/gcc46",
+                  "-L/usr/local/lib/gcc44"]);
     }
 
     // FIXME (#2397): At some point we want to rpath our guesses as to
     // where extern libraries might live, based on the
     // addl_lib_search_paths
     if !sess.opts.cg.no_rpath {
-        args.push_all(rpath::get_rpath_flags(sess, out_filename).as_slice());
+        cmd.args(rpath::get_rpath_flags(sess, out_filename).as_slice());
     }
 
     // compiler-rt contains implementations of low-level LLVM helpers. This is
@@ -1284,15 +1275,14 @@ fn link_args(sess: &Session,
     //
     // This is the end of the command line, so this library is used to resolve
     // *all* undefined symbols in all other libraries, and this is intentional.
-    args.push("-lcompiler-rt".to_strbuf());
+    cmd.arg("-lcompiler-rt");
 
     // Finally add all the linker arguments provided on the command line along
     // with any #[link_args] attributes found inside the crate
-    args.push_all(sess.opts.cg.link_args.as_slice());
+    cmd.args(sess.opts.cg.link_args.as_slice());
     for arg in sess.cstore.get_used_link_args().borrow().iter() {
-        args.push(arg.clone());
+        cmd.arg(arg.as_slice());
     }
-    return args;
 }
 
 // # Native library linking
@@ -1306,16 +1296,14 @@ fn link_args(sess: &Session,
 // Also note that the native libraries linked here are only the ones located
 // in the current crate. Upstream crates with native library dependencies
 // may have their native library pulled in above.
-fn add_local_native_libraries(args: &mut Vec<StrBuf>, sess: &Session) {
+fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
     for path in sess.opts.addl_lib_search_paths.borrow().iter() {
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        args.push(("-L" + path.as_str().unwrap().to_owned()).to_strbuf());
+        cmd.arg("-L").arg(path);
     }
 
     let rustpath = filesearch::rust_path();
     for path in rustpath.iter() {
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        args.push(("-L" + path.as_str().unwrap().to_owned()).to_strbuf());
+        cmd.arg("-L").arg(path);
     }
 
     // Some platforms take hints about whether a library is static or dynamic.
@@ -1329,21 +1317,21 @@ fn add_local_native_libraries(args: &mut Vec<StrBuf>, sess: &Session) {
             cstore::NativeUnknown | cstore::NativeStatic => {
                 if takes_hints {
                     if kind == cstore::NativeStatic {
-                        args.push("-Wl,-Bstatic".to_strbuf());
+                        cmd.arg("-Wl,-Bstatic");
                     } else {
-                        args.push("-Wl,-Bdynamic".to_strbuf());
+                        cmd.arg("-Wl,-Bdynamic");
                     }
                 }
-                args.push(format_strbuf!("-l{}", *l));
+                cmd.arg(format_strbuf!("-l{}", *l));
             }
             cstore::NativeFramework => {
-                args.push("-framework".to_strbuf());
-                args.push(l.to_strbuf());
+                cmd.arg("-framework");
+                cmd.arg(l.as_slice());
             }
         }
     }
     if takes_hints {
-        args.push("-Wl,-Bdynamic".to_strbuf());
+        cmd.arg("-Wl,-Bdynamic");
     }
 }
 
@@ -1352,7 +1340,7 @@ fn add_local_native_libraries(args: &mut Vec<StrBuf>, sess: &Session) {
 // Rust crates are not considered at all when creating an rlib output. All
 // dependencies will be linked when producing the final output (instead of
 // the intermediate rlib version)
-fn add_upstream_rust_crates(args: &mut Vec<StrBuf>, sess: &Session,
+fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
                             dylib: bool, tmpdir: &Path,
                             trans: &CrateTranslation) {
     // All of the heavy lifting has previously been accomplished by the
@@ -1384,26 +1372,26 @@ fn add_upstream_rust_crates(args: &mut Vec<StrBuf>, sess: &Session,
         let src = sess.cstore.get_used_crate_source(cnum).unwrap();
         match kind {
             cstore::RequireDynamic => {
-                add_dynamic_crate(args, sess, src.dylib.unwrap())
+                add_dynamic_crate(cmd, sess, src.dylib.unwrap())
             }
             cstore::RequireStatic => {
-                add_static_crate(args, sess, tmpdir, cnum, src.rlib.unwrap())
+                add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap())
             }
         }
 
     }
 
     // Converts a library file-stem into a cc -l argument
-    fn unlib(config: &config::Config, stem: &str) -> StrBuf {
-        if stem.starts_with("lib") && config.os != abi::OsWin32 {
-            stem.slice(3, stem.len()).to_strbuf()
+    fn unlib<'a>(config: &config::Config, stem: &'a [u8]) -> &'a [u8] {
+        if stem.starts_with("lib".as_bytes()) && config.os != abi::OsWin32 {
+            stem.tailn(3)
         } else {
-            stem.to_strbuf()
+            stem
         }
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
-    fn add_static_crate(args: &mut Vec<StrBuf>, sess: &Session, tmpdir: &Path,
+    fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
                         cnum: ast::CrateNum, cratepath: Path) {
         // When performing LTO on an executable output, all of the
         // bytecode from the upstream libraries has already been
@@ -1434,34 +1422,32 @@ fn add_static_crate(args: &mut Vec<StrBuf>, sess: &Session, tmpdir: &Path,
                         sess.abort_if_errors();
                     }
                 }
-                let dst_str = dst.as_str().unwrap().to_strbuf();
-                let mut archive = Archive::open(sess, dst);
+                let mut archive = Archive::open(sess, dst.clone());
                 archive.remove_file(format!("{}.o", name));
                 let files = archive.files();
                 if files.iter().any(|s| s.as_slice().ends_with(".o")) {
-                    args.push(dst_str);
+                    cmd.arg(dst);
                 }
             });
         } else {
-            args.push(cratepath.as_str().unwrap().to_strbuf());
+            cmd.arg(cratepath);
         }
     }
 
     // Same thing as above, but for dynamic crates instead of static crates.
-    fn add_dynamic_crate(args: &mut Vec<StrBuf>, sess: &Session,
-                         cratepath: Path) {
+    fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: Path) {
         // If we're performing LTO, then it should have been previously required
         // that all upstream rust dependencies were available in an rlib format.
         assert!(!sess.lto());
 
         // Just need to tell the linker about where the library lives and
         // what its name is
-        let dir = cratepath.dirname_str().unwrap();
-        if !dir.is_empty() {
-            args.push(format_strbuf!("-L{}", dir));
-        }
-        let libarg = unlib(&sess.targ_cfg, cratepath.filestem_str().unwrap());
-        args.push(format_strbuf!("-l{}", libarg));
+        let dir = cratepath.dirname();
+        if !dir.is_empty() { cmd.arg("-L").arg(dir); }
+
+        let mut v = Vec::from_slice("-l".as_bytes());
+        v.push_all(unlib(&sess.targ_cfg, cratepath.filestem().unwrap()));
+        cmd.arg(v.as_slice());
     }
 }
 
@@ -1470,12 +1456,12 @@ fn add_dynamic_crate(args: &mut Vec<StrBuf>, sess: &Session,
 // dependencies. We've got two cases then:
 //
 // 1. The upstream crate is an rlib. In this case we *must* link in the
-//    native dependency because the rlib is just an archive.
+// native dependency because the rlib is just an archive.
 //
 // 2. The upstream crate is a dylib. In order to use the dylib, we have to
-//    have the dependency present on the system somewhere. Thus, we don't
-//    gain a whole lot from not linking in the dynamic dependency to this
-//    crate as well.
+// have the dependency present on the system somewhere. Thus, we don't
+// gain a whole lot from not linking in the dynamic dependency to this
+// crate as well.
 //
 // The use case for this is a little subtle. In theory the native
 // dependencies of a crate are purely an implementation detail of the crate
@@ -1483,7 +1469,7 @@ fn add_dynamic_crate(args: &mut Vec<StrBuf>, sess: &Session,
 // generic function calls a native function, then the generic function must
 // be instantiated in the target crate, meaning that the native symbol must
 // also be resolved in the target crate.
-fn add_upstream_native_libraries(args: &mut Vec<StrBuf>, sess: &Session) {
+fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) {
     // Be sure to use a topological sorting of crates because there may be
     // interdependencies between native libraries. When passing -nodefaultlibs,
     // for example, almost all native libraries depend on libc, so we have to
@@ -1499,11 +1485,11 @@ fn add_upstream_native_libraries(args: &mut Vec<StrBuf>, sess: &Session) {
         for &(kind, ref lib) in libs.iter() {
             match kind {
                 cstore::NativeUnknown => {
-                    args.push(format_strbuf!("-l{}", *lib))
+                    cmd.arg(format_strbuf!("-l{}", *lib));
                 }
                 cstore::NativeFramework => {
-                    args.push("-framework".to_strbuf());
-                    args.push(lib.to_strbuf());
+                    cmd.arg("-framework");
+                    cmd.arg(lib.as_slice());
                 }
                 cstore::NativeStatic => {
                     sess.bug("statics shouldn't be propagated");
index b60468e85bbf16fc5d569f496638c82a992a45d4..02f937af90d2d3a55a6667cf8fee6aabf99b78ca 100644 (file)
@@ -27,6 +27,7 @@
 use syntax::ast::{IntTy, UintTy};
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
+use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
 use syntax::parse;
 use syntax::parse::token::InternedString;
 
@@ -92,6 +93,7 @@ pub struct Options {
     /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
     pub print_metas: (bool, bool, bool),
     pub cg: CodegenOptions,
+    pub color: ColorConfig,
 }
 
 /// Some reasonable defaults
@@ -115,6 +117,7 @@ pub fn basic_options() -> Options {
         write_dependency_info: (false, None),
         print_metas: (false, false, false),
         cg: basic_codegen_options(),
+        color: Auto,
     }
 }
 
@@ -316,7 +319,7 @@ pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
 {
     let mut cg = basic_codegen_options();
     for option in matches.opt_strs("C").move_iter() {
-        let mut iter = option.splitn('=', 1);
+        let mut iter = option.as_slice().splitn('=', 1);
         let key = iter.next().unwrap();
         let value = iter.next();
         let option_to_lookup = key.replace("-", "_");
@@ -516,12 +519,13 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
         optopt( "",  "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
         optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
         optflagopt("", "pretty",
-                 "Pretty-print the input instead of compiling;
-                  valid types are: normal (un-annotated source),
-                  expanded (crates expanded),
-                  typed (crates expanded, with type annotations),
-                  or identified (fully parenthesized,
-                  AST nodes and blocks with IDs)", "TYPE"),
+                   "Pretty-print the input instead of compiling;
+                   valid types are: `normal` (un-annotated source),
+                   `expanded` (crates expanded),
+                   `typed` (crates expanded, with type annotations),
+                   `expanded,identified` (fully parenthesized, AST nodes with IDs), or
+                   `flowgraph=<nodeid>` (graphviz formatted flowgraph for node)",
+                 "TYPE"),
         optflagopt("", "dep-info",
                  "Output dependency info to <filename> after compiling, \
                   in a format suitable for use by Makefiles", "FILENAME"),
@@ -536,7 +540,11 @@ pub fn optgroups() -> Vec<getopts::OptGroup> {
         optmulti("F", "forbid", "Set lint forbidden", "OPT"),
         optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
         optmulti("Z", "", "Set internal debugging options", "FLAG"),
-        optflag( "v", "version", "Print version info and exit")
+        optflag("v", "version", "Print version info and exit"),
+        optopt("", "color", "Configure coloring of output:
+            auto   = colorize, if output goes to a tty (default);
+            always = always colorize output;
+            never  = never colorize output", "auto|always|never")
     )
 }
 
@@ -555,7 +563,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let mut crate_types: Vec<CrateType> = Vec::new();
     let unparsed_crate_types = matches.opt_strs("crate-type");
     for unparsed_crate_type in unparsed_crate_types.iter() {
-        for part in unparsed_crate_type.split(',') {
+        for part in unparsed_crate_type.as_slice().split(',') {
             let new_part = match part {
                 "lib"       => default_lib_output(),
                 "rlib"      => CrateTypeRlib,
@@ -604,7 +612,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         let mut this_bit = 0;
         for tuple in debug_map.iter() {
             let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
-            if *name == *debug_flag { this_bit = bit; break; }
+            if *name == debug_flag.as_slice() {
+                this_bit = bit;
+                break;
+            }
         }
         if this_bit == 0 {
             early_error(format!("unknown debug flag: {}", *debug_flag))
@@ -620,7 +631,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     if !parse_only && !no_trans {
         let unparsed_output_types = matches.opt_strs("emit");
         for unparsed_output_type in unparsed_output_types.iter() {
-            for part in unparsed_output_type.split(',') {
+            for part in unparsed_output_type.as_slice().split(',') {
                 let output_type = match part.as_slice() {
                     "asm"  => link::OutputTypeAssembly,
                     "ir"   => link::OutputTypeLlvmAssembly,
@@ -707,6 +718,18 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
                        matches.opt_present("crate-file-name"));
     let cg = build_codegen_options(matches);
 
+    let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
+        Some("auto")   => Auto,
+        Some("always") => Always,
+        Some("never")  => Never,
+
+        None => Auto,
+
+        Some(arg) => early_error(format!(
+            "argument for --color must be auto, always or never (instead was `{}`)",
+            arg))
+    };
+
     Options {
         crate_types: crate_types,
         gc: gc,
@@ -726,6 +749,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         write_dependency_info: write_dependency_info,
         print_metas: print_metas,
         cg: cg,
+        color: color
     }
 }
 
@@ -744,7 +768,7 @@ mod test {
     #[test]
     fn test_switch_implies_cfg_test() {
         let matches =
-            &match getopts(["--test".to_owned()], optgroups().as_slice()) {
+            &match getopts(["--test".to_strbuf()], optgroups().as_slice()) {
               Ok(m) => m,
               Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
             };
@@ -759,7 +783,7 @@ fn test_switch_implies_cfg_test() {
     #[test]
     fn test_switch_implies_cfg_test_unless_cfg_test() {
         let matches =
-            &match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
+            &match getopts(["--test".to_strbuf(), "--cfg=test".to_strbuf()],
                            optgroups().as_slice()) {
               Ok(m) => m,
               Err(f) => {
index 51bdf9ef9edd58304359792ad6991d21a5964bcc..5f9fd7124a9e92289804ed8e3da117b5c3fed88d 100644 (file)
 
 use back::link;
 use driver::session::Session;
-use driver::config;
+use driver::{config, PpMode};
+use driver::PpmFlowGraph; // FIXME (#14221).
 use front;
 use lib::llvm::{ContextRef, ModuleRef};
 use metadata::common::LinkMeta;
 use metadata::creader;
 use metadata::creader::Loader;
+use middle::cfg;
+use middle::cfg::graphviz::LabelledCFG;
 use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
 use middle::dependency_format;
 use middle;
@@ -24,6 +27,8 @@
 use util::ppaux;
 use util::nodemap::{NodeSet};
 
+use dot = graphviz;
+
 use serialize::{json, Encodable};
 
 use std::io;
@@ -356,6 +361,7 @@ pub struct CrateTranslation {
     pub metadata: Vec<u8>,
     pub reachable: Vec<StrBuf>,
     pub crate_formats: dependency_format::Dependencies,
+    pub no_builtins: bool,
 }
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
@@ -581,14 +587,14 @@ fn post(&self,
 pub fn pretty_print_input(sess: Session,
                           cfg: ast::CrateConfig,
                           input: &Input,
-                          ppm: ::driver::PpMode,
+                          ppm: PpMode,
                           ofile: Option<Path>) {
     let krate = phase_1_parse_input(&sess, cfg, input);
     let id = link::find_crate_id(krate.attrs.as_slice(),
                                  input.filestem().as_slice());
 
     let (krate, ast_map, is_expanded) = match ppm {
-        PpmExpanded | PpmExpandedIdentified | PpmTyped => {
+        PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => {
             let loader = &mut Loader::new(&sess);
             let (krate, ast_map) = phase_2_configure_and_expand(&sess,
                                                                 loader,
@@ -643,6 +649,18 @@ pub fn pretty_print_input(sess: Session,
                                 &annotation,
                                 is_expanded)
         }
+        PpmFlowGraph(nodeid) => {
+            let ast_map = ast_map.expect("--pretty flowgraph missing ast_map");
+            let node = ast_map.find(nodeid).unwrap_or_else(|| {
+                fail!("--pretty flowgraph=id couldn't find id: {}", id)
+            });
+            let block = match node {
+                syntax::ast_map::NodeBlock(block) => block,
+                _ => fail!("--pretty=flowgraph needs block, got {:?}", node)
+            };
+            let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
+            print_flowgraph(analysis, block, out)
+        }
         _ => {
             pprust::print_crate(sess.codemap(),
                                 sess.diagnostic(),
@@ -657,6 +675,32 @@ pub fn pretty_print_input(sess: Session,
 
 }
 
+fn print_flowgraph<W:io::Writer>(analysis: CrateAnalysis,
+                                 block: ast::P<ast::Block>,
+                                 mut out: W) -> io::IoResult<()> {
+    let ty_cx = &analysis.ty_cx;
+    let cfg = cfg::CFG::new(ty_cx, block);
+    let lcfg = LabelledCFG { ast_map: &ty_cx.map,
+                             cfg: &cfg,
+                             name: format!("block{}", block.id).to_strbuf(), };
+    debug!("cfg: {:?}", cfg);
+    let r = dot::render(&lcfg, &mut out);
+    return expand_err_details(r);
+
+    fn expand_err_details(r: io::IoResult<()>) -> io::IoResult<()> {
+        r.map_err(|ioerr| {
+            let orig_detail = ioerr.detail.clone();
+            let m = "graphviz::render failed";
+            io::IoError {
+                detail: Some(match orig_detail {
+                    None => m.into_owned(), Some(d) => format!("{}: {}", m, d)
+                }),
+                ..ioerr
+            }
+        })
+    }
+}
+
 pub fn collect_crate_types(session: &Session,
                            attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
     // If we're generating a test executable, then ignore all other output
index b92075444234bd17c4b926841e691288fa115b97..c4c145f5bd66d7adaee9184e4282ba046b1122a4 100644 (file)
@@ -35,7 +35,7 @@
 pub mod config;
 
 
-pub fn main_args(args: &[~str]) -> int {
+pub fn main_args(args: &[StrBuf]) -> int {
     let owned_args = args.to_owned();
     monitor(proc() run_compiler(owned_args));
     0
@@ -44,7 +44,7 @@ pub fn main_args(args: &[~str]) -> int {
 static BUG_REPORT_URL: &'static str =
     "http://static.rust-lang.org/doc/master/complement-bugreport.html";
 
-fn run_compiler(args: &[~str]) {
+fn run_compiler(args: &[StrBuf]) {
     let matches = match handle_options(Vec::from_slice(args)) {
         Some(matches) => matches,
         None => return
@@ -73,7 +73,7 @@ fn run_compiler(args: &[~str]) {
     let ofile = matches.opt_str("o").map(|o| Path::new(o));
 
     let pretty = matches.opt_default("pretty", "normal").map(|a| {
-        parse_pretty(&sess, a)
+        parse_pretty(&sess, a.as_slice())
     });
     match pretty {
         Some::<PpMode>(ppm) => {
@@ -84,7 +84,7 @@ fn run_compiler(args: &[~str]) {
     }
 
     let r = matches.opt_strs("Z");
-    if r.contains(&("ls".to_owned())) {
+    if r.contains(&("ls".to_strbuf())) {
         match input {
             FileInput(ref ifile) => {
                 let mut stdout = io::stdout();
@@ -191,17 +191,20 @@ fn describe_codegen_flags() {
 /// Process command line options. Emits messages as appropirate.If compilation
 /// should continue, returns a getopts::Matches object parsed from args, otherwise
 /// returns None.
-pub fn handle_options(mut args: Vec<~str>) -> Option<getopts::Matches> {
+pub fn handle_options(mut args: Vec<StrBuf>) -> Option<getopts::Matches> {
     // Throw away the first argument, the name of the binary
     let _binary = args.shift().unwrap();
 
-    if args.is_empty() { usage(); return None; }
+    if args.is_empty() {
+        usage();
+        return None;
+    }
 
     let matches =
         match getopts::getopts(args.as_slice(), config::optgroups().as_slice()) {
             Ok(m) => m,
             Err(f) => {
-                early_error(f.to_err_msg());
+                early_error(f.to_err_msg().as_slice());
             }
         };
 
@@ -212,24 +215,24 @@ pub fn handle_options(mut args: Vec<~str>) -> Option<getopts::Matches> {
 
     let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
                                     matches.opt_strs("warn").as_slice());
-    if lint_flags.iter().any(|x| x == &"help".to_owned()) {
+    if lint_flags.iter().any(|x| x.as_slice() == "help") {
         describe_warnings();
         return None;
     }
 
     let r = matches.opt_strs("Z");
-    if r.iter().any(|x| x == &"help".to_owned()) {
+    if r.iter().any(|x| x.as_slice() == "help") {
         describe_debug_flags();
         return None;
     }
 
     let cg_flags = matches.opt_strs("C");
-    if cg_flags.iter().any(|x| x == &"help".to_owned()) {
+    if cg_flags.iter().any(|x| x.as_slice() == "help") {
         describe_codegen_flags();
         return None;
     }
 
-    if cg_flags.contains(&"passes=list".to_owned()) {
+    if cg_flags.contains(&"passes=list".to_strbuf()) {
         unsafe { ::lib::llvm::llvm::LLVMRustPrintPasses(); }
         return None;
     }
@@ -285,20 +288,32 @@ pub enum PpMode {
     PpmExpanded,
     PpmTyped,
     PpmIdentified,
-    PpmExpandedIdentified
+    PpmExpandedIdentified,
+    PpmFlowGraph(ast::NodeId),
 }
 
 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
-    match name {
-        "normal" => PpmNormal,
-        "expanded" => PpmExpanded,
-        "typed" => PpmTyped,
-        "expanded,identified" => PpmExpandedIdentified,
-        "identified" => PpmIdentified,
+    let mut split = name.splitn('=', 1);
+    let first = split.next().unwrap();
+    let opt_second = split.next();
+    match (opt_second, first) {
+        (None, "normal")       => PpmNormal,
+        (None, "expanded")     => PpmExpanded,
+        (None, "typed")        => PpmTyped,
+        (None, "expanded,identified") => PpmExpandedIdentified,
+        (None, "identified")   => PpmIdentified,
+        (Some(s), "flowgraph") => {
+             match from_str(s) {
+                 Some(id) => PpmFlowGraph(id),
+                 None => sess.fatal(format!("`pretty flowgraph=<nodeid>` needs \
+                                             an integer <nodeid>; got {}", s))
+             }
+        }
         _ => {
-            sess.fatal("argument to `pretty` must be one of `normal`, \
-                        `expanded`, `typed`, `identified`, \
-                        or `expanded,identified`");
+            sess.fatal(format!(
+                "argument to `pretty` must be one of `normal`, \
+                 `expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
+                 or `expanded,identified`; got {}", name));
         }
     }
 }
@@ -323,7 +338,7 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
 }
 
 pub fn early_error(msg: &str) -> ! {
-    let mut emitter = diagnostic::EmitterWriter::stderr();
+    let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
     emitter.emit(None, msg, diagnostic::Fatal);
     fail!(diagnostic::FatalError);
 }
@@ -368,7 +383,7 @@ fn monitor(f: proc():Send) {
         Err(value) => {
             // Task failed without emitting a fatal diagnostic
             if !value.is::<diagnostic::FatalError>() {
-                let mut emitter = diagnostic::EmitterWriter::stderr();
+                let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto);
 
                 // a .span_bug or .bug call has already printed what
                 // it wants to print.
index b5176d3f4a8ddd0e130f898f7a474e6b7d065819..e450fd200a6ae19598720d1d67bd759605efa9e7 100644 (file)
@@ -196,7 +196,7 @@ pub fn build_session(sopts: config::Options,
                      -> Session {
     let codemap = codemap::CodeMap::new();
     let diagnostic_handler =
-        diagnostic::default_handler();
+        diagnostic::default_handler(sopts.color);
     let span_diagnostic_handler =
         diagnostic::mk_span_handler(diagnostic_handler, codemap);
 
index d3b5fb1ca470c4f62e97f9a962c5c7e43e2346d2..678d525ddcbb90b1121f4832c352cb66338423e4 100644 (file)
@@ -33,6 +33,7 @@
 
 extern crate flate;
 extern crate arena;
+extern crate graphviz;
 extern crate syntax;
 extern crate serialize;
 extern crate sync;
@@ -120,6 +121,8 @@ pub mod lib {
 }
 
 pub fn main() {
-    std::os::set_exit_status(driver::main_args(std::os::args().as_slice()));
+    let args = std::os::args().iter()
+                              .map(|x| x.to_strbuf())
+                              .collect::<Vec<_>>();
+    std::os::set_exit_status(driver::main_args(args.as_slice()));
 }
-
index 0c874bd776ed11d1fd8a7e162d4741d3354197b3..711081f46d6669703a276c2d8981881c4398b078 100644 (file)
@@ -1755,8 +1755,10 @@ pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef,
                                          PM: PassManagerRef,
                                          M: ModuleRef);
         pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
-                                             M: ModuleRef);
-        pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef);
+                                             M: ModuleRef,
+                                             DisableSimplifyLibCalls: bool);
+        pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef,
+                                      DisableSimplifyLibCalls: bool);
         pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
         pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
                                        PM: PassManagerRef,
index 49b5d7b28640c80730d9986bcfe5197f519bbd22..c885fc49de25f7009e8321d5828f92d4a8659f52 100644 (file)
@@ -15,9 +15,7 @@
 
 use std::cell::RefCell;
 use collections::HashMap;
-use std::io;
 use std::io::MemWriter;
-use std::fmt;
 
 use middle::ty::param_ty;
 use middle::ty;
@@ -28,9 +26,7 @@
 use syntax::diagnostic::SpanHandler;
 use syntax::parse::token;
 
-macro_rules! mywrite( ($wr:expr, $($arg:tt)*) => (
-    format_args!(|a| { mywrite($wr, a) }, $($arg)*)
-) )
+macro_rules! mywrite( ($($arg:tt)*) => ({ write!($($arg)*); }) )
 
 pub struct ctxt<'a> {
     pub diag: &'a SpanHandler,
@@ -52,10 +48,6 @@ pub struct ty_abbrev {
 
 pub type abbrev_map = RefCell<HashMap<ty::t, ty_abbrev>>;
 
-fn mywrite(w: &mut MemWriter, fmt: &fmt::Arguments) {
-    fmt::write(&mut *w as &mut io::Writer, fmt);
-}
-
 pub fn enc_ty(w: &mut MemWriter, cx: &ctxt, t: ty::t) {
     match cx.abbrevs.borrow_mut().find(&t) {
         Some(a) => { w.write(a.s.as_bytes()); return; }
index d631340fc4e31c974c1ed4bc287b2b5ed3157a7e..c9c397d3d6121141a0cc6a7dc901dfe884ff3653 100644 (file)
 
 struct CFGBuilder<'a> {
     tcx: &'a ty::ctxt,
-    method_map: typeck::MethodMap,
     exit_map: NodeMap<CFGIndex>,
     graph: CFGGraph,
-    loop_scopes: Vec<LoopScope> ,
+    fn_exit: CFGIndex,
+    loop_scopes: Vec<LoopScope>,
 }
 
 struct LoopScope {
@@ -31,22 +31,35 @@ struct LoopScope {
 }
 
 pub fn construct(tcx: &ty::ctxt,
-                 method_map: typeck::MethodMap,
                  blk: &ast::Block) -> CFG {
+    let mut graph = graph::Graph::new();
+    let entry = add_initial_dummy_node(&mut graph);
+
+    // `fn_exit` is target of return exprs, which lies somewhere
+    // outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
+    // also resolves chicken-and-egg problem that arises if you try to
+    // have return exprs jump to `block_exit` during construction.)
+    let fn_exit = add_initial_dummy_node(&mut graph);
+    let block_exit;
+
     let mut cfg_builder = CFGBuilder {
         exit_map: NodeMap::new(),
-        graph: graph::Graph::new(),
+        graph: graph,
+        fn_exit: fn_exit,
         tcx: tcx,
-        method_map: method_map,
         loop_scopes: Vec::new()
     };
-    let entry = cfg_builder.add_node(0, []);
-    let exit = cfg_builder.block(blk, entry);
+    block_exit = cfg_builder.block(blk, entry);
+    cfg_builder.add_contained_edge(block_exit, fn_exit);
     let CFGBuilder {exit_map, graph, ..} = cfg_builder;
     CFG {exit_map: exit_map,
          graph: graph,
          entry: entry,
-         exit: exit}
+         exit: fn_exit}
+}
+
+fn add_initial_dummy_node(g: &mut CFGGraph) -> CFGIndex {
+    g.add_node(CFGNodeData { id: ast::DUMMY_NODE_ID })
 }
 
 impl<'a> CFGBuilder<'a> {
@@ -327,24 +340,25 @@ fn expr(&mut self, expr: @ast::Expr, pred: CFGIndex) -> CFGIndex {
 
             ast::ExprRet(v) => {
                 let v_exit = self.opt_expr(v, pred);
-                let loop_scope = *self.loop_scopes.get(0);
-                self.add_exiting_edge(expr, v_exit,
-                                      loop_scope, loop_scope.break_index);
-                self.add_node(expr.id, [])
+                let b = self.add_node(expr.id, [v_exit]);
+                self.add_returning_edge(expr, b);
+                self.add_node(ast::DUMMY_NODE_ID, [])
             }
 
             ast::ExprBreak(label) => {
                 let loop_scope = self.find_scope(expr, label);
-                self.add_exiting_edge(expr, pred,
+                let b = self.add_node(expr.id, [pred]);
+                self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
-                self.add_node(expr.id, [])
+                self.add_node(ast::DUMMY_NODE_ID, [])
             }
 
             ast::ExprAgain(label) => {
                 let loop_scope = self.find_scope(expr, label);
-                self.add_exiting_edge(expr, pred,
+                let a = self.add_node(expr.id, [pred]);
+                self.add_exiting_edge(expr, a,
                                       loop_scope, loop_scope.continue_index);
-                self.add_node(expr.id, [])
+                self.add_node(ast::DUMMY_NODE_ID, [])
             }
 
             ast::ExprVec(ref elems) => {
@@ -453,13 +467,16 @@ fn straightline(&mut self,
     }
 
     fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
-        self.add_node(0, preds)
+        self.add_node(ast::DUMMY_NODE_ID, preds)
     }
 
     fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
         assert!(!self.exit_map.contains_key(&id));
         let node = self.graph.add_node(CFGNodeData {id: id});
-        self.exit_map.insert(id, node);
+        if id != ast::DUMMY_NODE_ID {
+            assert!(!self.exit_map.contains_key(&id));
+            self.exit_map.insert(id, node);
+        }
         for &pred in preds.iter() {
             self.add_contained_edge(pred, node);
         }
@@ -488,6 +505,16 @@ fn add_exiting_edge(&mut self,
         self.graph.add_edge(from_index, to_index, data);
     }
 
+    fn add_returning_edge(&mut self,
+                          _from_expr: @ast::Expr,
+                          from_index: CFGIndex) {
+        let mut data = CFGEdgeData {exiting_scopes: vec!() };
+        for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
+            data.exiting_scopes.push(id);
+        }
+        self.graph.add_edge(from_index, self.fn_exit, data);
+    }
+
     fn find_scope(&self,
                   expr: @ast::Expr,
                   label: Option<ast::Ident>) -> LoopScope {
@@ -521,6 +548,6 @@ fn find_scope(&self,
 
     fn is_method_call(&self, expr: &ast::Expr) -> bool {
         let method_call = typeck::MethodCall::expr(expr.id);
-        self.method_map.borrow().contains_key(&method_call)
+        self.tcx.method_map.borrow().contains_key(&method_call)
     }
 }
diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs
new file mode 100644 (file)
index 0000000..b8baeef
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2014 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 module provides linkage between rustc::middle::graph and
+/// libgraphviz traits.
+
+/// For clarity, rename the graphviz crate locally to dot.
+use dot = graphviz;
+
+use syntax::ast;
+use syntax::ast_map;
+
+use middle::cfg;
+
+pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
+pub type Edge<'a> = &'a cfg::CFGEdge;
+
+pub struct LabelledCFG<'a>{
+    pub ast_map: &'a ast_map::Map,
+    pub cfg: &'a cfg::CFG,
+    pub name: StrBuf,
+}
+
+fn replace_newline_with_backslash_l(s: StrBuf) -> StrBuf {
+    // Replacing newlines with \\l causes each line to be left-aligned,
+    // improving presentation of (long) pretty-printed expressions.
+    if s.as_slice().contains("\n") {
+        let mut s = s.replace("\n", "\\l");
+        // Apparently left-alignment applies to the line that precedes
+        // \l, not the line that follows; so, add \l at end of string
+        // if not already present, ensuring last line gets left-aligned
+        // as well.
+        let mut last_two : Vec<_> = s.chars().rev().take(2).collect();
+        last_two.reverse();
+        if last_two.as_slice() != ['\\', 'l'] {
+            s = s.append("\\l");
+        }
+        s.to_strbuf()
+    } else {
+        s
+    }
+}
+
+impl<'a> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a> {
+    fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(self.name.as_slice()) }
+
+    fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> {
+        dot::Id::new(format!("N{:u}", i.node_id()))
+    }
+
+    fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {
+        if i == self.cfg.entry {
+            dot::LabelStr("entry".into_maybe_owned())
+        } else if i == self.cfg.exit {
+            dot::LabelStr("exit".into_maybe_owned())
+        } else if n.data.id == ast::DUMMY_NODE_ID {
+            dot::LabelStr("(dummy_node)".into_maybe_owned())
+        } else {
+            let s = self.ast_map.node_to_str(n.data.id);
+            // left-aligns the lines
+            let s = replace_newline_with_backslash_l(s);
+            dot::EscStr(s.into_maybe_owned())
+        }
+    }
+
+    fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
+        let mut label = StrBuf::new();
+        let mut put_one = false;
+        for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() {
+            if put_one {
+                label = label.append(",\\l");
+            } else {
+                put_one = true;
+            }
+            let s = self.ast_map.node_to_str(node_id);
+            // left-aligns the lines
+            let s = replace_newline_with_backslash_l(s);
+            label = label.append(format!("exiting scope_{} {}", i, s.as_slice()));
+        }
+        dot::EscStr(label.into_maybe_owned())
+    }
+}
+
+impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG {
+    fn nodes(&self) -> dot::Nodes<'a, Node<'a>> {
+        let mut v = Vec::new();
+        self.graph.each_node(|i, nd| { v.push((i, nd)); true });
+        dot::maybe_owned_vec::Growable(v)
+    }
+    fn edges(&self) -> dot::Edges<'a, Edge<'a>> {
+        self.graph.all_edges().iter().collect()
+    }
+    fn source(&self, edge: &Edge<'a>) -> Node<'a> {
+        let i = edge.source();
+        (i, self.graph.node(i))
+    }
+    fn target(&self, edge: &Edge<'a>) -> Node<'a> {
+        let i = edge.target();
+        (i, self.graph.node(i))
+    }
+}
+
+impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a>
+{
+    fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() }
+    fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() }
+    fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) }
+    fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) }
+}
index 97ea996bb7e458e3dd53aecd37b2c375e4b38118..f0b912fb87bbff17b7f4aac7ebf31b8c90fd2efb 100644 (file)
 
 use middle::graph;
 use middle::ty;
-use middle::typeck;
 use syntax::ast;
 use util::nodemap::NodeMap;
 
 mod construct;
+pub mod graphviz;
 
 pub struct CFG {
-    exit_map: NodeMap<CFGIndex>,
-    graph: CFGGraph,
-    entry: CFGIndex,
-    exit: CFGIndex,
+    pub exit_map: NodeMap<CFGIndex>,
+    pub graph: CFGGraph,
+    pub entry: CFGIndex,
+    pub exit: CFGIndex,
 }
 
 pub struct CFGNodeData {
-    id: ast::NodeId
+    pub id: ast::NodeId
 }
 
 pub struct CFGEdgeData {
-    exiting_scopes: Vec<ast::NodeId>
+    pub exiting_scopes: Vec<ast::NodeId>
 }
 
 pub type CFGIndex = graph::NodeIndex;
@@ -55,8 +55,7 @@ pub struct CFGIndices {
 
 impl CFG {
     pub fn new(tcx: &ty::ctxt,
-               method_map: typeck::MethodMap,
                blk: &ast::Block) -> CFG {
-        construct::construct(tcx, method_map, blk)
+        construct::construct(tcx, blk)
     }
 }
index 2705f9bf9bf4dfc0e4de7cd98409a7076f981a41..5773d0bafa1d1a9e9265b22323b9300c5cfeab8a 100644 (file)
@@ -70,10 +70,14 @@ pub struct Direction { repr: uint }
 
 impl NodeIndex {
     fn get(&self) -> uint { let NodeIndex(v) = *self; v }
+    /// Returns unique id (unique with respect to the graph holding associated node).
+    pub fn node_id(&self) -> uint { self.get() }
 }
 
 impl EdgeIndex {
     fn get(&self) -> uint { let EdgeIndex(v) = *self; v }
+    /// Returns unique id (unique with respect to the graph holding associated edge).
+    pub fn edge_id(&self) -> uint { self.get() }
 }
 
 impl<N,E> Graph<N,E> {
@@ -201,39 +205,39 @@ pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex {
     ///////////////////////////////////////////////////////////////////////////
     // Iterating over nodes, edges
 
-    pub fn each_node(&self, f: |NodeIndex, &Node<N>| -> bool) -> bool {
+    pub fn each_node<'a>(&'a self, f: |NodeIndex, &'a Node<N>| -> bool) -> bool {
         //! Iterates over all edges defined in the graph.
         self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node))
     }
 
-    pub fn each_edge(&self, f: |EdgeIndex, &Edge<E>| -> bool) -> bool {
+    pub fn each_edge<'a>(&'a self, f: |EdgeIndex, &'a Edge<E>| -> bool) -> bool {
         //! Iterates over all edges defined in the graph
         self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge))
     }
 
-    pub fn each_outgoing_edge(&self,
-                              source: NodeIndex,
-                              f: |EdgeIndex, &Edge<E>| -> bool)
-                              -> bool {
+    pub fn each_outgoing_edge<'a>(&'a self,
+                                  source: NodeIndex,
+                                  f: |EdgeIndex, &'a Edge<E>| -> bool)
+                                  -> bool {
         //! Iterates over all outgoing edges from the node `from`
 
         self.each_adjacent_edge(source, Outgoing, f)
     }
 
-    pub fn each_incoming_edge(&self,
-                              target: NodeIndex,
-                              f: |EdgeIndex, &Edge<E>| -> bool)
-                              -> bool {
+    pub fn each_incoming_edge<'a>(&'a self,
+                                  target: NodeIndex,
+                                  f: |EdgeIndex, &'a Edge<E>| -> bool)
+                                  -> bool {
         //! Iterates over all incoming edges to the node `target`
 
         self.each_adjacent_edge(target, Incoming, f)
     }
 
-    pub fn each_adjacent_edge(&self,
-                              node: NodeIndex,
-                              dir: Direction,
-                              f: |EdgeIndex, &Edge<E>| -> bool)
-                              -> bool {
+    pub fn each_adjacent_edge<'a>(&'a self,
+                                  node: NodeIndex,
+                                  dir: Direction,
+                                  f: |EdgeIndex, &'a Edge<E>| -> bool)
+                                  -> bool {
         //! Iterates over all edges adjacent to the node `node`
         //! in the direction `dir` (either `Outgoing` or `Incoming)
 
@@ -257,11 +261,11 @@ pub fn each_adjacent_edge(&self,
     // variables or other bitsets. This method facilitates such a
     // computation.
 
-    pub fn iterate_until_fixed_point(&self,
-                                     op: |iter_index: uint,
-                                          edge_index: EdgeIndex,
-                                          edge: &Edge<E>|
-                                          -> bool) {
+    pub fn iterate_until_fixed_point<'a>(&'a self,
+                                         op: |iter_index: uint,
+                                              edge_index: EdgeIndex,
+                                              edge: &'a Edge<E>|
+                                              -> bool) {
         let mut iteration = 0;
         let mut changed = true;
         while changed {
index 062a7418287e3e7da0b17daabb35d5aa8fbf8240..1c24d609551ab992d7791537ff8af17a96e1f80b 100644 (file)
@@ -1050,6 +1050,7 @@ fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) {
 static crate_attrs: &'static [&'static str] = &[
     "crate_type", "feature", "no_start", "no_main", "no_std", "crate_id",
     "desc", "comment", "license", "copyright", // not used in rustc now
+    "no_builtins",
 ];
 
 
index 02599d7a368c165287b739fcf972cacc1ef833b4..1954c6d4123eebb92f7fa440ea72142f5a19ada5 100644 (file)
@@ -183,13 +183,13 @@ pub fn check_crate(tcx: &ty::ctxt,
 
 impl fmt::Show for LiveNode {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "ln({})", self.get())
+        write!(f, "ln({})", self.get())
     }
 }
 
 impl fmt::Show for Variable {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "v({})", self.get())
+        write!(f, "v({})", self.get())
     }
 }
 
index 17aa0664d479410d8de9bb5bc587b6598962668a..92e3b95abadc1d34eb94c867a55c04a7a22fe0f2 100644 (file)
@@ -2226,6 +2226,7 @@ pub fn trans_crate(krate: ast::Crate,
 
     let metadata_module = ccx.metadata_llmod;
     let formats = ccx.tcx.dependency_formats.borrow().clone();
+    let no_builtins = attr::contains_name(krate.attrs.as_slice(), "no_builtins");
 
     (ccx.tcx, CrateTranslation {
         context: llcx,
@@ -2235,5 +2236,6 @@ pub fn trans_crate(krate: ast::Crate,
         metadata: metadata,
         reachable: reachable,
         crate_formats: formats,
+        no_builtins: no_builtins,
     })
 }
index bc3a0c0073f272b1d649dc39b5134990dfb94f54..861caa62515b517b0dcbe6cac2cc6f23be6145eb 100644 (file)
@@ -309,6 +309,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
         ast_map::NodeStmt(..) |
         ast_map::NodeArg(..) |
         ast_map::NodeBlock(..) |
+        ast_map::NodePat(..) |
         ast_map::NodeLocal(..) => {
             ccx.sess().bug(format!("can't monomorphize a {:?}", map_node))
         }
index 2ae925caab56395c1d6028d0dd3dd45e8541fad5..517be1bde2f3a980ecb45115a643cc3d789bbb40 100644 (file)
@@ -388,7 +388,7 @@ pub struct t { inner: *t_opaque }
 
 impl fmt::Show for t {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.buf.write_str("*t_opaque")
+        "*t_opaque".fmt(f)
     }
 }
 
@@ -912,7 +912,7 @@ impl Vid for TyVid {
 
 impl fmt::Show for TyVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
-        write!(f.buf, "<generic \\#{}>", self.to_uint())
+        write!(f, "<generic \\#{}>", self.to_uint())
     }
 }
 
@@ -922,7 +922,7 @@ impl Vid for IntVid {
 
 impl fmt::Show for IntVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "<generic integer \\#{}>", self.to_uint())
+        write!(f, "<generic integer \\#{}>", self.to_uint())
     }
 }
 
@@ -932,7 +932,7 @@ impl Vid for FloatVid {
 
 impl fmt::Show for FloatVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "<generic float \\#{}>", self.to_uint())
+        write!(f, "<generic float \\#{}>", self.to_uint())
     }
 }
 
@@ -949,7 +949,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for FnSig {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         // grr, without tcx not much we can do.
-        write!(f.buf, "(...)")
+        write!(f, "(...)")
     }
 }
 
@@ -1987,7 +1987,7 @@ fn sub(&self, other: &TypeContents) -> TypeContents {
 
 impl fmt::Show for TypeContents {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "TypeContents({:t})", self.bits)
+        write!(f, "TypeContents({:t})", self.bits)
     }
 }
 
index f853b0dbad40f9254f3553c958b33da962da1ed8..d80e9f0888865b2e16415461f84c98524f44cd2e 100644 (file)
@@ -103,12 +103,24 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool {
     ty::walk_ty(original_type, |t| {
         match get(t).sty {
             ty_enum(def_id, _) |
-            ty_trait(box ty::TyTrait { def_id, .. }) |
             ty_struct(def_id, _) => {
                 if def_id.krate == ast::LOCAL_CRATE {
                     found_nominal = true;
                 }
             }
+            ty_trait(box ty::TyTrait { def_id, ref store, .. }) => {
+                if def_id.krate == ast::LOCAL_CRATE {
+                    found_nominal = true;
+                }
+                if *store == ty::UniqTraitStore {
+                    match tcx.lang_items.owned_box() {
+                        Some(did) if did.krate == ast::LOCAL_CRATE => {
+                            found_nominal = true;
+                        }
+                        _ => {}
+                    }
+                }
+            }
             ty_uniq(..) => {
                 match tcx.lang_items.owned_box() {
                     Some(did) if did.krate == ast::LOCAL_CRATE => {
index f2f86485b199716b5cd3edf1229675e2e8499696..42850f8876338d002114ee3b88ef054e40022258 100644 (file)
@@ -240,9 +240,9 @@ enum VarianceTerm<'a> {
 impl<'a> fmt::Show for VarianceTerm<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ConstantTerm(c1) => write!(f.buf, "{}", c1),
-            TransformTerm(v1, v2) => write!(f.buf, "({} \u00D7 {})", v1, v2),
-            InferredTerm(id) => write!(f.buf, "[{}]", { let InferredIndex(i) = id; i })
+            ConstantTerm(c1) => write!(f, "{}", c1),
+            TransformTerm(v1, v2) => write!(f, "({} \u00D7 {})", v1, v2),
+            InferredTerm(id) => write!(f, "[{}]", { let InferredIndex(i) = id; i })
         }
     }
 }
index 4439f626b2ce12a2fc9f95069bedb81f3f6c04d9..bd911f42db0fa046002ffeb8b212e123341a671f 100644 (file)
@@ -1204,7 +1204,7 @@ fn clean(&self) -> Item {
                 ForeignFunctionItem(Function {
                     decl: decl.clean(),
                     generics: generics.clean(),
-                    fn_style: ast::NormalFn,
+                    fn_style: ast::UnsafeFn,
                 })
             }
             ast::ForeignItemStatic(ref ty, mutbl) => {
index 2f6f16a4ed44bea7499e6a16e8101321bdd3c891..791ee96d67290cde77ea2f40c0e1cb4816f07c9c 100644 (file)
@@ -78,7 +78,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<StrBuf>)
 
 
     let codemap = syntax::codemap::CodeMap::new();
-    let diagnostic_handler = syntax::diagnostic::default_handler();
+    let diagnostic_handler = syntax::diagnostic::default_handler(syntax::diagnostic::Auto);
     let span_diagnostic_handler =
         syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
 
index 60fcbe33a1be956e8e6671530e7d1aea5517ec76..fe93dbbc081f8b688963eb8e9461073c62057ded 100644 (file)
@@ -29,7 +29,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         for (i, ch) in s.bytes().enumerate() {
             match ch as char {
                 '<' | '>' | '&' | '\'' | '"' => {
-                    try!(fmt.buf.write(pile_o_bits.slice(last, i).as_bytes()));
+                    try!(fmt.write(pile_o_bits.slice(last, i).as_bytes()));
                     let s = match ch as char {
                         '>' => "&gt;",
                         '<' => "&lt;",
@@ -38,7 +38,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                         '"' => "&quot;",
                         _ => unreachable!()
                     };
-                    try!(fmt.buf.write(s.as_bytes()));
+                    try!(fmt.write(s.as_bytes()));
                     last = i + 1;
                 }
                 _ => {}
@@ -46,7 +46,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         }
 
         if last < s.len() {
-            try!(fmt.buf.write(pile_o_bits.slice_from(last).as_bytes()));
+            try!(fmt.write(pile_o_bits.slice_from(last).as_bytes()));
         }
         Ok(())
     }
index 342b96ba82f50c3f2599a539616fc93ff6f6bdf1..563da5318f7c13f1e67d2cccd3340e6aa3a404b5 100644 (file)
@@ -16,7 +16,6 @@
 //! them in the future to instead emit any format desired.
 
 use std::fmt;
-use std::io;
 use std::strbuf::StrBuf;
 
 use syntax::ast;
@@ -52,46 +51,46 @@ pub fn get(&self) -> ast::FnStyle {
 impl fmt::Show for clean::Generics {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) }
-        try!(f.buf.write("&lt;".as_bytes()));
+        try!(f.write("&lt;".as_bytes()));
 
         for (i, life) in self.lifetimes.iter().enumerate() {
             if i > 0 {
-                try!(f.buf.write(", ".as_bytes()));
+                try!(f.write(", ".as_bytes()));
             }
-            try!(write!(f.buf, "{}", *life));
+            try!(write!(f, "{}", *life));
         }
 
         if self.type_params.len() > 0 {
             if self.lifetimes.len() > 0 {
-                try!(f.buf.write(", ".as_bytes()));
+                try!(f.write(", ".as_bytes()));
             }
 
             for (i, tp) in self.type_params.iter().enumerate() {
                 if i > 0 {
-                    try!(f.buf.write(", ".as_bytes()))
+                    try!(f.write(", ".as_bytes()))
                 }
-                try!(f.buf.write(tp.name.as_bytes()));
+                try!(f.write(tp.name.as_bytes()));
 
                 if tp.bounds.len() > 0 {
-                    try!(f.buf.write(": ".as_bytes()));
+                    try!(f.write(": ".as_bytes()));
                     for (i, bound) in tp.bounds.iter().enumerate() {
                         if i > 0 {
-                            try!(f.buf.write(" + ".as_bytes()));
+                            try!(f.write(" + ".as_bytes()));
                         }
-                        try!(write!(f.buf, "{}", *bound));
+                        try!(write!(f, "{}", *bound));
                     }
                 }
             }
         }
-        try!(f.buf.write("&gt;".as_bytes()));
+        try!(f.write("&gt;".as_bytes()));
         Ok(())
     }
 }
 
 impl fmt::Show for clean::Lifetime {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(f.buf.write("'".as_bytes()));
-        try!(f.buf.write(self.get_ref().as_bytes()));
+        try!(f.write("'".as_bytes()));
+        try!(f.write(self.get_ref().as_bytes()));
         Ok(())
     }
 }
@@ -100,10 +99,10 @@ impl fmt::Show for clean::TyParamBound {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::RegionBound => {
-                f.buf.write("'static".as_bytes())
+                f.write("::".as_bytes())
             }
             clean::TraitBound(ref ty) => {
-                write!(f.buf, "{}", *ty)
+                write!(f, "{}", *ty)
             }
         }
     }
@@ -112,32 +111,33 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.global {
-            try!(f.buf.write("::".as_bytes()))
+            try!(f.write("::".as_bytes()))
         }
+
         for (i, seg) in self.segments.iter().enumerate() {
             if i > 0 {
-                try!(f.buf.write("::".as_bytes()))
+                try!(f.write("::".as_bytes()))
             }
-            try!(f.buf.write(seg.name.as_bytes()));
+            try!(f.write(seg.name.as_bytes()));
 
             if seg.lifetimes.len() > 0 || seg.types.len() > 0 {
-                try!(f.buf.write("&lt;".as_bytes()));
+                try!(f.write("&lt;".as_bytes()));
                 let mut comma = false;
                 for lifetime in seg.lifetimes.iter() {
                     if comma {
-                        try!(f.buf.write(", ".as_bytes()));
+                        try!(f.write(", ".as_bytes()));
                     }
                     comma = true;
-                    try!(write!(f.buf, "{}", *lifetime));
+                    try!(write!(f, "{}", *lifetime));
                 }
                 for ty in seg.types.iter() {
                     if comma {
-                        try!(f.buf.write(", ".as_bytes()));
+                        try!(f.write(", ".as_bytes()));
                     }
                     comma = true;
-                    try!(write!(f.buf, "{}", *ty));
+                    try!(write!(f, "{}", *ty));
                 }
-                try!(f.buf.write("&gt;".as_bytes()));
+                try!(f.write("&gt;".as_bytes()));
             }
         }
         Ok(())
@@ -146,7 +146,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
 /// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path(w: &mut io::Writer, did: ast::DefId, p: &clean::Path,
+fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
                  print_all: bool) -> fmt::Result {
     path(w, p, print_all,
         |cache, loc| {
@@ -170,7 +170,7 @@ fn resolved_path(w: &mut io::Writer, did: ast::DefId, p: &clean::Path,
         })
 }
 
-fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
+fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool,
         root: |&render::Cache, &[StrBuf]| -> Option<StrBuf>,
         info: |&render::Cache| -> Option<(Vec<StrBuf> , ItemType)>)
     -> fmt::Result
@@ -264,7 +264,7 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
 }
 
 /// Helper to render type parameters
-fn tybounds(w: &mut io::Writer,
+fn tybounds(w: &mut fmt::Formatter,
             typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
     match *typarams {
         Some(ref params) => {
@@ -286,13 +286,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::TyParamBinder(id) | clean::Generic(id) => {
                 let m = cache_key.get().unwrap();
-                f.buf.write(m.typarams.get(&id).as_bytes())
+                f.write(m.typarams.get(&id).as_bytes())
             }
             clean::ResolvedPath{ did, ref typarams, ref path} => {
-                try!(resolved_path(f.buf, did, path, false));
-                tybounds(f.buf, typarams)
+                try!(resolved_path(f, did, path, false));
+                tybounds(f, typarams)
             }
-            clean::Self(..) => f.buf.write("Self".as_bytes()),
+            clean::Self(..) => f.write("Self".as_bytes()),
             clean::Primitive(prim) => {
                 let s = match prim {
                     ast::TyInt(ast::TyI) => "int",
@@ -312,11 +312,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                     ast::TyBool => "bool",
                     ast::TyChar => "char",
                 };
-                f.buf.write(s.as_bytes())
+                f.write(s.as_bytes())
             }
             clean::Closure(ref decl, ref region) => {
-                write!(f.buf, "{style}{lifetimes}|{args}|{bounds}\
-                               {arrow, select, yes{ -&gt; {ret}} other{}}",
+                write!(f, "{style}{lifetimes}|{args}|{bounds}\
+                           {arrow, select, yes{ -&gt; {ret}} other{}}",
                        style = FnStyleSpace(decl.fn_style),
                        lifetimes = if decl.lifetimes.len() == 0 {
                            "".to_owned()
@@ -351,8 +351,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        })
             }
             clean::Proc(ref decl) => {
-                write!(f.buf, "{style}{lifetimes}proc({args}){bounds}\
-                               {arrow, select, yes{ -&gt; {ret}} other{}}",
+                write!(f, "{style}{lifetimes}proc({args}){bounds}\
+                           {arrow, select, yes{ -&gt; {ret}} other{}}",
                        style = FnStyleSpace(decl.fn_style),
                        lifetimes = if decl.lifetimes.len() == 0 {
                            "".to_strbuf()
@@ -374,7 +374,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        ret = decl.decl.output)
             }
             clean::BareFunction(ref decl) => {
-                write!(f.buf, "{}{}fn{}{}",
+                write!(f, "{}{}fn{}{}",
                        FnStyleSpace(decl.fn_style),
                        match decl.abi.as_slice() {
                            "" => " extern ".to_strbuf(),
@@ -385,27 +385,27 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                        decl.decl)
             }
             clean::Tuple(ref typs) => {
-                try!(f.buf.write("(".as_bytes()));
+                try!(f.write("(".as_bytes()));
                 for (i, typ) in typs.iter().enumerate() {
                     if i > 0 {
-                        try!(f.buf.write(", ".as_bytes()))
+                        try!(f.write(", ".as_bytes()))
                     }
-                    try!(write!(f.buf, "{}", *typ));
+                    try!(write!(f, "{}", *typ));
                 }
-                f.buf.write(")".as_bytes())
+                f.write(")".as_bytes())
             }
-            clean::Vector(ref t) => write!(f.buf, "[{}]", **t),
+            clean::Vector(ref t) => write!(f, "[{}]", **t),
             clean::FixedVector(ref t, ref s) => {
-                write!(f.buf, "[{}, ..{}]", **t, *s)
-            }
-            clean::String => f.buf.write("str".as_bytes()),
-            clean::Bool => f.buf.write("bool".as_bytes()),
-            clean::Unit => f.buf.write("()".as_bytes()),
-            clean::Bottom => f.buf.write("!".as_bytes()),
-            clean::Unique(ref t) => write!(f.buf, "~{}", **t),
-            clean::Managed(ref t) => write!(f.buf, "@{}", **t),
+                write!(f, "[{}, ..{}]", **t, *s)
+            }
+            clean::String => f.write("str".as_bytes()),
+            clean::Bool => f.write("bool".as_bytes()),
+            clean::Unit => f.write("()".as_bytes()),
+            clean::Bottom => f.write("!".as_bytes()),
+            clean::Unique(ref t) => write!(f, "~{}", **t),
+            clean::Managed(ref t) => write!(f, "@{}", **t),
             clean::RawPointer(m, ref t) => {
-                write!(f.buf, "*{}{}",
+                write!(f, "*{}{}",
                        match m {
                            clean::Mutable => "mut ",
                            clean::Immutable => "",
@@ -413,7 +413,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
             clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
                 let lt = match *l { Some(ref l) => format!("{} ", *l), _ => "".to_owned() };
-                write!(f.buf, "&amp;{}{}{}",
+                write!(f, "&amp;{}{}{}",
                        lt,
                        match mutability {
                            clean::Mutable => "mut ",
@@ -428,11 +428,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::Arguments {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         for (i, input) in self.values.iter().enumerate() {
-            if i > 0 { try!(write!(f.buf, ", ")); }
+            if i > 0 { try!(write!(f, ", ")); }
             if input.name.len() > 0 {
-                try!(write!(f.buf, "{}: ", input.name));
+                try!(write!(f, "{}: ", input.name));
             }
-            try!(write!(f.buf, "{}", input.type_));
+            try!(write!(f, "{}", input.type_));
         }
         Ok(())
     }
@@ -440,7 +440,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl fmt::Show for clean::FnDecl {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
+        write!(f, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
                args = self.inputs,
                arrow = match self.output { clean::Unit => "no", _ => "yes" },
                ret = self.output)
@@ -475,7 +475,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             }
             args.push_str(format!("{}", input.type_));
         }
-        write!(f.buf,
+        write!(f,
                "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
                args = args,
                arrow = match d.output { clean::Unit => "no", _ => "yes" },
@@ -486,7 +486,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for VisSpace {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.get() {
-            Some(ast::Public) => write!(f.buf, "pub "),
+            Some(ast::Public) => write!(f, "pub "),
             Some(ast::Inherited) | None => Ok(())
         }
     }
@@ -495,7 +495,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for FnStyleSpace {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.get() {
-            ast::UnsafeFn => write!(f.buf, "unsafe "),
+            ast::UnsafeFn => write!(f, "unsafe "),
             ast::NormalFn => Ok(())
         }
     }
@@ -506,23 +506,23 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::SimpleImport(ref name, ref src) => {
                 if *name == src.path.segments.last().unwrap().name {
-                    write!(f.buf, "use {};", *src)
+                    write!(f, "use {};", *src)
                 } else {
-                    write!(f.buf, "use {} = {};", *name, *src)
+                    write!(f, "use {} = {};", *name, *src)
                 }
             }
             clean::GlobImport(ref src) => {
-                write!(f.buf, "use {}::*;", *src)
+                write!(f, "use {}::*;", *src)
             }
             clean::ImportList(ref src, ref names) => {
-                try!(write!(f.buf, "use {}::\\{", *src));
+                try!(write!(f, "use {}::\\{", *src));
                 for (i, n) in names.iter().enumerate() {
                     if i > 0 {
-                        try!(write!(f.buf, ", "));
+                        try!(write!(f, ", "));
                     }
-                    try!(write!(f.buf, "{}", *n));
+                    try!(write!(f, "{}", *n));
                 }
-                write!(f.buf, "\\};")
+                write!(f, "\\};")
             }
         }
     }
@@ -531,13 +531,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::ImportSource {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.did {
-            Some(did) => resolved_path(f.buf, did, &self.path, true),
+            Some(did) => resolved_path(f, did, &self.path, true),
             _ => {
                 for (i, seg) in self.path.segments.iter().enumerate() {
                     if i > 0 {
-                        try!(write!(f.buf, "::"))
+                        try!(write!(f, "::"))
                     }
-                    try!(write!(f.buf, "{}", seg.name));
+                    try!(write!(f, "{}", seg.name));
                 }
                 Ok(())
             }
@@ -557,9 +557,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                         types: Vec::new(),
                     })
                 };
-                resolved_path(f.buf, did, &path, false)
+                resolved_path(f, did, &path, false)
             }
-            _ => write!(f.buf, "{}", self.name),
+            _ => write!(f, "{}", self.name),
         }
     }
 }
index e667f7a57f14bfb7ff4092ae4adbd8074f11c037..dd465df1db7e4a3f5c1d217dff7d02d88b5308dc 100644 (file)
@@ -26,7 +26,7 @@ pub struct Page<'a> {
 
 pub fn render<T: fmt::Show, S: fmt::Show>(
     dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
-    -> fmt::Result
+    -> io::IoResult<()>
 {
     write!(dst,
 r##"<!DOCTYPE html>
index d6831e225bc2931384cf9a663a44170146e9386b..b64e77615e1f5905f1632d5971b3bd1de453f064 100644 (file)
@@ -29,7 +29,6 @@
 use libc;
 use std::cell::RefCell;
 use std::fmt;
-use std::io;
 use std::slice;
 use std::str;
 use collections::HashMap;
@@ -141,7 +140,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
 
 local_data_key!(used_header_map: RefCell<HashMap<StrBuf, uint>>)
 
-pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result {
+pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
     extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer,
                     lang: *hoedown_buffer, opaque: *mut libc::c_void) {
         unsafe {
@@ -355,13 +354,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let Markdown(md) = *self;
         // This is actually common enough to special-case
         if md.len() == 0 { return Ok(()) }
-        render(fmt.buf, md.as_slice(), false)
+        render(fmt, md.as_slice(), false)
     }
 }
 
 impl<'a> fmt::Show for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let MarkdownWithToc(md) = *self;
-        render(fmt.buf, md.as_slice(), true)
+        render(fmt, md.as_slice(), true)
     }
 }
index 0883d25770ef75bd255c60ffca3ea2e20f5e8ef7..8ae29d7d273c2d89ca03303d7e403507e534f17a 100644 (file)
@@ -587,7 +587,7 @@ fn emit_source(&mut self, filename: &str) -> io::IoResult<()> {
             root_path: root_path.as_slice(),
         };
         try!(layout::render(&mut w as &mut Writer, &self.cx.layout,
-                              &page, &(""), &Source(contents)));
+                            &page, &(""), &Source(contents)));
         try!(w.flush());
         return Ok(());
     }
@@ -925,8 +925,8 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
             // write sycall all the time.
             let mut writer = BufferedWriter::new(w);
             try!(layout::render(&mut writer as &mut Writer, &cx.layout, &page,
-                                  &Sidebar{ cx: cx, item: it },
-                                  &Item{ cx: cx, item: it }));
+                                &Sidebar{ cx: cx, item: it },
+                                &Item{ cx: cx, item: it }));
             writer.flush()
         }
 
@@ -997,17 +997,17 @@ fn link(&self) -> StrBuf {
 impl<'a> fmt::Show for Item<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         // Write the breadcrumb trail header for the top
-        try!(write!(fmt.buf, "\n<h1 class='fqn'>"));
+        try!(write!(fmt, "\n<h1 class='fqn'>"));
         match self.item.inner {
             clean::ModuleItem(ref m) => if m.is_crate {
-                    try!(write!(fmt.buf, "Crate "));
+                    try!(write!(fmt, "Crate "));
                 } else {
-                    try!(write!(fmt.buf, "Module "));
+                    try!(write!(fmt, "Module "));
                 },
-            clean::FunctionItem(..) => try!(write!(fmt.buf, "Function ")),
-            clean::TraitItem(..) => try!(write!(fmt.buf, "Trait ")),
-            clean::StructItem(..) => try!(write!(fmt.buf, "Struct ")),
-            clean::EnumItem(..) => try!(write!(fmt.buf, "Enum ")),
+            clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
+            clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
+            clean::StructItem(..) => try!(write!(fmt, "Struct ")),
+            clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
             _ => {}
         }
         let cur = self.cx.current.as_slice();
@@ -1017,16 +1017,16 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             for _ in range(0, cur.len() - i - 1) {
                 trail.push_str("../");
             }
-            try!(write!(fmt.buf, "<a href='{}index.html'>{}</a>::",
-                          trail, component.as_slice()));
+            try!(write!(fmt, "<a href='{}index.html'>{}</a>::",
+                        trail, component.as_slice()));
         }
-        try!(write!(fmt.buf, "<a class='{}' href=''>{}</a>",
-                      shortty(self.item), self.item.name.get_ref().as_slice()));
+        try!(write!(fmt, "<a class='{}' href=''>{}</a>",
+                    shortty(self.item), self.item.name.get_ref().as_slice()));
 
         // Write stability attributes
         match attr::find_stability(self.item.attrs.iter()) {
             Some(ref stability) => {
-                try!(write!(fmt.buf,
+                try!(write!(fmt,
                        "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
                        lvl = stability.level.to_str(),
                        reason = match stability.text {
@@ -1039,22 +1039,22 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 
         // Write `src` tag
         if self.cx.include_sources {
-            try!(write!(fmt.buf, "<a class='source' href='{}'>[src]</a>",
+            try!(write!(fmt, "<a class='source' href='{}'>[src]</a>",
                         self.link()));
         }
-        try!(write!(fmt.buf, "</h1>\n"));
+        try!(write!(fmt, "</h1>\n"));
 
         match self.item.inner {
             clean::ModuleItem(ref m) => {
-                item_module(fmt.buf, self.cx, self.item, m.items.as_slice())
+                item_module(fmt, self.cx, self.item, m.items.as_slice())
             }
             clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
-                item_function(fmt.buf, self.item, f),
-            clean::TraitItem(ref t) => item_trait(fmt.buf, self.item, t),
-            clean::StructItem(ref s) => item_struct(fmt.buf, self.item, s),
-            clean::EnumItem(ref e) => item_enum(fmt.buf, self.item, e),
-            clean::TypedefItem(ref t) => item_typedef(fmt.buf, self.item, t),
-            clean::MacroItem(ref m) => item_macro(fmt.buf, self.item, m),
+                item_function(fmt, self.item, f),
+            clean::TraitItem(ref t) => item_trait(fmt, self.item, t),
+            clean::StructItem(ref s) => item_struct(fmt, self.item, s),
+            clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
+            clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
+            clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
             _ => Ok(())
         }
     }
@@ -1097,7 +1097,7 @@ fn shorter<'a>(s: Option<&'a str>) -> &'a str {
     }
 }
 
-fn document(w: &mut Writer, item: &clean::Item) -> fmt::Result {
+fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
     match item.doc_value() {
         Some(s) => {
             try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
@@ -1107,7 +1107,7 @@ fn document(w: &mut Writer, item: &clean::Item) -> fmt::Result {
     Ok(())
 }
 
-fn item_module(w: &mut Writer, cx: &Context,
+fn item_module(w: &mut fmt::Formatter, cx: &Context,
                item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
     try!(document(w, item));
     debug!("{:?}", items);
@@ -1196,13 +1196,12 @@ impl<'a> fmt::Show for Initializer<'a> {
                     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                         let Initializer(s, item) = *self;
                         if s.len() == 0 { return Ok(()); }
-                        try!(write!(f.buf, "<code> = </code>"));
+                        try!(write!(f, "<code> = </code>"));
                         if s.contains("\n") {
-                            write!(f.buf,
-                                   "<a href='{}'>[definition]</a>",
+                            write!(f, "<a href='{}'>[definition]</a>",
                                    item.link())
                         } else {
-                            write!(f.buf, "<code>{}</code>", s.as_slice())
+                            write!(f, "<code>{}</code>", s.as_slice())
                         }
                     }
                 }
@@ -1262,7 +1261,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     write!(w, "</table>")
 }
 
-fn item_function(w: &mut Writer, it: &clean::Item,
+fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
     try!(write!(w, "<pre class='rust fn'>{vis}{fn_style}fn \
                     {name}{generics}{decl}</pre>",
@@ -1274,7 +1273,7 @@ fn item_function(w: &mut Writer, it: &clean::Item,
     document(w, it)
 }
 
-fn item_trait(w: &mut Writer, it: &clean::Item,
+fn item_trait(w: &mut fmt::Formatter, it: &clean::Item,
               t: &clean::Trait) -> fmt::Result {
     let mut parents = StrBuf::new();
     if t.parents.len() > 0 {
@@ -1318,7 +1317,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
     // Trait documentation
     try!(document(w, it));
 
-    fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
+    fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
         try!(write!(w, "<h3 id='{}.{}' class='method'><code>",
                       shortty(m.item()),
                       *m.item().name.get_ref()));
@@ -1374,8 +1373,8 @@ fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
     Ok(())
 }
 
-fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
-    fn fun(w: &mut Writer, it: &clean::Item, fn_style: ast::FnStyle,
+fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
+    fn fun(w: &mut fmt::Formatter, it: &clean::Item, fn_style: ast::FnStyle,
            g: &clean::Generics, selfty: &clean::SelfTy,
            d: &clean::FnDecl) -> fmt::Result {
         write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
@@ -1400,7 +1399,7 @@ fn fun(w: &mut Writer, it: &clean::Item, fn_style: ast::FnStyle,
     }
 }
 
-fn item_struct(w: &mut Writer, it: &clean::Item,
+fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
                s: &clean::Struct) -> fmt::Result {
     try!(write!(w, "<pre class='rust struct'>"));
     try!(render_struct(w,
@@ -1437,7 +1436,8 @@ fn item_struct(w: &mut Writer, it: &clean::Item,
     render_methods(w, it)
 }
 
-fn item_enum(w: &mut Writer, it: &clean::Item, e: &clean::Enum) -> fmt::Result {
+fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
+             e: &clean::Enum) -> fmt::Result {
     try!(write!(w, "<pre class='rust enum'>{}enum {}{}",
                   VisSpace(it.visibility),
                   it.name.get_ref().as_slice(),
@@ -1533,7 +1533,7 @@ fn item_enum(w: &mut Writer, it: &clean::Item, e: &clean::Enum) -> fmt::Result {
     Ok(())
 }
 
-fn render_struct(w: &mut Writer, it: &clean::Item,
+fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                  g: Option<&clean::Generics>,
                  ty: doctree::StructType,
                  fields: &[clean::Item],
@@ -1597,7 +1597,7 @@ fn render_struct(w: &mut Writer, it: &clean::Item,
     Ok(())
 }
 
-fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result {
+fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
     match cache_key.get().unwrap().impls.find(&it.id) {
         Some(v) => {
             let mut non_trait = v.iter().filter(|p| {
@@ -1642,7 +1642,7 @@ fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result {
     Ok(())
 }
 
-fn render_impl(w: &mut Writer, i: &clean::Impl,
+fn render_impl(w: &mut fmt::Formatter, i: &clean::Impl,
                dox: &Option<StrBuf>) -> fmt::Result {
     try!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
     let trait_id = match i.trait_ {
@@ -1664,8 +1664,8 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
         None => {}
     }
 
-    fn docmeth(w: &mut Writer, item: &clean::Item,
-               dox: bool) -> io::IoResult<()> {
+    fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
+               dox: bool) -> fmt::Result {
         try!(write!(w, "<h4 id='method.{}' class='method'><code>",
                       *item.name.get_ref()));
         try!(render_method(w, item));
@@ -1714,7 +1714,7 @@ fn docmeth(w: &mut Writer, item: &clean::Item,
     Ok(())
 }
 
-fn item_typedef(w: &mut Writer, it: &clean::Item,
+fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
                 t: &clean::Typedef) -> fmt::Result {
     try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
                   it.name.get_ref().as_slice(),
@@ -1728,21 +1728,21 @@ impl<'a> fmt::Show for Sidebar<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let cx = self.cx;
         let it = self.item;
-        try!(write!(fmt.buf, "<p class='location'>"));
+        try!(write!(fmt, "<p class='location'>"));
         let len = cx.current.len() - if it.is_mod() {1} else {0};
         for (i, name) in cx.current.iter().take(len).enumerate() {
             if i > 0 {
-                try!(write!(fmt.buf, "&\\#8203;::"));
+                try!(write!(fmt, "&\\#8203;::"));
             }
-            try!(write!(fmt.buf, "<a href='{}index.html'>{}</a>",
+            try!(write!(fmt, "<a href='{}index.html'>{}</a>",
                           cx.root_path
                             .as_slice()
                             .slice_to((cx.current.len() - i - 1) * 3),
                           *name));
         }
-        try!(write!(fmt.buf, "</p>"));
+        try!(write!(fmt, "</p>"));
 
-        fn block(w: &mut Writer, short: &str, longty: &str,
+        fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
                  cur: &clean::Item, cx: &Context) -> fmt::Result {
             let items = match cx.sidebar.find_equiv(&short) {
                 Some(items) => items.as_slice(),
@@ -1770,12 +1770,12 @@ fn block(w: &mut Writer, short: &str, longty: &str,
             Ok(())
         }
 
-        try!(block(fmt.buf, "mod", "Modules", it, cx));
-        try!(block(fmt.buf, "struct", "Structs", it, cx));
-        try!(block(fmt.buf, "enum", "Enums", it, cx));
-        try!(block(fmt.buf, "trait", "Traits", it, cx));
-        try!(block(fmt.buf, "fn", "Functions", it, cx));
-        try!(block(fmt.buf, "macro", "Macros", it, cx));
+        try!(block(fmt, "mod", "Modules", it, cx));
+        try!(block(fmt, "struct", "Structs", it, cx));
+        try!(block(fmt, "enum", "Enums", it, cx));
+        try!(block(fmt, "trait", "Traits", it, cx));
+        try!(block(fmt, "fn", "Functions", it, cx));
+        try!(block(fmt, "macro", "Macros", it, cx));
         Ok(())
     }
 }
@@ -1808,19 +1808,18 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
             cols += 1;
             tmp /= 10;
         }
-        try!(write!(fmt.buf, "<pre class='line-numbers'>"));
+        try!(write!(fmt, "<pre class='line-numbers'>"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt.buf, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols));
+            try!(write!(fmt, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols));
         }
-        try!(write!(fmt.buf, "</pre>"));
-        try!(write!(fmt.buf, "{}", highlight::highlight(s.as_slice(), None)));
+        try!(write!(fmt, "</pre>"));
+        try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None)));
         Ok(())
     }
 }
 
-fn item_macro(w: &mut Writer, it: &clean::Item,
+fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
               t: &clean::Macro) -> fmt::Result {
-    try!(w.write_str(highlight::highlight(t.source.as_slice(),
-                                          Some("macro")).as_slice()));
+    try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro")).as_bytes()));
     document(w, it)
 }
index 893214dc9c9c7d433b963c95f601e8bd0cf19a17..4dabdf64f8102da691d785e5ead46326bacb6165 100644 (file)
@@ -174,17 +174,17 @@ pub fn push<'a>(&'a mut self, level: u32, name: StrBuf, id: StrBuf) -> &'a str {
 
 impl fmt::Show for Toc {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(fmt.buf, "<ul>"));
+        try!(write!(fmt, "<ul>"));
         for entry in self.entries.iter() {
             // recursively format this table of contents (the
             // `{children}` is the key).
-            try!(write!(fmt.buf,
+            try!(write!(fmt,
                         "\n<li><a href=\"\\#{id}\">{num} {name}</a>{children}</li>",
                         id = entry.id,
                         num = entry.sec_number, name = entry.name,
                         children = entry.children))
         }
-        write!(fmt.buf, "</ul>")
+        write!(fmt, "</ul>")
     }
 }
 
index 757adcc7671b44dd9002c9c0a9a96da4ee35fcd7..2a7808fdf77593c53c53a70278e3b964f85640e9 100644 (file)
@@ -137,12 +137,7 @@ pub fn usage(argv0: &str) {
 }
 
 pub fn main_args(args: &[StrBuf]) -> int {
-    let matches = match getopts::getopts(args.tail()
-                                             .iter()
-                                             .map(|x| (*x).to_owned())
-                                             .collect::<Vec<_>>()
-                                             .as_slice(),
-                                         opts().as_slice()) {
+    let matches = match getopts::getopts(args.tail(), opts().as_slice()) {
         Ok(m) => m,
         Err(err) => {
             println!("{}", err.to_err_msg());
@@ -170,7 +165,7 @@ pub fn main_args(args: &[StrBuf]) -> int {
 
     let test_args = matches.opt_strs("test-args");
     let test_args: Vec<StrBuf> = test_args.iter()
-                                          .flat_map(|s| s.words())
+                                          .flat_map(|s| s.as_slice().words())
                                           .map(|s| s.to_strbuf())
                                           .collect();
 
@@ -199,7 +194,7 @@ pub fn main_args(args: &[StrBuf]) -> int {
         (false, false) => {}
     }
 
-    if matches.opt_strs("passes").as_slice() == &["list".to_owned()] {
+    if matches.opt_strs("passes").as_slice() == &["list".to_strbuf()] {
         println!("Available passes for running rustdoc:");
         for &(name, _, description) in PASSES.iter() {
             println!("{:>20s} - {}", name, description);
@@ -306,7 +301,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
                     clean::NameValue(ref x, ref value)
                             if "passes" == x.as_slice() => {
                         for pass in value.as_slice().words() {
-                            passes.push(pass.to_owned());
+                            passes.push(pass.to_strbuf());
                         }
                     }
                     clean::NameValue(ref x, ref value)
@@ -323,15 +318,19 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
     }
     if default_passes {
         for name in DEFAULT_PASSES.iter().rev() {
-            passes.unshift(name.to_owned());
+            passes.unshift(name.to_strbuf());
         }
     }
 
     // Load all plugins/passes into a PluginManager
-    let path = matches.opt_str("plugin-path").unwrap_or("/tmp/rustdoc/plugins".to_owned());
+    let path = matches.opt_str("plugin-path")
+                      .unwrap_or("/tmp/rustdoc/plugins".to_strbuf());
     let mut pm = plugins::PluginManager::new(Path::new(path));
     for pass in passes.iter() {
-        let plugin = match PASSES.iter().position(|&(p, _, _)| p == *pass) {
+        let plugin = match PASSES.iter()
+                                 .position(|&(p, _, _)| {
+                                     p == pass.as_slice()
+                                 }) {
             Some(i) => PASSES[i].val1(),
             None => {
                 error!("unknown pass {}, skipping", *pass);
@@ -364,7 +363,7 @@ fn json_input(input: &str) -> Result<Output, StrBuf> {
         Ok(json::Object(obj)) => {
             let mut obj = obj;
             // Make sure the schema is what we expect
-            match obj.pop(&"schema".to_owned()) {
+            match obj.pop(&"schema".to_strbuf()) {
                 Some(json::String(version)) => {
                     if version.as_slice() != SCHEMA_VERSION {
                         return Err(format_strbuf!(
@@ -375,7 +374,7 @@ fn json_input(input: &str) -> Result<Output, StrBuf> {
                 Some(..) => return Err("malformed json".to_strbuf()),
                 None => return Err("expected a schema version".to_strbuf()),
             }
-            let krate = match obj.pop(&"crate".to_str()) {
+            let krate = match obj.pop(&"crate".to_strbuf()) {
                 Some(json) => {
                     let mut d = json::Decoder::new(json);
                     Decodable::decode(&mut d).unwrap()
@@ -404,13 +403,14 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
     //   "plugins": { output of plugins ... }
     // }
     let mut json = box collections::TreeMap::new();
-    json.insert("schema".to_owned(), json::String(SCHEMA_VERSION.to_owned()));
+    json.insert("schema".to_strbuf(),
+                json::String(SCHEMA_VERSION.to_strbuf()));
     let plugins_json = box res.move_iter()
                               .filter_map(|opt| {
                                   match opt {
                                       None => None,
                                       Some((string, json)) => {
-                                          Some((string.to_owned(), json))
+                                          Some((string.to_strbuf(), json))
                                       }
                                   }
                               }).collect();
@@ -423,15 +423,15 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
             let mut encoder = json::Encoder::new(&mut w as &mut io::Writer);
             krate.encode(&mut encoder).unwrap();
         }
-        str::from_utf8(w.unwrap().as_slice()).unwrap().to_owned()
+        str::from_utf8(w.unwrap().as_slice()).unwrap().to_strbuf()
     };
-    let crate_json = match json::from_str(crate_json_str) {
+    let crate_json = match json::from_str(crate_json_str.as_slice()) {
         Ok(j) => j,
         Err(e) => fail!("Rust generated JSON is invalid: {:?}", e)
     };
 
-    json.insert("crate".to_owned(), crate_json);
-    json.insert("plugins".to_owned(), json::Object(plugins_json));
+    json.insert("crate".to_strbuf(), crate_json);
+    json.insert("plugins".to_strbuf(), json::Object(plugins_json));
 
     let mut file = try!(File::create(&dst));
     try!(json::Object(json).to_writer(&mut file));
index 9e63848b90eab0d9d2f821e630229e1654513402..c56841a076d00133ae5d89390a0134092fbdf4a8 100644 (file)
@@ -11,7 +11,7 @@
 use std::cell::RefCell;
 use std::char;
 use std::io;
-use std::io::{Process, TempDir};
+use std::io::{Command, TempDir};
 use std::os;
 use std::str;
 use std::strbuf::StrBuf;
@@ -53,7 +53,7 @@ pub fn run(input: &str,
 
 
     let codemap = CodeMap::new();
-    let diagnostic_handler = diagnostic::default_handler();
+    let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto);
     let span_diagnostic_handler =
     diagnostic::mk_span_handler(diagnostic_handler, codemap);
 
@@ -155,9 +155,7 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
     if no_run { return }
 
     // Run the code!
-    let exe = outdir.path().join("rust_out");
-    let out = Process::output(exe.as_str().unwrap(), []);
-    match out {
+    match Command::new(outdir.path().join("rust_out")).output() {
         Err(e) => fail!("couldn't run the test: {}{}", e,
                         if e.kind == io::PermissionDenied {
                             " - maybe your tempdir is mounted with noexec?"
index 06271e61ce7a0f9f72d4361a835ee4e3584a62da..12636a3c490ad0ca64daafe083f8ff9dea0eb5d7 100644 (file)
@@ -285,9 +285,7 @@ fn to_msec(stat: uvll::uv_timespec_t) -> u64 {
         FileStat {
             size: stat.st_size as u64,
             kind: kind,
-            perm: unsafe {
-                io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions
-            },
+            perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32),
             created: to_msec(stat.st_birthtim),
             modified: to_msec(stat.st_mtim),
             accessed: to_msec(stat.st_atim),
index c9bff2e80bfe64f1992842f75748cb07c90f5628..a9b449e63be4c710628d123718cd93416c700755 100644 (file)
@@ -353,21 +353,21 @@ fn get_blockers(&self) -> uint {
 pub struct UvError(c_int);
 
 impl UvError {
-    pub fn name(&self) -> ~str {
+    pub fn name(&self) -> StrBuf {
         unsafe {
             let inner = match self { &UvError(a) => a };
             let name_str = uvll::uv_err_name(inner);
             assert!(name_str.is_not_null());
-            from_c_str(name_str)
+            from_c_str(name_str).to_strbuf()
         }
     }
 
-    pub fn desc(&self) -> ~str {
+    pub fn desc(&self) -> StrBuf {
         unsafe {
             let inner = match self { &UvError(a) => a };
             let desc_str = uvll::uv_strerror(inner);
             assert!(desc_str.is_not_null());
-            from_c_str(desc_str)
+            from_c_str(desc_str).to_strbuf()
         }
     }
 
@@ -379,7 +379,7 @@ pub fn is_eof(&self) -> bool {
 
 impl fmt::Show for UvError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}: {}", self.name(), self.desc())
+        write!(f, "{}: {}", self.name(), self.desc())
     }
 }
 
@@ -472,7 +472,7 @@ fn local_loop() -> &'static mut uvio::UvIoFactory {
 #[cfg(test)]
 mod test {
     use std::mem::transmute;
-    use std::unstable::run_in_bare_thread;
+    use std::rt::thread::Thread;
 
     use super::{slice_to_uv_buf, Loop};
 
@@ -496,10 +496,10 @@ fn test_slice_to_uv_buf() {
 
     #[test]
     fn loop_smoke_test() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let mut loop_ = Loop::new();
             loop_.run();
             loop_.close();
-        });
+        }).join();
     }
 }
index 8e827703cb2b8985de8a3b685ea6915dc86227cf..deb7036848f96413bd1c26c7038f8eebda416f9e 100644 (file)
@@ -28,9 +28,7 @@ macro_rules! uvdebug (
 )
 
 pub fn dumb_println(args: &fmt::Arguments) {
-    use std::io;
     use std::rt;
-
     let mut w = rt::Stderr;
-    let _ = fmt::writeln(&mut w as &mut io::Writer, args);
+    let _ = writeln!(&mut w, "{}", args);
 }
index 798c9ac3cab169140936377eac56d78b037bed01..0b31010020be15e362364111fe240b0861165661 100644 (file)
@@ -851,7 +851,7 @@ mod test {
     fn connect_close_ip4() {
         match TcpWatcher::connect(local_loop(), next_test_ip4(), None) {
             Ok(..) => fail!(),
-            Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_owned()),
+            Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_strbuf()),
         }
     }
 
@@ -859,7 +859,7 @@ fn connect_close_ip4() {
     fn connect_close_ip6() {
         match TcpWatcher::connect(local_loop(), next_test_ip6(), None) {
             Ok(..) => fail!(),
-            Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_owned()),
+            Err(e) => assert_eq!(e.name(), "ECONNREFUSED".to_strbuf()),
         }
     }
 
index ba39f8a7f5f32fbbf5d4f10b7832169e05024631..cf3035c742c36d6e8ab1fc73235e622982d7174c 100644 (file)
@@ -338,7 +338,7 @@ fn connect_err() {
     fn bind_err() {
         match PipeListener::bind(local_loop(), &"path/to/nowhere".to_c_str()) {
             Ok(..) => fail!(),
-            Err(e) => assert_eq!(e.name(), "EACCES".to_owned()),
+            Err(e) => assert_eq!(e.name(), "EACCES".to_strbuf()),
         }
     }
 
index 7afac6801519b652fe9453886c004164ced706f9..f6fcf3e48162fa138e251dc4cdb0d6e62862f6bc 100644 (file)
@@ -13,7 +13,8 @@
 use std::io::IoError;
 use std::io::process;
 use std::ptr;
-use std::rt::rtio::RtioProcess;
+use std::c_str::CString;
+use std::rt::rtio::{ProcessConfig, RtioProcess};
 use std::rt::task::BlockedTask;
 
 use homing::{HomingIO, HomeHandle};
@@ -50,12 +51,10 @@ impl Process {
     ///
     /// Returns either the corresponding process object or an error which
     /// occurred.
-    pub fn spawn(io_loop: &mut UvIoFactory, config: process::ProcessConfig)
-                -> Result<(Box<Process>, Vec<Option<PipeWatcher>>), UvError>
-    {
-        let cwd = config.cwd.map(|s| s.to_c_str());
-        let mut io = vec![config.stdin, config.stdout, config.stderr];
-        for slot in config.extra_io.iter() {
+    pub fn spawn(io_loop: &mut UvIoFactory, cfg: ProcessConfig)
+                -> Result<(Box<Process>, Vec<Option<PipeWatcher>>), UvError> {
+        let mut io = vec![cfg.stdin, cfg.stdout, cfg.stderr];
+        for slot in cfg.extra_io.iter() {
             io.push(*slot);
         }
         let mut stdio = Vec::<uvll::uv_stdio_container_t>::with_capacity(io.len());
@@ -69,16 +68,16 @@ pub fn spawn(io_loop: &mut UvIoFactory, config: process::ProcessConfig)
             }
         }
 
-        let ret = with_argv(config.program, config.args, |argv| {
-            with_env(config.env, |envp| {
+        let ret = with_argv(cfg.program, cfg.args, |argv| {
+            with_env(cfg.env, |envp| {
                 let mut flags = 0;
-                if config.uid.is_some() {
+                if cfg.uid.is_some() {
                     flags |= uvll::PROCESS_SETUID;
                 }
-                if config.gid.is_some() {
+                if cfg.gid.is_some() {
                     flags |= uvll::PROCESS_SETGID;
                 }
-                if config.detach {
+                if cfg.detach {
                     flags |= uvll::PROCESS_DETACHED;
                 }
                 let options = uvll::uv_process_options_t {
@@ -86,15 +85,15 @@ pub fn spawn(io_loop: &mut UvIoFactory, config: process::ProcessConfig)
                     file: unsafe { *argv },
                     args: argv,
                     env: envp,
-                    cwd: match cwd {
-                        Some(ref cwd) => cwd.with_ref(|p| p),
+                    cwd: match cfg.cwd {
+                        Some(cwd) => cwd.with_ref(|p| p),
                         None => ptr::null(),
                     },
                     flags: flags as libc::c_uint,
                     stdio_count: stdio.len() as libc::c_int,
                     stdio: stdio.as_ptr(),
-                    uid: config.uid.unwrap_or(0) as uvll::uv_uid_t,
-                    gid: config.gid.unwrap_or(0) as uvll::uv_gid_t,
+                    uid: cfg.uid.unwrap_or(0) as uvll::uv_uid_t,
+                    gid: cfg.gid.unwrap_or(0) as uvll::uv_gid_t,
                 };
 
                 let handle = UvHandle::alloc(None::<Process>, uvll::UV_PROCESS);
@@ -175,42 +174,53 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
     }
 }
 
-/// Converts the program and arguments to the argv array expected by libuv
-fn with_argv<T>(prog: &str, args: &[~str], f: |**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());
-    }
+/// Converts the program and arguments to the argv array expected by libuv.
+fn with_argv<T>(prog: &CString, args: &[CString], cb: |**libc::c_char| -> T) -> T {
+    let mut ptrs: Vec<*libc::c_char> = Vec::with_capacity(args.len()+1);
 
-    // 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());
-    f(c_args.as_ptr())
+    // Convert the CStrings into an array of pointers. Note: the
+    // lifetime of the various CStrings involved is guaranteed to be
+    // larger than the lifetime of our invocation of cb, but this is
+    // technically unsafe as the callback could leak these pointers
+    // out of our scope.
+    ptrs.push(prog.with_ref(|buf| buf));
+    ptrs.extend(args.iter().map(|tmp| tmp.with_ref(|buf| buf)));
+
+    // Add a terminating null pointer (required by libc).
+    ptrs.push(ptr::null());
+
+    cb(ptrs.as_ptr())
 }
 
 /// Converts the environment to the env array expected by libuv
-fn with_env<T>(env: Option<&[(~str, ~str)]>, f: |**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(format!("{}={}", *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));
+fn with_env<T>(env: Option<&[(CString, CString)]>, cb: |**libc::c_char| -> T) -> T {
+    // We can pass a char** for envp, which is a null-terminated array
+    // of "k=v\0" strings. Since we must create these strings locally,
+    // yet expose a raw pointer to them, we create a temporary vector
+    // to own the CStrings that outlives the call to cb.
+    match env {
+        Some(env) => {
+            let mut tmps = Vec::with_capacity(env.len());
+
+            for pair in env.iter() {
+                let mut kv = Vec::new();
+                kv.push_all(pair.ref0().as_bytes_no_nul());
+                kv.push('=' as u8);
+                kv.push_all(pair.ref1().as_bytes()); // includes terminal \0
+                tmps.push(kv);
+            }
+
+            // As with `with_argv`, this is unsafe, since cb could leak the pointers.
+            let mut ptrs: Vec<*libc::c_char> =
+                tmps.iter()
+                    .map(|tmp| tmp.as_ptr() as *libc::c_char)
+                    .collect();
+            ptrs.push(ptr::null());
+
+            cb(ptrs.as_ptr())
+        }
+        _ => cb(ptr::null())
     }
-    c_envp.push(ptr::null());
-    f(c_envp.as_ptr())
 }
 
 impl HomingIO for Process {
index c42b17cc3256e92787060891e4a1792f02c51146..71589e00fc008e5f08f68877a0e750be5db757d7 100644 (file)
@@ -13,7 +13,6 @@
 use std::c_str::CString;
 use std::io::IoError;
 use std::io::net::ip::SocketAddr;
-use std::io::process::ProcessConfig;
 use std::io::signal::Signum;
 use std::io::{FileMode, FileAccess, Open, Append, Truncate, Read, Write,
               ReadWrite, FileStat};
 use libc;
 use std::path::Path;
 use std::rt::rtio;
-use std::rt::rtio::{IoFactory, EventLoop};
+use std::rt::rtio::{ProcessConfig, IoFactory, EventLoop};
 use ai = std::io::net::addrinfo;
 
-#[cfg(test)] use std::unstable::run_in_bare_thread;
+#[cfg(test)] use std::rt::thread::Thread;
 
 use super::{uv_error_to_io_error, Loop};
 
@@ -117,7 +116,7 @@ fn has_active_io(&self) -> bool {
 
 #[test]
 fn test_callback_run_once() {
-    run_in_bare_thread(proc() {
+    Thread::start(proc() {
         let mut event_loop = UvEventLoop::new();
         let mut count = 0;
         let count_ptr: *mut int = &mut count;
@@ -126,7 +125,7 @@ fn test_callback_run_once() {
         });
         event_loop.run();
         assert_eq!(count, 1);
-    });
+    }).join();
 }
 
 pub struct UvIoFactory {
@@ -270,12 +269,12 @@ fn fs_utime(&mut self, path: &CString, atime: u64, mtime: u64)
         r.map_err(uv_error_to_io_error)
     }
 
-    fn spawn(&mut self, config: ProcessConfig)
+    fn spawn(&mut self, cfg: ProcessConfig)
             -> Result<(Box<rtio::RtioProcess:Send>,
                        Vec<Option<Box<rtio::RtioPipe:Send>>>),
                       IoError>
     {
-        match Process::spawn(self, config) {
+        match Process::spawn(self, cfg) {
             Ok((p, io)) => {
                 Ok((p as Box<rtio::RtioProcess:Send>,
                     io.move_iter().map(|i| i.map(|p| {
index 3035b305617879d6fa62300c1ad07be5417e9066..2f1d59b23a280b8326a68eee0ecb245d8668ed00 100644 (file)
@@ -96,18 +96,18 @@ pub struct Version {
 impl fmt::Show for Version {
     #[inline]
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, "{}.{}.{}", self.major, self.minor, self.patch))
+        try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch))
         if !self.pre.is_empty() {
-            try!(write!(f.buf, "-"));
+            try!(write!(f, "-"));
             for (i, x) in self.pre.iter().enumerate() {
-                if i != 0 { try!(write!(f.buf, ".")) };
+                if i != 0 { try!(write!(f, ".")) };
                 try!(x.fmt(f));
             }
         }
         if !self.build.is_empty() {
-            try!(write!(f.buf, "+"));
+            try!(write!(f, "+"));
             for (i, x) in self.build.iter().enumerate() {
-                if i != 0 { try!(write!(f.buf, ".")) };
+                if i != 0 { try!(write!(f, ".")) };
                 try!(x.fmt(f));
             }
         }
index 4709365ebff533fe7d0647fbfee3f2720c40cb85..2d938bc9ae77eceaa01b02bfb00c4f9450f88d9a 100644 (file)
@@ -54,7 +54,7 @@ pub struct Config {
 pub trait ToBase64 {
     /// Converts the value of `self` to a base64 value following the specified
     /// format configuration, returning the owned string.
-    fn to_base64(&self, config: Config) -> ~str;
+    fn to_base64(&self, config: Config) -> StrBuf;
 }
 
 impl<'a> ToBase64 for &'a [u8] {
@@ -73,7 +73,7 @@ impl<'a> ToBase64 for &'a [u8] {
      * }
      * ```
      */
-    fn to_base64(&self, config: Config) -> ~str {
+    fn to_base64(&self, config: Config) -> StrBuf {
         let bytes = match config.char_set {
             Standard => STANDARD_CHARS,
             UrlSafe => URLSAFE_CHARS
@@ -146,7 +146,7 @@ fn to_base64(&self, config: Config) -> ~str {
         }
 
         unsafe {
-            str::raw::from_utf8(v.as_slice()).to_owned()
+            str::raw::from_utf8(v.as_slice()).to_strbuf()
         }
     }
 }
@@ -170,8 +170,8 @@ impl fmt::Show for FromBase64Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             InvalidBase64Character(ch, idx) =>
-                write!(f.buf, "Invalid character '{}' at position {}", ch, idx),
-            InvalidBase64Length => write!(f.buf, "Invalid length"),
+                write!(f, "Invalid character '{}' at position {}", ch, idx),
+            InvalidBase64Length => write!(f, "Invalid length"),
         }
     }
 }
@@ -181,9 +181,8 @@ impl<'a> FromBase64 for &'a str {
      * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
      * to the byte values it encodes.
      *
-     * You can use the `from_utf8_owned` function in `std::str`
-     * to turn a `[u8]` into a string with characters corresponding to those
-     * values.
+     * You can use the `StrBuf::from_utf8` function in `std::strbuf` to turn a
+     * `Vec<u8>` into a string with characters corresponding to those values.
      *
      * # Example
      *
@@ -196,10 +195,10 @@ impl<'a> FromBase64 for &'a str {
      * fn main () {
      *     let hello_str = bytes!("Hello, World").to_base64(STANDARD);
      *     println!("base64 output: {}", hello_str);
-     *     let res = hello_str.from_base64();
+     *     let res = hello_str.as_slice().from_base64();
      *     if res.is_ok() {
      *       let opt_bytes = StrBuf::from_utf8(res.unwrap());
-     *       if opt_bytes.is_some() {
+     *       if opt_bytes.is_ok() {
      *         println!("decoded from base64: {}", opt_bytes.unwrap());
      *       }
      *     }
@@ -268,34 +267,35 @@ mod tests {
 
     #[test]
     fn test_to_base64_basic() {
-        assert_eq!("".as_bytes().to_base64(STANDARD), "".to_owned());
-        assert_eq!("f".as_bytes().to_base64(STANDARD), "Zg==".to_owned());
-        assert_eq!("fo".as_bytes().to_base64(STANDARD), "Zm8=".to_owned());
-        assert_eq!("foo".as_bytes().to_base64(STANDARD), "Zm9v".to_owned());
-        assert_eq!("foob".as_bytes().to_base64(STANDARD), "Zm9vYg==".to_owned());
-        assert_eq!("fooba".as_bytes().to_base64(STANDARD), "Zm9vYmE=".to_owned());
-        assert_eq!("foobar".as_bytes().to_base64(STANDARD), "Zm9vYmFy".to_owned());
+        assert_eq!("".as_bytes().to_base64(STANDARD), "".to_strbuf());
+        assert_eq!("f".as_bytes().to_base64(STANDARD), "Zg==".to_strbuf());
+        assert_eq!("fo".as_bytes().to_base64(STANDARD), "Zm8=".to_strbuf());
+        assert_eq!("foo".as_bytes().to_base64(STANDARD), "Zm9v".to_strbuf());
+        assert_eq!("foob".as_bytes().to_base64(STANDARD), "Zm9vYg==".to_strbuf());
+        assert_eq!("fooba".as_bytes().to_base64(STANDARD), "Zm9vYmE=".to_strbuf());
+        assert_eq!("foobar".as_bytes().to_base64(STANDARD), "Zm9vYmFy".to_strbuf());
     }
 
     #[test]
     fn test_to_base64_line_break() {
         assert!(![0u8, ..1000].to_base64(Config {line_length: None, ..STANDARD})
-                .contains("\r\n"));
+                              .as_slice()
+                              .contains("\r\n"));
         assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
                                                          ..STANDARD}),
-                   "Zm9v\r\nYmFy".to_owned());
+                   "Zm9v\r\nYmFy".to_strbuf());
     }
 
     #[test]
     fn test_to_base64_padding() {
-        assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg".to_owned());
-        assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zm8".to_owned());
+        assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zg".to_strbuf());
+        assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), "Zm8".to_strbuf());
     }
 
     #[test]
     fn test_to_base64_url_safe() {
-        assert_eq!([251, 255].to_base64(URL_SAFE), "-_8".to_owned());
-        assert_eq!([251, 255].to_base64(STANDARD), "+/8=".to_owned());
+        assert_eq!([251, 255].to_base64(URL_SAFE), "-_8".to_strbuf());
+        assert_eq!([251, 255].to_base64(STANDARD), "+/8=".to_strbuf());
     }
 
     #[test]
@@ -340,7 +340,12 @@ fn test_base64_random() {
         for _ in range(0, 1000) {
             let times = task_rng().gen_range(1u, 100);
             let v = Vec::from_fn(times, |_| random::<u8>());
-            assert_eq!(v.as_slice().to_base64(STANDARD).from_base64().unwrap().as_slice(),
+            assert_eq!(v.as_slice()
+                        .to_base64(STANDARD)
+                        .as_slice()
+                        .from_base64()
+                        .unwrap()
+                        .as_slice(),
                        v.as_slice());
         }
     }
@@ -361,7 +366,7 @@ pub fn bench_from_base64(b: &mut Bencher) {
                  ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
         let sb = s.as_bytes().to_base64(STANDARD);
         b.iter(|| {
-            sb.from_base64().unwrap();
+            sb.as_slice().from_base64().unwrap();
         });
         b.bytes = sb.len() as u64;
     }
index ea506931d76eef7350f22cf0f06b8d7ab4c6be08..104efbeab0a3cd61ff45459399c8ca3a3311af93 100644 (file)
@@ -34,8 +34,8 @@ pub fn as_str_slice<'a>(&'a self) -> &'a str {
         str::from_utf8(self.data.slice(self.start, self.end)).unwrap()
     }
 
-    pub fn as_str(&self) -> ~str {
-        self.as_str_slice().to_owned()
+    pub fn as_str(&self) -> StrBuf {
+        self.as_str_slice().to_strbuf()
     }
 }
 
@@ -80,7 +80,7 @@ pub enum EbmlEncoderTag {
 #[deriving(Show)]
 pub enum Error {
     IntTooBig(uint),
-    Expected(~str),
+    Expected(StrBuf),
     IoError(io::IoError)
 }
 // --------------------------------------
@@ -312,7 +312,10 @@ fn _check_label(&mut self, lbl: &str) -> DecodeResult<()> {
                     self.pos = r_doc.end;
                     let str = r_doc.as_str_slice();
                     if lbl != str {
-                        return Err(Expected(format!("Expected label {} but found {}", lbl, str)));
+                        return Err(Expected(format_strbuf!("Expected label \
+                                                            {} but found {}",
+                                                           lbl,
+                                                           str)));
                     }
                 }
             }
@@ -322,7 +325,8 @@ fn _check_label(&mut self, lbl: &str) -> DecodeResult<()> {
         fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> {
             debug!(". next_doc(exp_tag={:?})", exp_tag);
             if self.pos >= self.parent.end {
-                return Err(Expected(format!("no more documents in current node!")));
+                return Err(Expected(format_strbuf!("no more documents in \
+                                                    current node!")));
             }
             let TaggedDoc { tag: r_tag, doc: r_doc } =
                 try!(doc_at(self.parent.data, self.pos));
@@ -334,12 +338,18 @@ fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult<Doc<'doc>> {
                    r_doc.start,
                    r_doc.end);
             if r_tag != (exp_tag as uint) {
-                return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}",
-                       exp_tag, r_tag)));
+                return Err(Expected(format_strbuf!("expected EBML doc with \
+                                                    tag {:?} but found tag \
+                                                    {:?}",
+                                                   exp_tag,
+                                                   r_tag)));
             }
             if r_doc.end > self.parent.end {
-                return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to {:#x}",
-                      r_doc.end, self.parent.end)));
+                return Err(Expected(format_strbuf!("invalid EBML, child \
+                                                    extends to {:#x}, parent \
+                                                    to {:#x}",
+                                                   r_doc.end,
+                                                   self.parent.end)));
             }
             self.pos = r_doc.end;
             Ok(r_doc)
@@ -433,7 +443,7 @@ fn read_f32(&mut self) -> DecodeResult<f32> {
         fn read_char(&mut self) -> DecodeResult<char> {
             Ok(char::from_u32(doc_as_u32(try!(self.next_doc(EsChar)))).unwrap())
         }
-        fn read_str(&mut self) -> DecodeResult<~str> {
+        fn read_str(&mut self) -> DecodeResult<StrBuf> {
             Ok(try!(self.next_doc(EsStr)).as_str())
         }
 
@@ -570,7 +580,10 @@ fn read_option<T>(&mut self,
                     match idx {
                         0 => f(this, false),
                         1 => f(this, true),
-                        _ => Err(Expected(format!("Expected None or Some"))),
+                        _ => {
+                            Err(Expected(format_strbuf!("Expected None or \
+                                                         Some")))
+                        }
                     }
                 })
             })
index c463d97dba4d48fe960b36f79c1621615de10852..3b8500753cb3f5170b7d3120152395413f9ddece 100644 (file)
@@ -16,7 +16,7 @@
 pub trait ToHex {
     /// Converts the value of `self` to a hex value, returning the owned
     /// string.
-    fn to_hex(&self) -> ~str;
+    fn to_hex(&self) -> StrBuf;
 }
 
 static CHARS: &'static[u8] = bytes!("0123456789abcdef");
@@ -37,7 +37,7 @@ impl<'a> ToHex for &'a [u8] {
      * }
      * ```
      */
-    fn to_hex(&self) -> ~str {
+    fn to_hex(&self) -> StrBuf {
         let mut v = Vec::with_capacity(self.len() * 2);
         for &byte in self.iter() {
             v.push(CHARS[(byte >> 4) as uint]);
@@ -45,7 +45,7 @@ fn to_hex(&self) -> ~str {
         }
 
         unsafe {
-            str::raw::from_utf8(v.as_slice()).to_owned()
+            str::raw::from_utf8(v.as_slice()).to_strbuf()
         }
     }
 }
@@ -69,8 +69,8 @@ impl fmt::Show for FromHexError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             InvalidHexCharacter(ch, idx) =>
-                write!(f.buf, "Invalid character '{}' at position {}", ch, idx),
-            InvalidHexLength => write!(f.buf, "Invalid input length"),
+                write!(f, "Invalid character '{}' at position {}", ch, idx),
+            InvalidHexLength => write!(f, "Invalid input length"),
         }
     }
 }
@@ -80,9 +80,8 @@ impl<'a> FromHex for &'a str {
      * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
      * to the byte values it encodes.
      *
-     * You can use the `from_utf8_owned` function in `std::str`
-     * to turn a `[u8]` into a string with characters corresponding to those
-     * values.
+     * You can use the `StrBuf::from_utf8` function in `std::strbuf` to turn a
+     * `Vec<u8>` into a string with characters corresponding to those values.
      *
      * # Example
      *
@@ -95,7 +94,7 @@ impl<'a> FromHex for &'a str {
      * fn main () {
      *     let hello_str = "Hello, World".as_bytes().to_hex();
      *     println!("{}", hello_str);
-     *     let bytes = hello_str.from_hex().unwrap();
+     *     let bytes = hello_str.as_slice().from_hex().unwrap();
      *     println!("{:?}", bytes);
      *     let result_str = StrBuf::from_utf8(bytes).unwrap();
      *     println!("{}", result_str);
@@ -144,7 +143,7 @@ mod tests {
 
     #[test]
     pub fn test_to_hex() {
-        assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172".to_owned());
+        assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172".to_strbuf());
     }
 
     #[test]
@@ -175,7 +174,8 @@ pub fn test_from_hex_ignores_whitespace() {
     #[test]
     pub fn test_to_hex_all_bytes() {
         for i in range(0, 256) {
-            assert_eq!([i as u8].to_hex(), format!("{:02x}", i as uint));
+            assert_eq!([i as u8].to_hex(),
+                       format_strbuf!("{:02x}", i as uint));
         }
     }
 
@@ -203,7 +203,7 @@ pub fn bench_from_hex(b: &mut Bencher) {
                  ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
         let sb = s.as_bytes().to_hex();
         b.iter(|| {
-            sb.from_hex().unwrap();
+            sb.as_slice().from_hex().unwrap();
         });
         b.bytes = sb.len() as u64;
     }
index bf04f10fcf0d337a6b6d0c58b7c88ead3a0b100c..422914b1405706bf60ff1d9681890c7009ca18c5 100644 (file)
 
  #[deriving(Encodable)]
  pub struct TestStruct   {
-    data_str: ~str,
+    data_str: StrBuf,
  }
 
 fn main() {
-    let to_encode_object = TestStruct{data_str:"example of string to encode".to_owned()};
+    let to_encode_object = TestStruct{data_str:"example of string to encode".to_strbuf()};
     let mut m = io::MemWriter::new();
     {
         let mut encoder = json::Encoder::new(&mut m as &mut std::io::Writer);
@@ -81,12 +81,12 @@ fn main() {
 ```
 
 Two wrapper functions are provided to encode a Encodable object
-into a string (~str) or buffer (~[u8]): `str_encode(&m)` and `buffer_encode(&m)`.
+into a string (StrBuf) or buffer (~[u8]): `str_encode(&m)` and `buffer_encode(&m)`.
 
 ```rust
 use serialize::json;
-let to_encode_object = "example of string to encode".to_owned();
-let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object);
+let to_encode_object = "example of string to encode".to_strbuf();
+let encoded_str: StrBuf = json::Encoder::str_encode(&to_encode_object);
 ```
 
 JSON API provide an enum `json::Json` and a trait `ToJson` to encode object.
@@ -108,22 +108,22 @@ fn main() {
 
 pub struct MyStruct  {
     attr1: u8,
-    attr2: ~str,
+    attr2: StrBuf,
 }
 
 impl ToJson for MyStruct {
     fn to_json( &self ) -> json::Json {
         let mut d = box TreeMap::new();
-        d.insert("attr1".to_owned(), self.attr1.to_json());
-        d.insert("attr2".to_owned(), self.attr2.to_json());
+        d.insert("attr1".to_strbuf(), self.attr1.to_json());
+        d.insert("attr2".to_strbuf(), self.attr2.to_json());
         json::Object(d)
     }
 }
 
 fn main() {
-    let test2: MyStruct = MyStruct {attr1: 1, attr2:"test".to_owned()};
+    let test2: MyStruct = MyStruct {attr1: 1, attr2:"test".to_strbuf()};
     let tjson: json::Json = test2.to_json();
-    let json_str: ~str = tjson.to_str();
+    let json_str: StrBuf = tjson.to_str().into_strbuf();
 }
 ```
 
@@ -136,13 +136,13 @@ fn main() {
 #[deriving(Decodable)]
 pub struct MyStruct  {
      attr1: u8,
-     attr2: ~str,
+     attr2: StrBuf,
 }
 
 fn main() {
-    let json_str_to_decode: ~str =
-            "{\"attr1\":1,\"attr2\":\"toto\"}".to_owned();
-    let json_object = json::from_str(json_str_to_decode);
+    let json_str_to_decode: StrBuf =
+            "{\"attr1\":1,\"attr2\":\"toto\"}".to_strbuf();
+    let json_object = json::from_str(json_str_to_decode.as_slice());
     let mut decoder = json::Decoder::new(json_object.unwrap());
     let decoded_object: MyStruct = match Decodable::decode(&mut decoder) {
         Ok(v) => v,
@@ -165,7 +165,7 @@ fn main() {
  #[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl.
  pub struct TestStruct1  {
     data_int: u8,
-    data_str: ~str,
+    data_str: StrBuf,
     data_vector: Vec<u8>,
  }
 
@@ -173,12 +173,12 @@ pub struct TestStruct1  {
 // It calls the generated `Encodable` impl.
 fn main() {
     let to_encode_object = TestStruct1
-         {data_int: 1, data_str:"toto".to_owned(), data_vector:vec![2,3,4,5]};
-    let encoded_str: ~str = json::Encoder::str_encode(&to_encode_object);
+         {data_int: 1, data_str:"toto".to_strbuf(), data_vector:vec![2,3,4,5]};
+    let encoded_str: StrBuf = json::Encoder::str_encode(&to_encode_object);
 
     // To deserialize use the `json::from_str` and `json::Decoder`
 
-    let json_object = json::from_str(encoded_str);
+    let json_object = json::from_str(encoded_str.as_slice());
     let mut decoder = json::Decoder::new(json_object.unwrap());
     let decoded1: TestStruct1 = Decodable::decode(&mut decoder).unwrap(); // create the final object
 }
@@ -200,16 +200,16 @@ fn main() {
 #[deriving(Decodable, Encodable)] // generate Decodable, Encodable impl.
 pub struct TestStruct1  {
     data_int: u8,
-    data_str: ~str,
+    data_str: StrBuf,
     data_vector: Vec<u8>,
 }
 
 impl ToJson for TestStruct1 {
     fn to_json( &self ) -> json::Json {
         let mut d = box TreeMap::new();
-        d.insert("data_int".to_owned(), self.data_int.to_json());
-        d.insert("data_str".to_owned(), self.data_str.to_json());
-        d.insert("data_vector".to_owned(), self.data_vector.to_json());
+        d.insert("data_int".to_strbuf(), self.data_int.to_json());
+        d.insert("data_str".to_strbuf(), self.data_str.to_json());
+        d.insert("data_vector".to_strbuf(), self.data_vector.to_json());
         json::Object(d)
     }
 }
@@ -217,14 +217,15 @@ fn to_json( &self ) -> json::Json {
 fn main() {
     // Serialization using our impl of to_json
 
-    let test2: TestStruct1 = TestStruct1 {data_int: 1, data_str:"toto".to_owned(),
+    let test2: TestStruct1 = TestStruct1 {data_int: 1, data_str:"toto".to_strbuf(),
                                           data_vector:vec![2,3,4,5]};
     let tjson: json::Json = test2.to_json();
-    let json_str: ~str = tjson.to_str();
+    let json_str: StrBuf = tjson.to_str().into_strbuf();
 
     // Deserialize like before.
 
-    let mut decoder = json::Decoder::new(json::from_str(json_str).unwrap());
+    let mut decoder =
+        json::Decoder::new(json::from_str(json_str.as_slice()).unwrap());
     // create the final object
     let decoded2: TestStruct1 = Decodable::decode(&mut decoder).unwrap();
 }
@@ -251,7 +252,7 @@ fn main() {
 #[deriving(Clone, Eq)]
 pub enum Json {
     Number(f64),
-    String(~str),
+    String(StrBuf),
     Boolean(bool),
     List(List),
     Object(Box<Object>),
@@ -259,7 +260,7 @@ pub enum Json {
 }
 
 pub type List = Vec<Json>;
-pub type Object = TreeMap<~str, Json>;
+pub type Object = TreeMap<StrBuf, Json>;
 
 /// The errors that can arise while parsing a JSON stream.
 #[deriving(Clone, Eq)]
@@ -295,9 +296,9 @@ pub enum ParserError {
 #[deriving(Clone, Eq, Show)]
 pub enum DecoderError {
     ParseError(ParserError),
-    ExpectedError(~str, ~str),
-    MissingFieldError(~str),
-    UnknownVariantError(~str),
+    ExpectedError(StrBuf, StrBuf),
+    MissingFieldError(StrBuf),
+    UnknownVariantError(StrBuf),
 }
 
 /// Returns a readable error string for a given error code.
@@ -336,7 +337,7 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
 pub type EncodeResult = io::IoResult<()>;
 pub type DecodeResult<T> = Result<T, DecoderError>;
 
-fn escape_str(s: &str) -> ~str {
+fn escape_str(s: &str) -> StrBuf {
     let mut escaped = StrBuf::from_str("\"");
     for c in s.chars() {
         match c {
@@ -351,15 +352,15 @@ fn escape_str(s: &str) -> ~str {
         }
     };
     escaped.push_char('"');
-    escaped.into_owned()
+    escaped
 }
 
-fn spaces(n: uint) -> ~str {
+fn spaces(n: uint) -> StrBuf {
     let mut ss = StrBuf::new();
     for _ in range(0, n) {
         ss.push_str(" ");
     }
-    return ss.into_owned();
+    return ss
 }
 
 /// A structure for implementing serialization to JSON.
@@ -387,9 +388,12 @@ pub fn buffer_encode<T:Encodable<Encoder<'a>, io::IoError>>(to_encode_object: &T
     }
 
     /// Encode the specified struct into a json str
-    pub fn str_encode<T:Encodable<Encoder<'a>, io::IoError>>(to_encode_object: &T) -> ~str  {
+    pub fn str_encode<T:Encodable<Encoder<'a>,
+                        io::IoError>>(
+                      to_encode_object: &T)
+                      -> StrBuf {
         let buff = Encoder::buffer_encode(to_encode_object);
-        str::from_utf8(buff.as_slice()).unwrap().to_owned()
+        str::from_utf8(buff.as_slice()).unwrap().to_strbuf()
     }
 }
 
@@ -826,15 +830,15 @@ pub fn to_pretty_writer(&self, wr: &mut io::Writer) -> EncodeResult {
     }
 
     /// Encodes a json value into a string
-    pub fn to_pretty_str(&self) -> ~str {
+    pub fn to_pretty_str(&self) -> StrBuf {
         let mut s = MemWriter::new();
         self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
-        str::from_utf8(s.unwrap().as_slice()).unwrap().to_owned()
+        str::from_utf8(s.unwrap().as_slice()).unwrap().to_strbuf()
     }
 
      /// If the Json value is an Object, returns the value associated with the provided key.
     /// Otherwise, returns None.
-    pub fn find<'a>(&'a self, key: &~str) -> Option<&'a Json>{
+    pub fn find<'a>(&'a self, key: &StrBuf) -> Option<&'a Json>{
         match self {
             &Object(ref map) => map.find(key),
             _ => None
@@ -844,7 +848,7 @@ pub fn find<'a>(&'a self, key: &~str) -> Option<&'a Json>{
     /// Attempts to get a nested Json Object for each key in `keys`.
     /// If any key is found not to exist, find_path will return None.
     /// Otherwise, it will return the Json value associated with the final key.
-    pub fn find_path<'a>(&'a self, keys: &[&~str]) -> Option<&'a Json>{
+    pub fn find_path<'a>(&'a self, keys: &[&StrBuf]) -> Option<&'a Json>{
         let mut target = self;
         for key in keys.iter() {
             match target.find(*key) {
@@ -858,7 +862,7 @@ pub fn find_path<'a>(&'a self, keys: &[&~str]) -> Option<&'a Json>{
     /// If the Json value is an Object, performs a depth-first search until
     /// a value associated with the provided key is found. If no value is found
     /// or the Json value is not an Object, returns None.
-    pub fn search<'a>(&'a self, key: &~str) -> Option<&'a Json> {
+    pub fn search<'a>(&'a self, key: &StrBuf) -> Option<&'a Json> {
         match self {
             &Object(ref map) => {
                 match map.find(key) {
@@ -973,7 +977,7 @@ pub enum JsonEvent {
     ListEnd,
     BooleanValue(bool),
     NumberValue(f64),
-    StringValue(~str),
+    StringValue(StrBuf),
     NullValue,
     Error(ParserError),
 }
@@ -1091,7 +1095,7 @@ pub fn top<'l>(&'l self) -> Option<StackElement<'l>> {
     }
 
     // Used by Parser to insert Key elements at the top of the stack.
-    fn push_key(&mut self, key: ~str) {
+    fn push_key(&mut self, key: StrBuf) {
         self.stack.push(InternalKey(self.str_buffer.len() as u16, key.len() as u16));
         for c in key.as_bytes().iter() {
             self.str_buffer.push(*c);
@@ -1378,7 +1382,7 @@ fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
         Ok(n)
     }
 
-    fn parse_str(&mut self) -> Result<~str, ParserError> {
+    fn parse_str(&mut self) -> Result<StrBuf, ParserError> {
         let mut escape = false;
         let mut res = StrBuf::new();
 
@@ -1462,7 +1466,7 @@ fn parse_str(&mut self) -> Result<~str, ParserError> {
                 match self.ch {
                     Some('"') => {
                         self.bump();
-                        return Ok(res.into_owned());
+                        return Ok(res);
                     },
                     Some(c) => res.push_char(c),
                     None => unreachable!()
@@ -1738,7 +1742,7 @@ fn build_value(&mut self) -> Result<Json, BuilderError> {
             Some(NumberValue(n)) => { Ok(Number(n)) }
             Some(BooleanValue(b)) => { Ok(Boolean(b)) }
             Some(StringValue(ref mut s)) => {
-                let mut temp = "".to_owned();
+                let mut temp = StrBuf::new();
                 swap(s, &mut temp);
                 Ok(String(temp))
             }
@@ -1780,7 +1784,7 @@ fn build_object(&mut self) -> Result<Json, BuilderError> {
                 _ => {}
             }
             let key = match self.parser.stack().top() {
-                Some(Key(k)) => { k.into_owned() }
+                Some(Key(k)) => { k.to_strbuf() }
                 _ => { fail!("invalid state"); }
             };
             match self.build_value() {
@@ -1801,10 +1805,10 @@ pub fn from_reader(rdr: &mut io::Reader) -> Result<Json, BuilderError> {
         Err(e) => return Err(io_error_to_error(e))
     };
     let s = match str::from_utf8(contents.as_slice()) {
-        Some(s) => s.to_owned(),
+        Some(s) => s.to_strbuf(),
         None => return Err(SyntaxError(NotUtf8, 0, 0))
     };
-    let mut builder = Builder::new(s.chars());
+    let mut builder = Builder::new(s.as_slice().chars());
     builder.build()
 }
 
@@ -1838,13 +1842,17 @@ macro_rules! expect(
     ($e:expr, Null) => ({
         match $e {
             Null => Ok(()),
-            other => Err(ExpectedError("Null".to_owned(), format!("{}", other)))
+            other => Err(ExpectedError("Null".to_strbuf(),
+                                       format_strbuf!("{}", other)))
         }
     });
     ($e:expr, $t:ident) => ({
         match $e {
             $t(v) => Ok(v),
-            other => Err(ExpectedError(stringify!($t).to_owned(), format!("{}", other)))
+            other => {
+                Err(ExpectedError(stringify!($t).to_strbuf(),
+                                  format_strbuf!("{}", other)))
+            }
         }
     })
 )
@@ -1881,9 +1889,12 @@ fn read_f64(&mut self) -> DecodeResult<f64> {
             String(s) => {
                 // re: #12967.. a type w/ numeric keys (ie HashMap<uint, V> etc)
                 // is going to have a string here, as per JSON spec..
-                Ok(FromStr::from_str(s).unwrap())
+                Ok(FromStr::from_str(s.as_slice()).unwrap())
             },
-            value => Err(ExpectedError("Number".to_owned(), format!("{}", value)))
+            value => {
+                Err(ExpectedError("Number".to_strbuf(),
+                                  format_strbuf!("{}", value)))
+            }
         }
     }
 
@@ -1892,17 +1903,18 @@ fn read_f32(&mut self) -> DecodeResult<f32> { Ok(try!(self.read_f64()) as f32) }
     fn read_char(&mut self) -> DecodeResult<char> {
         let s = try!(self.read_str());
         {
-            let mut it = s.chars();
+            let mut it = s.as_slice().chars();
             match (it.next(), it.next()) {
                 // exactly one character
                 (Some(c), None) => return Ok(c),
                 _ => ()
             }
         }
-        Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
+        Err(ExpectedError("single character string".to_strbuf(),
+                          format_strbuf!("{}", s)))
     }
 
-    fn read_str(&mut self) -> DecodeResult<~str> {
+    fn read_str(&mut self) -> DecodeResult<StrBuf> {
         debug!("read_str");
         Ok(try!(expect!(self.pop(), String)))
     }
@@ -1922,25 +1934,41 @@ fn read_enum_variant<T>(&mut self,
         let name = match self.pop() {
             String(s) => s,
             Object(mut o) => {
-                let n = match o.pop(&"variant".to_owned()) {
+                let n = match o.pop(&"variant".to_strbuf()) {
                     Some(String(s)) => s,
-                    Some(val) => return Err(ExpectedError("String".to_owned(), format!("{}", val))),
-                    None => return Err(MissingFieldError("variant".to_owned()))
+                    Some(val) => {
+                        return Err(ExpectedError("String".to_strbuf(),
+                                                 format_strbuf!("{}", val)))
+                    }
+                    None => {
+                        return Err(MissingFieldError("variant".to_strbuf()))
+                    }
                 };
-                match o.pop(&"fields".to_owned()) {
+                match o.pop(&"fields".to_strbuf()) {
                     Some(List(l)) => {
                         for field in l.move_iter().rev() {
                             self.stack.push(field.clone());
                         }
                     },
-                    Some(val) => return Err(ExpectedError("List".to_owned(), format!("{}", val))),
-                    None => return Err(MissingFieldError("fields".to_owned()))
+                    Some(val) => {
+                        return Err(ExpectedError("List".to_strbuf(),
+                                                 format_strbuf!("{}", val)))
+                    }
+                    None => {
+                        return Err(MissingFieldError("fields".to_strbuf()))
+                    }
                 }
                 n
             }
-            json => return Err(ExpectedError("String or Object".to_owned(), format!("{}", json)))
+            json => {
+                return Err(ExpectedError("String or Object".to_strbuf(),
+                                         format_strbuf!("{}", json)))
+            }
         };
-        let idx = match names.iter().position(|n| str::eq_slice(*n, name)) {
+        let idx = match names.iter()
+                             .position(|n| {
+                                 str::eq_slice(*n, name.as_slice())
+                             }) {
             Some(idx) => idx,
             None => return Err(UnknownVariantError(name))
         };
@@ -1990,8 +2018,8 @@ fn read_struct_field<T>(&mut self,
         debug!("read_struct_field(name={}, idx={})", name, idx);
         let mut obj = try!(expect!(self.pop(), Object));
 
-        let value = match obj.pop(&name.to_owned()) {
-            None => return Err(MissingFieldError(name.to_owned())),
+        let value = match obj.pop(&name.to_strbuf()) {
+            None => return Err(MissingFieldError(name.to_strbuf())),
             Some(json) => {
                 self.stack.push(json);
                 try!(f(self))
@@ -2199,12 +2227,8 @@ impl ToJson for bool {
     fn to_json(&self) -> Json { Boolean(*self) }
 }
 
-impl ToJson for ~str {
-    fn to_json(&self) -> Json { String((*self).clone()) }
-}
-
 impl ToJson for StrBuf {
-    fn to_json(&self) -> Json { String((*self).as_slice().into_owned()) }
+    fn to_json(&self) -> Json { String((*self).clone()) }
 }
 
 impl<A:ToJson,B:ToJson> ToJson for (A, B) {
@@ -2235,7 +2259,7 @@ impl<A:ToJson> ToJson for Vec<A> {
     fn to_json(&self) -> Json { List(self.iter().map(|elt| elt.to_json()).collect()) }
 }
 
-impl<A:ToJson> ToJson for TreeMap<~str, A> {
+impl<A:ToJson> ToJson for TreeMap<StrBuf, A> {
     fn to_json(&self) -> Json {
         let mut d = TreeMap::new();
         for (key, value) in self.iter() {
@@ -2245,7 +2269,7 @@ fn to_json(&self) -> Json {
     }
 }
 
-impl<A:ToJson> ToJson for HashMap<~str, A> {
+impl<A:ToJson> ToJson for HashMap<StrBuf, A> {
     fn to_json(&self) -> Json {
         let mut d = TreeMap::new();
         for (key, value) in self.iter() {
@@ -2267,7 +2291,7 @@ fn to_json(&self) -> Json {
 impl fmt::Show for Json {
     /// Encodes a json value into a string
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.to_writer(f.buf)
+        self.to_writer(f).map_err(|_| fmt::WriteError)
     }
 }
 
@@ -2291,14 +2315,14 @@ mod tests {
     #[deriving(Eq, Encodable, Decodable, Show)]
     enum Animal {
         Dog,
-        Frog(~str, int)
+        Frog(StrBuf, int)
     }
 
     #[deriving(Eq, Encodable, Decodable, Show)]
     struct Inner {
         a: (),
         b: uint,
-        c: Vec<~str>,
+        c: Vec<StrBuf>,
     }
 
     #[deriving(Eq, Encodable, Decodable, Show)]
@@ -2306,7 +2330,7 @@ struct Outer {
         inner: Vec<Inner>,
     }
 
-    fn mk_object(items: &[(~str, Json)]) -> Json {
+    fn mk_object(items: &[(StrBuf, Json)]) -> Json {
         let mut d = box TreeMap::new();
 
         for item in items.iter() {
@@ -2320,67 +2344,67 @@ fn mk_object(items: &[(~str, Json)]) -> Json {
 
     #[test]
     fn test_write_null() {
-        assert_eq!(Null.to_str(), "null".to_owned());
-        assert_eq!(Null.to_pretty_str(), "null".to_owned());
+        assert_eq!(Null.to_str().into_strbuf(), "null".to_strbuf());
+        assert_eq!(Null.to_pretty_str().into_strbuf(), "null".to_strbuf());
     }
 
 
     #[test]
     fn test_write_number() {
-        assert_eq!(Number(3.0).to_str(), "3".to_owned());
-        assert_eq!(Number(3.0).to_pretty_str(), "3".to_owned());
+        assert_eq!(Number(3.0).to_str().into_strbuf(), "3".to_strbuf());
+        assert_eq!(Number(3.0).to_pretty_str().into_strbuf(), "3".to_strbuf());
 
-        assert_eq!(Number(3.1).to_str(), "3.1".to_owned());
-        assert_eq!(Number(3.1).to_pretty_str(), "3.1".to_owned());
+        assert_eq!(Number(3.1).to_str().into_strbuf(), "3.1".to_strbuf());
+        assert_eq!(Number(3.1).to_pretty_str().into_strbuf(), "3.1".to_strbuf());
 
-        assert_eq!(Number(-1.5).to_str(), "-1.5".to_owned());
-        assert_eq!(Number(-1.5).to_pretty_str(), "-1.5".to_owned());
+        assert_eq!(Number(-1.5).to_str().into_strbuf(), "-1.5".to_strbuf());
+        assert_eq!(Number(-1.5).to_pretty_str().into_strbuf(), "-1.5".to_strbuf());
 
-        assert_eq!(Number(0.5).to_str(), "0.5".to_owned());
-        assert_eq!(Number(0.5).to_pretty_str(), "0.5".to_owned());
+        assert_eq!(Number(0.5).to_str().into_strbuf(), "0.5".to_strbuf());
+        assert_eq!(Number(0.5).to_pretty_str().into_strbuf(), "0.5".to_strbuf());
     }
 
     #[test]
     fn test_write_str() {
-        assert_eq!(String("".to_owned()).to_str(), "\"\"".to_owned());
-        assert_eq!(String("".to_owned()).to_pretty_str(), "\"\"".to_owned());
+        assert_eq!(String("".to_strbuf()).to_str().into_strbuf(), "\"\"".to_strbuf());
+        assert_eq!(String("".to_strbuf()).to_pretty_str().into_strbuf(), "\"\"".to_strbuf());
 
-        assert_eq!(String("foo".to_owned()).to_str(), "\"foo\"".to_owned());
-        assert_eq!(String("foo".to_owned()).to_pretty_str(), "\"foo\"".to_owned());
+        assert_eq!(String("foo".to_strbuf()).to_str().into_strbuf(), "\"foo\"".to_strbuf());
+        assert_eq!(String("foo".to_strbuf()).to_pretty_str().into_strbuf(), "\"foo\"".to_strbuf());
     }
 
     #[test]
     fn test_write_bool() {
-        assert_eq!(Boolean(true).to_str(), "true".to_owned());
-        assert_eq!(Boolean(true).to_pretty_str(), "true".to_owned());
+        assert_eq!(Boolean(true).to_str().into_strbuf(), "true".to_strbuf());
+        assert_eq!(Boolean(true).to_pretty_str().into_strbuf(), "true".to_strbuf());
 
-        assert_eq!(Boolean(false).to_str(), "false".to_owned());
-        assert_eq!(Boolean(false).to_pretty_str(), "false".to_owned());
+        assert_eq!(Boolean(false).to_str().into_strbuf(), "false".to_strbuf());
+        assert_eq!(Boolean(false).to_pretty_str().into_strbuf(), "false".to_strbuf());
     }
 
     #[test]
     fn test_write_list() {
-        assert_eq!(List(vec![]).to_str(), "[]".to_owned());
-        assert_eq!(List(vec![]).to_pretty_str(), "[]".to_owned());
+        assert_eq!(List(vec![]).to_str().into_strbuf(), "[]".to_strbuf());
+        assert_eq!(List(vec![]).to_pretty_str().into_strbuf(), "[]".to_strbuf());
 
-        assert_eq!(List(vec![Boolean(true)]).to_str(), "[true]".to_owned());
+        assert_eq!(List(vec![Boolean(true)]).to_str().into_strbuf(), "[true]".to_strbuf());
         assert_eq!(
-            List(vec![Boolean(true)]).to_pretty_str(),
+            List(vec![Boolean(true)]).to_pretty_str().into_strbuf(),
             "\
             [\n  \
                 true\n\
-            ]".to_owned()
+            ]".to_strbuf()
         );
 
         let long_test_list = List(vec![
             Boolean(false),
             Null,
-            List(vec![String("foo\nbar".to_owned()), Number(3.5)])]);
+            List(vec![String("foo\nbar".to_strbuf()), Number(3.5)])]);
 
-        assert_eq!(long_test_list.to_str(),
-            "[false,null,[\"foo\\nbar\",3.5]]".to_owned());
+        assert_eq!(long_test_list.to_str().into_strbuf(),
+            "[false,null,[\"foo\\nbar\",3.5]]".to_strbuf());
         assert_eq!(
-            long_test_list.to_pretty_str(),
+            long_test_list.to_pretty_str().into_strbuf(),
             "\
             [\n  \
                 false,\n  \
@@ -2389,45 +2413,47 @@ fn test_write_list() {
                     \"foo\\nbar\",\n    \
                     3.5\n  \
                 ]\n\
-            ]".to_owned()
+            ]".to_strbuf()
         );
     }
 
     #[test]
     fn test_write_object() {
-        assert_eq!(mk_object([]).to_str(), "{}".to_owned());
-        assert_eq!(mk_object([]).to_pretty_str(), "{}".to_owned());
+        assert_eq!(mk_object([]).to_str().into_strbuf(), "{}".to_strbuf());
+        assert_eq!(mk_object([]).to_pretty_str().into_strbuf(), "{}".to_strbuf());
 
         assert_eq!(
-            mk_object([("a".to_owned(), Boolean(true))]).to_str(),
-            "{\"a\":true}".to_owned()
+            mk_object([
+                ("a".to_strbuf(), Boolean(true))
+            ]).to_str().into_strbuf(),
+            "{\"a\":true}".to_strbuf()
         );
         assert_eq!(
-            mk_object([("a".to_owned(), Boolean(true))]).to_pretty_str(),
+            mk_object([("a".to_strbuf(), Boolean(true))]).to_pretty_str(),
             "\
             {\n  \
                 \"a\": true\n\
-            }".to_owned()
+            }".to_strbuf()
         );
 
         let complex_obj = mk_object([
-                ("b".to_owned(), List(vec![
-                    mk_object([("c".to_owned(), String("\x0c\r".to_owned()))]),
-                    mk_object([("d".to_owned(), String("".to_owned()))])
+                ("b".to_strbuf(), List(vec![
+                    mk_object([("c".to_strbuf(), String("\x0c\r".to_strbuf()))]),
+                    mk_object([("d".to_strbuf(), String("".to_strbuf()))])
                 ]))
             ]);
 
         assert_eq!(
-            complex_obj.to_str(),
+            complex_obj.to_str().into_strbuf(),
             "{\
                 \"b\":[\
                     {\"c\":\"\\f\\r\"},\
                     {\"d\":\"\"}\
                 ]\
-            }".to_owned()
+            }".to_strbuf()
         );
         assert_eq!(
-            complex_obj.to_pretty_str(),
+            complex_obj.to_pretty_str().into_strbuf(),
             "\
             {\n  \
                 \"b\": [\n    \
@@ -2438,30 +2464,31 @@ fn test_write_object() {
                         \"d\": \"\"\n    \
                     }\n  \
                 ]\n\
-            }".to_owned()
+            }".to_strbuf()
         );
 
         let a = mk_object([
-            ("a".to_owned(), Boolean(true)),
-            ("b".to_owned(), List(vec![
-                mk_object([("c".to_owned(), String("\x0c\r".to_owned()))]),
-                mk_object([("d".to_owned(), String("".to_owned()))])
+            ("a".to_strbuf(), Boolean(true)),
+            ("b".to_strbuf(), List(vec![
+                mk_object([("c".to_strbuf(), String("\x0c\r".to_strbuf()))]),
+                mk_object([("d".to_strbuf(), String("".to_strbuf()))])
             ]))
         ]);
 
         // We can't compare the strings directly because the object fields be
         // printed in a different order.
         assert_eq!(a.clone(), from_str(a.to_str()).unwrap());
-        assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap());
+        assert_eq!(a.clone(),
+                   from_str(a.to_pretty_str().as_slice()).unwrap());
     }
 
-    fn with_str_writer(f: |&mut io::Writer|) -> ~str {
+    fn with_str_writer(f: |&mut io::Writer|) -> StrBuf {
         use std::io::MemWriter;
         use std::str;
 
         let mut m = MemWriter::new();
         f(&mut m as &mut io::Writer);
-        str::from_utf8(m.unwrap().as_slice()).unwrap().to_owned()
+        str::from_utf8(m.unwrap().as_slice()).unwrap().to_strbuf()
     }
 
     #[test]
@@ -2472,23 +2499,23 @@ fn test_write_enum() {
                 let mut encoder = Encoder::new(wr);
                 animal.encode(&mut encoder).unwrap();
             }),
-            "\"Dog\"".to_owned()
+            "\"Dog\"".to_strbuf()
         );
         assert_eq!(
             with_str_writer(|wr| {
                 let mut encoder = PrettyEncoder::new(wr);
                 animal.encode(&mut encoder).unwrap();
             }),
-            "\"Dog\"".to_owned()
+            "\"Dog\"".to_strbuf()
         );
 
-        let animal = Frog("Henry".to_owned(), 349);
+        let animal = Frog("Henry".to_strbuf(), 349);
         assert_eq!(
             with_str_writer(|wr| {
                 let mut encoder = Encoder::new(wr);
                 animal.encode(&mut encoder).unwrap();
             }),
-            "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}".to_owned()
+            "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}".to_strbuf()
         );
         assert_eq!(
             with_str_writer(|wr| {
@@ -2500,41 +2527,41 @@ fn test_write_enum() {
                 \"Frog\",\n  \
                 \"Henry\",\n  \
                 349\n\
-            ]".to_owned()
+            ]".to_strbuf()
         );
     }
 
     #[test]
     fn test_write_some() {
-        let value = Some("jodhpurs".to_owned());
+        let value = Some("jodhpurs".to_strbuf());
         let s = with_str_writer(|wr| {
             let mut encoder = Encoder::new(wr);
             value.encode(&mut encoder).unwrap();
         });
-        assert_eq!(s, "\"jodhpurs\"".to_owned());
+        assert_eq!(s, "\"jodhpurs\"".to_strbuf());
 
-        let value = Some("jodhpurs".to_owned());
+        let value = Some("jodhpurs".to_strbuf());
         let s = with_str_writer(|wr| {
             let mut encoder = PrettyEncoder::new(wr);
             value.encode(&mut encoder).unwrap();
         });
-        assert_eq!(s, "\"jodhpurs\"".to_owned());
+        assert_eq!(s, "\"jodhpurs\"".to_strbuf());
     }
 
     #[test]
     fn test_write_none() {
-        let value: Option<~str> = None;
+        let value: Option<StrBuf> = None;
         let s = with_str_writer(|wr| {
             let mut encoder = Encoder::new(wr);
             value.encode(&mut encoder).unwrap();
         });
-        assert_eq!(s, "null".to_owned());
+        assert_eq!(s, "null".to_strbuf());
 
         let s = with_str_writer(|wr| {
             let mut encoder = Encoder::new(wr);
             value.encode(&mut encoder).unwrap();
         });
-        assert_eq!(s, "null".to_owned());
+        assert_eq!(s, "null".to_strbuf());
     }
 
     #[test]
@@ -2635,16 +2662,16 @@ fn test_read_str() {
         assert_eq!(from_str("\""),    Err(SyntaxError(EOFWhileParsingString, 1, 2)));
         assert_eq!(from_str("\"lol"), Err(SyntaxError(EOFWhileParsingString, 1, 5)));
 
-        assert_eq!(from_str("\"\""), Ok(String("".to_owned())));
-        assert_eq!(from_str("\"foo\""), Ok(String("foo".to_owned())));
-        assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_owned())));
-        assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_owned())));
-        assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_owned())));
-        assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_owned())));
-        assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_owned())));
-        assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_owned())));
-        assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u12ab".to_owned())));
-        assert_eq!(from_str("\"\\uAB12\""), Ok(String("\uAB12".to_owned())));
+        assert_eq!(from_str("\"\""), Ok(String("".to_strbuf())));
+        assert_eq!(from_str("\"foo\""), Ok(String("foo".to_strbuf())));
+        assert_eq!(from_str("\"\\\"\""), Ok(String("\"".to_strbuf())));
+        assert_eq!(from_str("\"\\b\""), Ok(String("\x08".to_strbuf())));
+        assert_eq!(from_str("\"\\n\""), Ok(String("\n".to_strbuf())));
+        assert_eq!(from_str("\"\\r\""), Ok(String("\r".to_strbuf())));
+        assert_eq!(from_str("\"\\t\""), Ok(String("\t".to_strbuf())));
+        assert_eq!(from_str(" \"foo\" "), Ok(String("foo".to_strbuf())));
+        assert_eq!(from_str("\"\\u12ab\""), Ok(String("\u12ab".to_strbuf())));
+        assert_eq!(from_str("\"\\uAB12\""), Ok(String("\uAB12".to_strbuf())));
     }
 
     #[test]
@@ -2665,8 +2692,8 @@ fn test_decode_str() {
             assert_eq!(v.as_slice(), o);
 
             let mut decoder = Decoder::new(from_str(i).unwrap());
-            let v: ~str = Decodable::decode(&mut decoder).unwrap();
-            assert_eq!(v, o.to_owned());
+            let v: StrBuf = Decodable::decode(&mut decoder).unwrap();
+            assert_eq!(v, o.to_strbuf());
         }
     }
 
@@ -2735,39 +2762,39 @@ fn test_read_object() {
 
         assert_eq!(from_str("{}").unwrap(), mk_object([]));
         assert_eq!(from_str("{\"a\": 3}").unwrap(),
-                  mk_object([("a".to_owned(), Number(3.0))]));
+                  mk_object([("a".to_strbuf(), Number(3.0))]));
 
         assert_eq!(from_str(
                       "{ \"a\": null, \"b\" : true }").unwrap(),
                   mk_object([
-                      ("a".to_owned(), Null),
-                      ("b".to_owned(), Boolean(true))]));
+                      ("a".to_strbuf(), Null),
+                      ("b".to_strbuf(), Boolean(true))]));
         assert_eq!(from_str("\n{ \"a\": null, \"b\" : true }\n").unwrap(),
                   mk_object([
-                      ("a".to_owned(), Null),
-                      ("b".to_owned(), Boolean(true))]));
+                      ("a".to_strbuf(), Null),
+                      ("b".to_strbuf(), Boolean(true))]));
         assert_eq!(from_str(
                       "{\"a\" : 1.0 ,\"b\": [ true ]}").unwrap(),
                   mk_object([
-                      ("a".to_owned(), Number(1.0)),
-                      ("b".to_owned(), List(vec![Boolean(true)]))
+                      ("a".to_strbuf(), Number(1.0)),
+                      ("b".to_strbuf(), List(vec![Boolean(true)]))
                   ]));
         assert_eq!(from_str(
-                      "{".to_owned() +
-                          "\"a\": 1.0, " +
-                          "\"b\": [" +
-                              "true," +
-                              "\"foo\\nbar\", " +
-                              "{ \"c\": {\"d\": null} } " +
-                          "]" +
-                      "}").unwrap(),
+                      "{\
+                          \"a\": 1.0, \
+                          \"b\": [\
+                              true,\
+                              \"foo\\nbar\", \
+                              { \"c\": {\"d\": null} } \
+                          ]\
+                      }").unwrap(),
                   mk_object([
-                      ("a".to_owned(), Number(1.0)),
-                      ("b".to_owned(), List(vec![
+                      ("a".to_strbuf(), Number(1.0)),
+                      ("b".to_strbuf(), List(vec![
                           Boolean(true),
-                          String("foo\nbar".to_owned()),
+                          String("foo\nbar".to_strbuf()),
                           mk_object([
-                              ("c".to_owned(), mk_object([("d".to_owned(), Null)]))
+                              ("c".to_strbuf(), mk_object([("d".to_strbuf(), Null)]))
                           ])
                       ]))
                   ]));
@@ -2779,14 +2806,14 @@ fn test_decode_struct() {
             \"inner\": [
                 { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] }
             ]
-        }".to_owned();
+        }";
         let mut decoder = Decoder::new(from_str(s).unwrap());
         let v: Outer = Decodable::decode(&mut decoder).unwrap();
         assert_eq!(
             v,
             Outer {
                 inner: vec![
-                    Inner { a: (), b: 2, c: vec!["abc".to_owned(), "xyz".to_owned()] }
+                    Inner { a: (), b: 2, c: vec!["abc".to_strbuf(), "xyz".to_strbuf()] }
                 ]
             }
         );
@@ -2795,12 +2822,12 @@ fn test_decode_struct() {
     #[test]
     fn test_decode_option() {
         let mut decoder = Decoder::new(from_str("null").unwrap());
-        let value: Option<~str> = Decodable::decode(&mut decoder).unwrap();
+        let value: Option<StrBuf> = Decodable::decode(&mut decoder).unwrap();
         assert_eq!(value, None);
 
         let mut decoder = Decoder::new(from_str("\"jodhpurs\"").unwrap());
-        let value: Option<~str> = Decodable::decode(&mut decoder).unwrap();
-        assert_eq!(value, Some("jodhpurs".to_owned()));
+        let value: Option<StrBuf> = Decodable::decode(&mut decoder).unwrap();
+        assert_eq!(value, Some("jodhpurs".to_strbuf()));
     }
 
     #[test]
@@ -2812,18 +2839,18 @@ fn test_decode_enum() {
         let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
         let mut decoder = Decoder::new(from_str(s).unwrap());
         let value: Animal = Decodable::decode(&mut decoder).unwrap();
-        assert_eq!(value, Frog("Henry".to_owned(), 349));
+        assert_eq!(value, Frog("Henry".to_strbuf(), 349));
     }
 
     #[test]
     fn test_decode_map() {
         let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
-                  \"fields\":[\"Henry\", 349]}}".to_owned();
+                  \"fields\":[\"Henry\", 349]}}";
         let mut decoder = Decoder::new(from_str(s).unwrap());
-        let mut map: TreeMap<~str, Animal> = Decodable::decode(&mut decoder).unwrap();
+        let mut map: TreeMap<StrBuf, Animal> = Decodable::decode(&mut decoder).unwrap();
 
-        assert_eq!(map.pop(&"a".to_owned()), Some(Dog));
-        assert_eq!(map.pop(&"b".to_owned()), Some(Frog("Henry".to_owned(), 349)));
+        assert_eq!(map.pop(&"a".to_strbuf()), Some(Dog));
+        assert_eq!(map.pop(&"b".to_strbuf()), Some(Frog("Henry".to_strbuf(), 349)));
     }
 
     #[test]
@@ -2836,13 +2863,13 @@ fn test_multiline_errors() {
     struct DecodeStruct {
         x: f64,
         y: bool,
-        z: ~str,
+        z: StrBuf,
         w: Vec<DecodeStruct>
     }
     #[deriving(Decodable)]
     enum DecodeEnum {
         A(f64),
-        B(~str)
+        B(StrBuf)
     }
     fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
                                                       expected: DecoderError) {
@@ -2862,51 +2889,51 @@ fn check_err<T: Decodable<Decoder, DecoderError>>(to_parse: &'static str,
     }
     #[test]
     fn test_decode_errors_struct() {
-        check_err::<DecodeStruct>("[]", ExpectedError("Object".to_owned(), "[]".to_owned()));
+        check_err::<DecodeStruct>("[]", ExpectedError("Object".to_strbuf(), "[]".to_strbuf()));
         check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
-                                  ExpectedError("Number".to_owned(), "true".to_owned()));
+                                  ExpectedError("Number".to_strbuf(), "true".to_strbuf()));
         check_err::<DecodeStruct>("{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
-                                  ExpectedError("Boolean".to_owned(), "[]".to_owned()));
+                                  ExpectedError("Boolean".to_strbuf(), "[]".to_strbuf()));
         check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
-                                  ExpectedError("String".to_owned(), "{}".to_owned()));
+                                  ExpectedError("String".to_strbuf(), "{}".to_strbuf()));
         check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
-                                  ExpectedError("List".to_owned(), "null".to_owned()));
+                                  ExpectedError("List".to_strbuf(), "null".to_strbuf()));
         check_err::<DecodeStruct>("{\"x\": 1, \"y\": true, \"z\": \"\"}",
-                                  MissingFieldError("w".to_owned()));
+                                  MissingFieldError("w".to_strbuf()));
     }
     #[test]
     fn test_decode_errors_enum() {
         check_err::<DecodeEnum>("{}",
-                                MissingFieldError("variant".to_owned()));
+                                MissingFieldError("variant".to_strbuf()));
         check_err::<DecodeEnum>("{\"variant\": 1}",
-                                ExpectedError("String".to_owned(), "1".to_owned()));
+                                ExpectedError("String".to_strbuf(), "1".to_strbuf()));
         check_err::<DecodeEnum>("{\"variant\": \"A\"}",
-                                MissingFieldError("fields".to_owned()));
+                                MissingFieldError("fields".to_strbuf()));
         check_err::<DecodeEnum>("{\"variant\": \"A\", \"fields\": null}",
-                                ExpectedError("List".to_owned(), "null".to_owned()));
+                                ExpectedError("List".to_strbuf(), "null".to_strbuf()));
         check_err::<DecodeEnum>("{\"variant\": \"C\", \"fields\": []}",
-                                UnknownVariantError("C".to_owned()));
+                                UnknownVariantError("C".to_strbuf()));
     }
 
     #[test]
     fn test_find(){
         let json_value = from_str("{\"dog\" : \"cat\"}").unwrap();
-        let found_str = json_value.find(&"dog".to_owned());
+        let found_str = json_value.find(&"dog".to_strbuf());
         assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cat");
     }
 
     #[test]
     fn test_find_path(){
         let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-        let found_str = json_value.find_path(&[&"dog".to_owned(),
-                                             &"cat".to_owned(), &"mouse".to_owned()]);
+        let found_str = json_value.find_path(&[&"dog".to_strbuf(),
+                                             &"cat".to_strbuf(), &"mouse".to_strbuf()]);
         assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cheese");
     }
 
     #[test]
     fn test_search(){
         let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap();
-        let found_str = json_value.search(&"mouse".to_owned()).and_then(|j| j.as_string());
+        let found_str = json_value.search(&"mouse".to_strbuf()).and_then(|j| j.as_string());
         assert!(found_str.is_some());
         assert!(found_str.unwrap() == "cheese");
     }
@@ -3069,7 +3096,7 @@ fn test_streaming_parser() {
             r#"{ "foo":"bar", "array" : [0, 1, 2,3 ,4,5], "idents":[null,true,false]}"#,
             ~[
                 (ObjectStart,             ~[]),
-                  (StringValue("bar".to_owned()),   ~[Key("foo")]),
+                  (StringValue("bar".to_strbuf()),   ~[Key("foo")]),
                   (ListStart,             ~[Key("array")]),
                     (NumberValue(0.0),    ~[Key("array"), Index(0)]),
                     (NumberValue(1.0),    ~[Key("array"), Index(1)]),
@@ -3158,7 +3185,7 @@ fn test_read_object_streaming() {
                   (NumberValue(1.0),            ~[Key("a")]),
                   (ListStart,                   ~[Key("b")]),
                     (BooleanValue(true),        ~[Key("b"), Index(0)]),
-                    (StringValue("foo\nbar".to_owned()),  ~[Key("b"), Index(1)]),
+                    (StringValue("foo\nbar".to_strbuf()),  ~[Key("b"), Index(1)]),
                     (ObjectStart,               ~[Key("b"), Index(2)]),
                       (ObjectStart,             ~[Key("b"), Index(2), Key("c")]),
                         (NullValue,             ~[Key("b"), Index(2), Key("c"), Key("d")]),
@@ -3291,7 +3318,7 @@ fn test_stack() {
         assert!(stack.last_is_index());
         assert!(stack.get(0) == Index(1));
 
-        stack.push_key("foo".to_owned());
+        stack.push_key("foo".to_strbuf());
 
         assert!(stack.len() == 2);
         assert!(stack.is_equal_to([Index(1), Key("foo")]));
@@ -3303,7 +3330,7 @@ fn test_stack() {
         assert!(stack.get(0) == Index(1));
         assert!(stack.get(1) == Key("foo"));
 
-        stack.push_key("bar".to_owned());
+        stack.push_key("bar".to_strbuf());
 
         assert!(stack.len() == 3);
         assert!(stack.is_equal_to([Index(1), Key("foo"), Key("bar")]));
@@ -3366,12 +3393,13 @@ fn bench_small(b: &mut Bencher) {
         });
     }
 
-    fn big_json() -> ~str {
-        let mut src = "[\n".to_owned();
+    fn big_json() -> StrBuf {
+        let mut src = "[\n".to_strbuf();
         for _ in range(0, 500) {
-            src = src + r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": [1,2,3]},"#;
+            src.push_str(r#"{ "a": true, "b": null, "c":3.1415, "d": "Hello world", "e": \
+                            [1,2,3]},"#);
         }
-        src = src + "{}]";
+        src.push_str("{}]");
         return src;
     }
 
@@ -3379,7 +3407,7 @@ fn big_json() -> ~str {
     fn bench_streaming_large(b: &mut Bencher) {
         let src = big_json();
         b.iter( || {
-            let mut parser = Parser::new(src.chars());
+            let mut parser = Parser::new(src.as_slice().chars());
             loop {
                 match parser.next() {
                     None => return,
@@ -3391,6 +3419,6 @@ fn bench_streaming_large(b: &mut Bencher) {
     #[bench]
     fn bench_large(b: &mut Bencher) {
         let src = big_json();
-        b.iter( || { let _ = from_str(src); });
+        b.iter( || { let _ = from_str(src.as_slice()); });
     }
 }
index 7914dd8c7d2aaf1269fc8288ae86e2f0aa724ba8..3189676ec1e24552d619b7e774248eadddb92835 100644 (file)
@@ -108,7 +108,7 @@ pub trait Decoder<E> {
     fn read_f64(&mut self) -> Result<f64, E>;
     fn read_f32(&mut self) -> Result<f32, E>;
     fn read_char(&mut self) -> Result<char, E>;
-    fn read_str(&mut self) -> Result<~str, E>;
+    fn read_str(&mut self) -> Result<StrBuf, E>;
 
     // Compound types:
     fn read_enum<T>(&mut self, name: &str, f: |&mut Self| -> Result<T, E>) -> Result<T, E>;
@@ -301,18 +301,6 @@ fn encode(&self, s: &mut S) -> Result<(), E> {
     }
 }
 
-impl<E, S:Encoder<E>> Encodable<S, E> for ~str {
-    fn encode(&self, s: &mut S) -> Result<(), E> {
-        s.emit_str(*self)
-    }
-}
-
-impl<E, D:Decoder<E>> Decodable<D, E> for ~str {
-    fn decode(d: &mut D) -> Result<~str, E> {
-        d.read_str()
-    }
-}
-
 impl<E, S:Encoder<E>> Encodable<S, E> for StrBuf {
     fn encode(&self, s: &mut S) -> Result<(), E> {
         s.emit_str(self.as_slice())
@@ -321,7 +309,7 @@ fn encode(&self, s: &mut S) -> Result<(), E> {
 
 impl<E, D:Decoder<E>> Decodable<D, E> for StrBuf {
     fn decode(d: &mut D) -> Result<StrBuf, E> {
-        Ok(StrBuf::from_str(try!(d.read_str())))
+        Ok(StrBuf::from_str(try!(d.read_str()).as_slice()))
     }
 }
 
index 32f9bc1173b2dec7e148fb22a049762a3e694d87..6b3939872811d4874af371baa2b120aeaf221201 100644 (file)
@@ -59,7 +59,7 @@
 //!
 //! impl fmt::Show for Flags {
 //!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-//!         write!(f.buf, "hi!")
+//!         write!(f, "hi!")
 //!     }
 //! }
 //!
@@ -136,10 +136,20 @@ pub fn bits(&self) -> $T {
                 self.bits
             }
 
-            /// Convert from underlying bit representation. Unsafe because the
-            /// bits are not guaranteed to represent valid flags.
-            pub unsafe fn from_bits(bits: $T) -> $BitFlags {
-                $BitFlags { bits: bits }
+            /// Convert from underlying bit representation, unless that
+            /// representation contains bits that do not correspond to a flag.
+            pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> {
+                if (bits & !$BitFlags::all().bits()) != 0 {
+                    ::std::option::None
+                } else {
+                    ::std::option::Some($BitFlags { bits: bits })
+                }
+            }
+
+            /// Convert from underlying bit representation, dropping any bits
+            /// that do not correspond to flags.
+            pub fn from_bits_truncate(bits: $T) -> $BitFlags {
+                $BitFlags { bits: bits } & $BitFlags::all()
             }
 
             /// Returns `true` if no flags are currently stored.
@@ -209,6 +219,7 @@ fn not(&self) -> $BitFlags {
 
 #[cfg(test)]
 mod tests {
+    use option::{Some, None};
     use ops::{BitOr, BitAnd, Sub, Not};
 
     bitflags!(
@@ -231,9 +242,21 @@ fn test_bits(){
 
     #[test]
     fn test_from_bits() {
-        assert!(unsafe { Flags::from_bits(0x00000000) } == Flags::empty());
-        assert!(unsafe { Flags::from_bits(0x00000001) } == FlagA);
-        assert!(unsafe { Flags::from_bits(0x00000111) } == FlagABC);
+        assert!(Flags::from_bits(0) == Some(Flags::empty()));
+        assert!(Flags::from_bits(0x1) == Some(FlagA));
+        assert!(Flags::from_bits(0x10) == Some(FlagB));
+        assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB));
+        assert!(Flags::from_bits(0x1000) == None);
+    }
+
+    #[test]
+    fn test_from_bits_truncate() {
+        assert!(Flags::from_bits_truncate(0) == Flags::empty());
+        assert!(Flags::from_bits_truncate(0x1) == FlagA);
+        assert!(Flags::from_bits_truncate(0x10) == FlagB);
+        assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB));
+        assert!(Flags::from_bits_truncate(0x1000) == Flags::empty());
+        assert!(Flags::from_bits_truncate(0x1001) == FlagA);
     }
 
     #[test]
index 0885a7af00b4d4d2be1be96780e5aed75e979cf1..0c529ee4d963e64404c013325956b5f5e43ef65b 100644 (file)
@@ -82,6 +82,7 @@ fn main() {
 use slice;
 use str::StrSlice;
 use str;
+use strbuf::StrBuf;
 
 /// The representation of a C String.
 ///
@@ -292,6 +293,14 @@ unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
     }
 }
 
+// FIXME (#12938): Until DST lands, we cannot decompose &str into &
+// and str, so we cannot usefully take ToCStr arguments by reference
+// (without forcing an additional & around &str). So we are instead
+// temporarily adding an instance for ~str and StrBuf, so that we can
+// take ToCStr as owned. When DST lands, the string instances should
+// be revisted, and arguments bound by ToCStr should be passed by
+// reference.
+
 impl<'a> ToCStr for &'a str {
     #[inline]
     fn to_c_str(&self) -> CString {
@@ -314,6 +323,51 @@ unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
     }
 }
 
+impl ToCStr for ~str {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        self.as_bytes().to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        self.as_bytes().to_c_str_unchecked()
+    }
+
+    #[inline]
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str(f)
+    }
+
+    #[inline]
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str_unchecked(f)
+    }
+}
+
+
+impl ToCStr for StrBuf {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        self.as_bytes().to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        self.as_bytes().to_c_str_unchecked()
+    }
+
+    #[inline]
+    fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str(f)
+    }
+
+    #[inline]
+    unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
+        self.as_bytes().with_c_str_unchecked(f)
+    }
+}
+
 // The length of the stack allocated buffer for `vec.with_c_str()`
 static BUF_LEN: uint = 128;
 
diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs
new file mode 100644 (file)
index 0000000..86b77a4
--- /dev/null
@@ -0,0 +1,588 @@
+// Copyright 2013-2014 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.
+
+/*!
+
+Utilities for formatting and printing strings
+
+This module contains the runtime support for the `format!` syntax extension.
+This macro is implemented in the compiler to emit calls to this module in order
+to format arguments at runtime into strings and streams.
+
+The functions contained in this module should not normally be used in everyday
+use cases of `format!`. The assumptions made by these functions are unsafe for
+all inputs, and the compiler performs a large amount of validation on the
+arguments to `format!` in order to ensure safety at runtime. While it is
+possible to call these functions directly, it is not recommended to do so in the
+general case.
+
+## Usage
+
+The `format!` macro is intended to be familiar to those coming from C's
+printf/fprintf functions or Python's `str.format` function. In its current
+revision, the `format!` macro returns a `~str` type which is the result of the
+formatting. In the future it will also be able to pass in a stream to format
+arguments directly while performing minimal allocations.
+
+Some examples of the `format!` extension are:
+
+```rust
+format!("Hello");                 // => "Hello".to_owned()
+format!("Hello, {:s}!", "world"); // => "Hello, world!".to_owned()
+format!("The number is {:d}", 1); // => "The number is 1".to_owned()
+format!("{:?}", ~[3, 4]);         // => "~[3, 4]".to_owned()
+format!("{value}", value=4);      // => "4".to_owned()
+format!("{} {}", 1, 2);           // => "1 2".to_owned()
+```
+
+From these, you can see that the first argument is a format string. It is
+required by the compiler for this to be a string literal; it cannot be a
+variable passed in (in order to perform validity checking). The compiler will
+then parse the format string and determine if the list of arguments provided is
+suitable to pass to this format string.
+
+### Positional parameters
+
+Each formatting argument is allowed to specify which value argument it's
+referencing, and if omitted it is assumed to be "the next argument". For
+example, the format string `{} {} {}` would take three parameters, and they
+would be formatted in the same order as they're given. The format string
+`{2} {1} {0}`, however, would format arguments in reverse order.
+
+Things can get a little tricky once you start intermingling the two types of
+positional specifiers. The "next argument" specifier can be thought of as an
+iterator over the argument. Each time a "next argument" specifier is seen, the
+iterator advances. This leads to behavior like this:
+
+```rust
+format!("{1} {} {0} {}", 1, 2); // => "2 1 1 2".to_owned()
+```
+
+The internal iterator over the argument has not been advanced by the time the
+first `{}` is seen, so it prints the first argument. Then upon reaching the
+second `{}`, the iterator has advanced forward to the second argument.
+Essentially, parameters which explicitly name their argument do not affect
+parameters which do not name an argument in terms of positional specifiers.
+
+A format string is required to use all of its arguments, otherwise it is a
+compile-time error. You may refer to the same argument more than once in the
+format string, although it must always be referred to with the same type.
+
+### Named parameters
+
+Rust itself does not have a Python-like equivalent of named parameters to a
+function, but the `format!` macro is a syntax extension which allows it to
+leverage named parameters. Named parameters are listed at the end of the
+argument list and have the syntax:
+
+```notrust
+identifier '=' expression
+```
+
+For example, the following `format!` expressions all use named argument:
+
+```rust
+format!("{argument}", argument = "test");       // => "test".to_owned()
+format!("{name} {}", 1, name = 2);              // => "2 1".to_owned()
+format!("{a:s} {c:d} {b:?}", a="a", b=(), c=3); // => "a 3 ()".to_owned()
+```
+
+It is illegal to put positional parameters (those without names) after arguments
+which have names. Like positional parameters, it is illegal to provided named
+parameters that are unused by the format string.
+
+### Argument types
+
+Each argument's type is dictated by the format string. It is a requirement that
+every argument is only ever referred to by one type. When specifying the format
+of an argument, however, a string like `{}` indicates no type. This is allowed,
+and if all references to one argument do not provide a type, then the format `?`
+is used (the type's rust-representation is printed). For example, this is an
+invalid format string:
+
+```notrust
+{0:d} {0:s}
+```
+
+Because the first argument is both referred to as an integer as well as a
+string.
+
+Because formatting is done via traits, there is no requirement that the
+`d` format actually takes an `int`, but rather it simply requires a type which
+ascribes to the `Signed` formatting trait. There are various parameters which do
+require a particular type, however. Namely if the syntax `{:.*s}` is used, then
+the number of characters to print from the string precedes the actual string and
+must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
+illegal to reference an argument as such. For example, this is another invalid
+format string:
+
+```notrust
+{:.*s} {0:u}
+```
+
+### Formatting traits
+
+When requesting that an argument be formatted with a particular type, you are
+actually requesting that an argument ascribes to a particular trait. This allows
+multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`).
+The current mapping of types to traits is:
+
+* `?` ⇒ `Poly`
+* `d` ⇒ `Signed`
+* `i` ⇒ `Signed`
+* `u` ⇒ `Unsigned`
+* `b` ⇒ `Bool`
+* `c` ⇒ `Char`
+* `o` ⇒ `Octal`
+* `x` ⇒ `LowerHex`
+* `X` ⇒ `UpperHex`
+* `s` ⇒ `String`
+* `p` ⇒ `Pointer`
+* `t` ⇒ `Binary`
+* `f` ⇒ `Float`
+* `e` ⇒ `LowerExp`
+* `E` ⇒ `UpperExp`
+* *nothing* ⇒ `Show`
+
+What this means is that any type of argument which implements the
+`std::fmt::Binary` trait can then be formatted with `{:t}`. Implementations are
+provided for these traits for a number of primitive types by the standard
+library as well. If no format is specified (as in `{}` or `{:6}`), then the
+format trait used is the `Show` trait. This is one of the more commonly
+implemented traits when formatting a custom type.
+
+When implementing a format trait for your own type, you will have to implement a
+method of the signature:
+
+```rust
+# use std;
+# mod fmt { pub type Result = (); }
+# struct T;
+# trait SomeName<T> {
+fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result;
+# }
+```
+
+Your type will be passed as `self` by-reference, and then the function should
+emit output into the `f.buf` stream. It is up to each format trait
+implementation to correctly adhere to the requested formatting parameters. The
+values of these parameters will be listed in the fields of the `Formatter`
+struct. In order to help with this, the `Formatter` struct also provides some
+helper methods.
+
+Additionally, the return value of this function is `fmt::Result` which is a
+typedef to `Result<(), IoError>` (also known as `IoError<()>`). Formatting
+implementations should ensure that they return errors from `write!` correctly
+(propagating errors upward).
+
+An example of implementing the formatting traits would look
+like:
+
+```rust
+use std::fmt;
+use std::f64;
+
+struct Vector2D {
+    x: int,
+    y: int,
+}
+
+impl fmt::Show for Vector2D {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        // The `f` value implements the `Writer` trait, which is what the
+        // write! macro is expecting. Note that this formatting ignores the
+        // various flags provided to format strings.
+        write!(f, "({}, {})", self.x, self.y)
+    }
+}
+
+// Different traits allow different forms of output of a type. The meaning of
+// this format is to print the magnitude of a vector.
+impl fmt::Binary for Vector2D {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let magnitude = (self.x * self.x + self.y * self.y) as f64;
+        let magnitude = magnitude.sqrt();
+
+        // Respect the formatting flags by using the helper method
+        // `pad_integral` on the Formatter object. See the method documentation
+        // for details, and the function `pad` can be used to pad strings.
+        let decimals = f.precision.unwrap_or(3);
+        let string = f64::to_str_exact(magnitude, decimals);
+        f.pad_integral(true, "", string.as_bytes())
+    }
+}
+
+fn main() {
+    let myvector = Vector2D { x: 3, y: 4 };
+
+    println!("{}", myvector);       // => "(3, 4)"
+    println!("{:10.3t}", myvector); // => "     5.000"
+}
+```
+
+### Related macros
+
+There are a number of related macros in the `format!` family. The ones that are
+currently implemented are:
+
+```ignore
+format!      // described above
+write!       // first argument is a &mut io::Writer, the destination
+writeln!     // same as write but appends a newline
+print!       // the format string is printed to the standard output
+println!     // same as print but appends a newline
+format_args! // described below.
+```
+
+
+#### `write!`
+
+This and `writeln` are two macros which are used to emit the format string to a
+specified stream. This is used to prevent intermediate allocations of format
+strings and instead directly write the output. Under the hood, this function is
+actually invoking the `write` function defined in this module. Example usage is:
+
+```rust
+# #![allow(unused_must_use)]
+use std::io;
+
+let mut w = io::MemWriter::new();
+write!(&mut w as &mut io::Writer, "Hello {}!", "world");
+```
+
+#### `print!`
+
+This and `println` emit their output to stdout. Similarly to the `write!` macro,
+the goal of these macros is to avoid intermediate allocations when printing
+output. Example usage is:
+
+```rust
+print!("Hello {}!", "world");
+println!("I have a newline {}", "character at the end");
+```
+
+#### `format_args!`
+This is a curious macro which is used to safely pass around
+an opaque object describing the format string. This object
+does not require any heap allocations to create, and it only
+references information on the stack. Under the hood, all of
+the related macros are implemented in terms of this. First
+off, some example usage is:
+
+```
+use std::fmt;
+use std::io;
+
+# #[allow(unused_must_use)]
+# fn main() {
+format_args!(fmt::format, "this returns {}", "~str");
+
+let some_writer: &mut io::Writer = &mut io::stdout();
+format_args!(|args| { write!(some_writer, "{}", args) }, "print with a {}", "closure");
+
+fn my_fmt_fn(args: &fmt::Arguments) {
+    write!(&mut io::stdout(), "{}", args);
+}
+format_args!(my_fmt_fn, "or a {} too", "function");
+# }
+```
+
+The first argument of the `format_args!` macro is a function (or closure) which
+takes one argument of type `&fmt::Arguments`. This structure can then be
+passed to the `write` and `format` functions inside this module in order to
+process the format string. The goal of this macro is to even further prevent
+intermediate allocations when dealing formatting strings.
+
+For example, a logging library could use the standard formatting syntax, but it
+would internally pass around this structure until it has been determined where
+output should go to.
+
+It is unsafe to programmatically create an instance of `fmt::Arguments` because
+the operations performed when executing a format string require the compile-time
+checks provided by the compiler. The `format_args!` macro is the only method of
+safely creating these structures, but they can be unsafely created with the
+constructor provided.
+
+## Internationalization
+
+The formatting syntax supported by the `format!` extension supports
+internationalization by providing "methods" which execute various different
+outputs depending on the input. The syntax and methods provided are similar to
+other internationalization systems, so again nothing should seem alien.
+Currently two methods are supported by this extension: "select" and "plural".
+
+Each method will execute one of a number of clauses, and then the value of the
+clause will become what's the result of the argument's format. Inside of the
+cases, nested argument strings may be provided, but all formatting arguments
+must not be done through implicit positional means. All arguments inside of each
+case of a method must be explicitly selected by their name or their integer
+position.
+
+Furthermore, whenever a case is running, the special character `#` can be used
+to reference the string value of the argument which was selected upon. As an
+example:
+
+```rust
+format!("{0, select, other{#}}", "hello"); // => "hello".to_owned()
+```
+
+This example is the equivalent of `{0:s}` essentially.
+
+### Select
+
+The select method is a switch over a `&str` parameter, and the parameter *must*
+be of the type `&str`. An example of the syntax is:
+
+```notrust
+{0, select, male{...} female{...} other{...}}
+```
+
+Breaking this down, the `0`-th argument is selected upon with the `select`
+method, and then a number of cases follow. Each case is preceded by an
+identifier which is the match-clause to execute the given arm. In this case,
+there are two explicit cases, `male` and `female`. The case will be executed if
+the string argument provided is an exact match to the case selected.
+
+The `other` case is also a required case for all `select` methods. This arm will
+be executed if none of the other arms matched the word being selected over.
+
+### Plural
+
+The plural method is a switch statement over a `uint` parameter, and the
+parameter *must* be a `uint`. A plural method in its full glory can be specified
+as:
+
+```notrust
+{0, plural, offset=1 =1{...} two{...} many{...} other{...}}
+```
+
+To break this down, the first `0` indicates that this method is selecting over
+the value of the first positional parameter to the format string. Next, the
+`plural` method is being executed. An optionally-supplied `offset` is then given
+which indicates a number to subtract from argument `0` when matching. This is
+then followed by a list of cases.
+
+Each case is allowed to supply a specific value to match upon with the syntax
+`=N`. This case is executed if the value at argument `0` matches N exactly,
+without taking the offset into account. A case may also be specified by one of
+five keywords: `zero`, `one`, `two`, `few`, and `many`. These cases are matched
+on after argument `0` has the offset taken into account. Currently the
+definitions of `many` and `few` are hardcoded, but they are in theory defined by
+the current locale.
+
+Finally, all `plural` methods must have an `other` case supplied which will be
+executed if none of the other cases match.
+
+## Syntax
+
+The syntax for the formatting language used is drawn from other languages, so it
+should not be too alien. Arguments are formatted with python-like syntax,
+meaning that arguments are surrounded by `{}` instead of the C-like `%`. The
+actual grammar for the formatting syntax is:
+
+```notrust
+format_string := <text> [ format <text> ] *
+format := '{' [ argument ] [ ':' format_spec ] [ ',' function_spec ] '}'
+argument := integer | identifier
+
+format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type]
+fill := character
+align := '<' | '>'
+sign := '+' | '-'
+width := count
+precision := count | '*'
+type := identifier | ''
+count := parameter | integer
+parameter := integer '$'
+
+function_spec := plural | select
+select := 'select' ',' ( identifier arm ) *
+plural := 'plural' ',' [ 'offset:' integer ] ( selector arm ) *
+selector := '=' integer | keyword
+keyword := 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'
+arm := '{' format_string '}'
+```
+
+## Formatting Parameters
+
+Each argument being formatted can be transformed by a number of formatting
+parameters (corresponding to `format_spec` in the syntax above). These
+parameters affect the string representation of what's being formatted. This
+syntax draws heavily from Python's, so it may seem a bit familiar.
+
+### Fill/Alignment
+
+The fill character is provided normally in conjunction with the `width`
+parameter. This indicates that if the value being formatted is smaller than
+`width` some extra characters will be printed around it. The extra characters
+are specified by `fill`, and the alignment can be one of two options:
+
+* `<` - the argument is left-aligned in `width` columns
+* `>` - the argument is right-aligned in `width` columns
+
+### Sign/#/0
+
+These can all be interpreted as flags for a particular formatter.
+
+* '+' - This is intended for numeric types and indicates that the sign should
+        always be printed. Positive signs are never printed by default, and the
+        negative sign is only printed by default for the `Signed` trait. This
+        flag indicates that the correct sign (+ or -) should always be printed.
+* '-' - Currently not used
+* '#' - This flag is indicates that the "alternate" form of printing should be
+        used. By default, this only applies to the integer formatting traits and
+        performs like:
+    * `x` - precedes the argument with a "0x"
+    * `X` - precedes the argument with a "0x"
+    * `t` - precedes the argument with a "0b"
+    * `o` - precedes the argument with a "0o"
+* '0' - This is used to indicate for integer formats that the padding should
+        both be done with a `0` character as well as be sign-aware. A format
+        like `{:08d}` would yield `00000001` for the integer `1`, while the same
+        format would yield `-0000001` for the integer `-1`. Notice that the
+        negative version has one fewer zero than the positive version.
+
+### Width
+
+This is a parameter for the "minimum width" that the format should take up. If
+the value's string does not fill up this many characters, then the padding
+specified by fill/alignment will be used to take up the required space.
+
+The default fill/alignment for non-numerics is a space and left-aligned. The
+defaults for numeric formatters is also a space but with right-alignment. If the
+'0' flag is specified for numerics, then the implicit fill character is '0'.
+
+The value for the width can also be provided as a `uint` in the list of
+parameters by using the `2$` syntax indicating that the second argument is a
+`uint` specifying the width.
+
+### Precision
+
+For non-numeric types, this can be considered a "maximum width". If the
+resulting string is longer than this width, then it is truncated down to this
+many characters and only those are emitted.
+
+For integral types, this has no meaning currently.
+
+For floating-point types, this indicates how many digits after the decimal point
+should be printed.
+
+## Escaping
+
+The literal characters `{`, `}`, or `#` may be included in a string by
+preceding them with the `\` character. Since `\` is already an
+escape character in Rust strings, a string literal using this escape
+will look like `"\\{"`.
+
+*/
+
+use io::Writer;
+use io;
+use option::None;
+use repr;
+use result::{Ok, Err};
+use str::{StrAllocating};
+use str;
+use strbuf::StrBuf;
+use slice::Vector;
+
+pub use core::fmt::{Formatter, Result, FormatWriter, Show, rt};
+pub use core::fmt::{Show, Bool, Char, Signed, Unsigned, Octal, Binary};
+pub use core::fmt::{LowerHex, UpperHex, String, Pointer};
+pub use core::fmt::{Float, LowerExp, UpperExp};
+pub use core::fmt::{FormatError, WriteError};
+pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt};
+
+#[doc(hidden)]
+pub use core::fmt::{argument, argumentstr, argumentuint};
+#[doc(hidden)]
+pub use core::fmt::{secret_show, secret_string, secret_unsigned};
+#[doc(hidden)]
+pub use core::fmt::{secret_signed, secret_lower_hex, secret_upper_hex};
+#[doc(hidden)]
+pub use core::fmt::{secret_bool, secret_char, secret_octal, secret_binary};
+#[doc(hidden)]
+pub use core::fmt::{secret_bool, secret_char, secret_octal, secret_binary};
+#[doc(hidden)]
+pub use core::fmt::{secret_float, secret_upper_exp, secret_lower_exp};
+#[doc(hidden)]
+pub use core::fmt::{secret_pointer};
+
+#[doc(hidden)]
+pub fn secret_poly<T: Poly>(x: &T, fmt: &mut Formatter) -> Result {
+    // FIXME #11938 - UFCS would make us able call the this method
+    //                directly Poly::fmt(x, fmt).
+    x.fmt(fmt)
+}
+
+/// Format trait for the `?` character
+pub trait Poly {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// The format function takes a precompiled format string and a list of
+/// arguments, to return the resulting formatted string.
+///
+/// # Arguments
+///
+///   * args - a structure of arguments generated via the `format_args!` macro.
+///            Because this structure can only be safely generated at
+///            compile-time, this function is safe.
+///
+/// # Example
+///
+/// ```rust
+/// use std::fmt;
+///
+/// let s = format_args!(fmt::format, "Hello, {}!", "world");
+/// assert_eq!(s, "Hello, world!".to_owned());
+/// ```
+pub fn format(args: &Arguments) -> ~str {
+    let mut output = io::MemWriter::new();
+    let _ = write!(&mut output, "{}", args);
+    str::from_utf8(output.unwrap().as_slice()).unwrap().to_owned()
+}
+
+/// Temporary transition utility
+pub fn format_strbuf(args: &Arguments) -> StrBuf {
+    let mut output = io::MemWriter::new();
+    let _ = write!(&mut output, "{}", args);
+    str::from_utf8(output.unwrap().as_slice()).unwrap().into_strbuf()
+}
+
+impl<T> Poly for T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        match (f.width, f.precision) {
+            (None, None) => {
+                match repr::write_repr(f, self) {
+                    Ok(()) => Ok(()),
+                    Err(..) => Err(WriteError),
+                }
+            }
+
+            // If we have a specified width for formatting, then we have to make
+            // this allocation of a new string
+            _ => {
+                let s = repr::repr_to_str(self);
+                f.pad(s)
+            }
+        }
+    }
+}
+
+impl<'a> Writer for Formatter<'a> {
+    fn write(&mut self, b: &[u8]) -> io::IoResult<()> {
+        match (*self).write(b) {
+            Ok(()) => Ok(()),
+            Err(WriteError) => Err(io::standard_error(io::OtherIoError))
+        }
+    }
+}
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
deleted file mode 100644 (file)
index d4f12f5..0000000
+++ /dev/null
@@ -1,1405 +0,0 @@
-// Copyright 2013-2014 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.
-
-/*!
-
-Utilities for formatting and printing strings
-
-This module contains the runtime support for the `format!` syntax extension.
-This macro is implemented in the compiler to emit calls to this module in order
-to format arguments at runtime into strings and streams.
-
-The functions contained in this module should not normally be used in everyday
-use cases of `format!`. The assumptions made by these functions are unsafe for
-all inputs, and the compiler performs a large amount of validation on the
-arguments to `format!` in order to ensure safety at runtime. While it is
-possible to call these functions directly, it is not recommended to do so in the
-general case.
-
-## Usage
-
-The `format!` macro is intended to be familiar to those coming from C's
-printf/fprintf functions or Python's `str.format` function. In its current
-revision, the `format!` macro returns a `~str` type which is the result of the
-formatting. In the future it will also be able to pass in a stream to format
-arguments directly while performing minimal allocations.
-
-Some examples of the `format!` extension are:
-
-```rust
-format!("Hello");                 // => "Hello".to_owned()
-format!("Hello, {:s}!", "world"); // => "Hello, world!".to_owned()
-format!("The number is {:d}", 1); // => "The number is 1".to_owned()
-format!("{:?}", ~[3, 4]);         // => "~[3, 4]".to_owned()
-format!("{value}", value=4);      // => "4".to_owned()
-format!("{} {}", 1, 2);           // => "1 2".to_owned()
-```
-
-From these, you can see that the first argument is a format string. It is
-required by the compiler for this to be a string literal; it cannot be a
-variable passed in (in order to perform validity checking). The compiler will
-then parse the format string and determine if the list of arguments provided is
-suitable to pass to this format string.
-
-### Positional parameters
-
-Each formatting argument is allowed to specify which value argument it's
-referencing, and if omitted it is assumed to be "the next argument". For
-example, the format string `{} {} {}` would take three parameters, and they
-would be formatted in the same order as they're given. The format string
-`{2} {1} {0}`, however, would format arguments in reverse order.
-
-Things can get a little tricky once you start intermingling the two types of
-positional specifiers. The "next argument" specifier can be thought of as an
-iterator over the argument. Each time a "next argument" specifier is seen, the
-iterator advances. This leads to behavior like this:
-
-```rust
-format!("{1} {} {0} {}", 1, 2); // => "2 1 1 2".to_owned()
-```
-
-The internal iterator over the argument has not been advanced by the time the
-first `{}` is seen, so it prints the first argument. Then upon reaching the
-second `{}`, the iterator has advanced forward to the second argument.
-Essentially, parameters which explicitly name their argument do not affect
-parameters which do not name an argument in terms of positional specifiers.
-
-A format string is required to use all of its arguments, otherwise it is a
-compile-time error. You may refer to the same argument more than once in the
-format string, although it must always be referred to with the same type.
-
-### Named parameters
-
-Rust itself does not have a Python-like equivalent of named parameters to a
-function, but the `format!` macro is a syntax extension which allows it to
-leverage named parameters. Named parameters are listed at the end of the
-argument list and have the syntax:
-
-```notrust
-identifier '=' expression
-```
-
-For example, the following `format!` expressions all use named argument:
-
-```rust
-format!("{argument}", argument = "test");       // => "test".to_owned()
-format!("{name} {}", 1, name = 2);              // => "2 1".to_owned()
-format!("{a:s} {c:d} {b:?}", a="a", b=(), c=3); // => "a 3 ()".to_owned()
-```
-
-It is illegal to put positional parameters (those without names) after arguments
-which have names. Like positional parameters, it is illegal to provided named
-parameters that are unused by the format string.
-
-### Argument types
-
-Each argument's type is dictated by the format string. It is a requirement that
-every argument is only ever referred to by one type. When specifying the format
-of an argument, however, a string like `{}` indicates no type. This is allowed,
-and if all references to one argument do not provide a type, then the format `?`
-is used (the type's rust-representation is printed). For example, this is an
-invalid format string:
-
-```notrust
-{0:d} {0:s}
-```
-
-Because the first argument is both referred to as an integer as well as a
-string.
-
-Because formatting is done via traits, there is no requirement that the
-`d` format actually takes an `int`, but rather it simply requires a type which
-ascribes to the `Signed` formatting trait. There are various parameters which do
-require a particular type, however. Namely if the syntax `{:.*s}` is used, then
-the number of characters to print from the string precedes the actual string and
-must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is
-illegal to reference an argument as such. For example, this is another invalid
-format string:
-
-```notrust
-{:.*s} {0:u}
-```
-
-### Formatting traits
-
-When requesting that an argument be formatted with a particular type, you are
-actually requesting that an argument ascribes to a particular trait. This allows
-multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`).
-The current mapping of types to traits is:
-
-* `?` ⇒ `Poly`
-* `d` ⇒ `Signed`
-* `i` ⇒ `Signed`
-* `u` ⇒ `Unsigned`
-* `b` ⇒ `Bool`
-* `c` ⇒ `Char`
-* `o` ⇒ `Octal`
-* `x` ⇒ `LowerHex`
-* `X` ⇒ `UpperHex`
-* `s` ⇒ `String`
-* `p` ⇒ `Pointer`
-* `t` ⇒ `Binary`
-* `f` ⇒ `Float`
-* `e` ⇒ `LowerExp`
-* `E` ⇒ `UpperExp`
-* *nothing* ⇒ `Show`
-
-What this means is that any type of argument which implements the
-`std::fmt::Binary` trait can then be formatted with `{:t}`. Implementations are
-provided for these traits for a number of primitive types by the standard
-library as well. If no format is specified (as in `{}` or `{:6}`), then the
-format trait used is the `Show` trait. This is one of the more commonly
-implemented traits when formatting a custom type.
-
-When implementing a format trait for your own type, you will have to implement a
-method of the signature:
-
-```rust
-# use std;
-# mod fmt { pub type Result = (); }
-# struct T;
-# trait SomeName<T> {
-fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result;
-# }
-```
-
-Your type will be passed as `self` by-reference, and then the function should
-emit output into the `f.buf` stream. It is up to each format trait
-implementation to correctly adhere to the requested formatting parameters. The
-values of these parameters will be listed in the fields of the `Formatter`
-struct. In order to help with this, the `Formatter` struct also provides some
-helper methods.
-
-Additionally, the return value of this function is `fmt::Result` which is a
-typedef to `Result<(), IoError>` (also known as `IoError<()>`). Formatting
-implementations should ensure that they return errors from `write!` correctly
-(propagating errors upward).
-
-An example of implementing the formatting traits would look
-like:
-
-```rust
-use std::fmt;
-use std::f64;
-
-struct Vector2D {
-    x: int,
-    y: int,
-}
-
-impl fmt::Show for Vector2D {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // The `f.buf` value is of the type `&mut io::Writer`, which is what the
-        // write! macro is expecting. Note that this formatting ignores the
-        // various flags provided to format strings.
-        write!(f.buf, "({}, {})", self.x, self.y)
-    }
-}
-
-// Different traits allow different forms of output of a type. The meaning of
-// this format is to print the magnitude of a vector.
-impl fmt::Binary for Vector2D {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let magnitude = (self.x * self.x + self.y * self.y) as f64;
-        let magnitude = magnitude.sqrt();
-
-        // Respect the formatting flags by using the helper method
-        // `pad_integral` on the Formatter object. See the method documentation
-        // for details, and the function `pad` can be used to pad strings.
-        let decimals = f.precision.unwrap_or(3);
-        let string = f64::to_str_exact(magnitude, decimals);
-        f.pad_integral(true, "", string.as_bytes())
-    }
-}
-
-fn main() {
-    let myvector = Vector2D { x: 3, y: 4 };
-
-    println!("{}", myvector);       // => "(3, 4)"
-    println!("{:10.3t}", myvector); // => "     5.000"
-}
-```
-
-### Related macros
-
-There are a number of related macros in the `format!` family. The ones that are
-currently implemented are:
-
-```ignore
-format!      // described above
-write!       // first argument is a &mut io::Writer, the destination
-writeln!     // same as write but appends a newline
-print!       // the format string is printed to the standard output
-println!     // same as print but appends a newline
-format_args! // described below.
-```
-
-
-#### `write!`
-
-This and `writeln` are two macros which are used to emit the format string to a
-specified stream. This is used to prevent intermediate allocations of format
-strings and instead directly write the output. Under the hood, this function is
-actually invoking the `write` function defined in this module. Example usage is:
-
-```rust
-# #![allow(unused_must_use)]
-use std::io;
-
-let mut w = io::MemWriter::new();
-write!(&mut w as &mut io::Writer, "Hello {}!", "world");
-```
-
-#### `print!`
-
-This and `println` emit their output to stdout. Similarly to the `write!` macro,
-the goal of these macros is to avoid intermediate allocations when printing
-output. Example usage is:
-
-```rust
-print!("Hello {}!", "world");
-println!("I have a newline {}", "character at the end");
-```
-
-#### `format_args!`
-This is a curious macro which is used to safely pass around
-an opaque object describing the format string. This object
-does not require any heap allocations to create, and it only
-references information on the stack. Under the hood, all of
-the related macros are implemented in terms of this. First
-off, some example usage is:
-
-```
-use std::fmt;
-use std::io;
-
-# #[allow(unused_must_use)]
-# fn main() {
-format_args!(fmt::format, "this returns {}", "~str");
-
-let some_writer: &mut io::Writer = &mut io::stdout();
-format_args!(|args| { fmt::write(some_writer, args) }, "print with a {}", "closure");
-
-fn my_fmt_fn(args: &fmt::Arguments) {
-    fmt::write(&mut io::stdout(), args);
-}
-format_args!(my_fmt_fn, "or a {} too", "function");
-# }
-```
-
-The first argument of the `format_args!` macro is a function (or closure) which
-takes one argument of type `&fmt::Arguments`. This structure can then be
-passed to the `write` and `format` functions inside this module in order to
-process the format string. The goal of this macro is to even further prevent
-intermediate allocations when dealing formatting strings.
-
-For example, a logging library could use the standard formatting syntax, but it
-would internally pass around this structure until it has been determined where
-output should go to.
-
-It is unsafe to programmatically create an instance of `fmt::Arguments` because
-the operations performed when executing a format string require the compile-time
-checks provided by the compiler. The `format_args!` macro is the only method of
-safely creating these structures, but they can be unsafely created with the
-constructor provided.
-
-## Internationalization
-
-The formatting syntax supported by the `format!` extension supports
-internationalization by providing "methods" which execute various different
-outputs depending on the input. The syntax and methods provided are similar to
-other internationalization systems, so again nothing should seem alien.
-Currently two methods are supported by this extension: "select" and "plural".
-
-Each method will execute one of a number of clauses, and then the value of the
-clause will become what's the result of the argument's format. Inside of the
-cases, nested argument strings may be provided, but all formatting arguments
-must not be done through implicit positional means. All arguments inside of each
-case of a method must be explicitly selected by their name or their integer
-position.
-
-Furthermore, whenever a case is running, the special character `#` can be used
-to reference the string value of the argument which was selected upon. As an
-example:
-
-```rust
-format!("{0, select, other{#}}", "hello"); // => "hello".to_owned()
-```
-
-This example is the equivalent of `{0:s}` essentially.
-
-### Select
-
-The select method is a switch over a `&str` parameter, and the parameter *must*
-be of the type `&str`. An example of the syntax is:
-
-```notrust
-{0, select, male{...} female{...} other{...}}
-```
-
-Breaking this down, the `0`-th argument is selected upon with the `select`
-method, and then a number of cases follow. Each case is preceded by an
-identifier which is the match-clause to execute the given arm. In this case,
-there are two explicit cases, `male` and `female`. The case will be executed if
-the string argument provided is an exact match to the case selected.
-
-The `other` case is also a required case for all `select` methods. This arm will
-be executed if none of the other arms matched the word being selected over.
-
-### Plural
-
-The plural method is a switch statement over a `uint` parameter, and the
-parameter *must* be a `uint`. A plural method in its full glory can be specified
-as:
-
-```notrust
-{0, plural, offset=1 =1{...} two{...} many{...} other{...}}
-```
-
-To break this down, the first `0` indicates that this method is selecting over
-the value of the first positional parameter to the format string. Next, the
-`plural` method is being executed. An optionally-supplied `offset` is then given
-which indicates a number to subtract from argument `0` when matching. This is
-then followed by a list of cases.
-
-Each case is allowed to supply a specific value to match upon with the syntax
-`=N`. This case is executed if the value at argument `0` matches N exactly,
-without taking the offset into account. A case may also be specified by one of
-five keywords: `zero`, `one`, `two`, `few`, and `many`. These cases are matched
-on after argument `0` has the offset taken into account. Currently the
-definitions of `many` and `few` are hardcoded, but they are in theory defined by
-the current locale.
-
-Finally, all `plural` methods must have an `other` case supplied which will be
-executed if none of the other cases match.
-
-## Syntax
-
-The syntax for the formatting language used is drawn from other languages, so it
-should not be too alien. Arguments are formatted with python-like syntax,
-meaning that arguments are surrounded by `{}` instead of the C-like `%`. The
-actual grammar for the formatting syntax is:
-
-```notrust
-format_string := <text> [ format <text> ] *
-format := '{' [ argument ] [ ':' format_spec ] [ ',' function_spec ] '}'
-argument := integer | identifier
-
-format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type]
-fill := character
-align := '<' | '>'
-sign := '+' | '-'
-width := count
-precision := count | '*'
-type := identifier | ''
-count := parameter | integer
-parameter := integer '$'
-
-function_spec := plural | select
-select := 'select' ',' ( identifier arm ) *
-plural := 'plural' ',' [ 'offset:' integer ] ( selector arm ) *
-selector := '=' integer | keyword
-keyword := 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'
-arm := '{' format_string '}'
-```
-
-## Formatting Parameters
-
-Each argument being formatted can be transformed by a number of formatting
-parameters (corresponding to `format_spec` in the syntax above). These
-parameters affect the string representation of what's being formatted. This
-syntax draws heavily from Python's, so it may seem a bit familiar.
-
-### Fill/Alignment
-
-The fill character is provided normally in conjunction with the `width`
-parameter. This indicates that if the value being formatted is smaller than
-`width` some extra characters will be printed around it. The extra characters
-are specified by `fill`, and the alignment can be one of two options:
-
-* `<` - the argument is left-aligned in `width` columns
-* `>` - the argument is right-aligned in `width` columns
-
-### Sign/#/0
-
-These can all be interpreted as flags for a particular formatter.
-
-* '+' - This is intended for numeric types and indicates that the sign should
-        always be printed. Positive signs are never printed by default, and the
-        negative sign is only printed by default for the `Signed` trait. This
-        flag indicates that the correct sign (+ or -) should always be printed.
-* '-' - Currently not used
-* '#' - This flag is indicates that the "alternate" form of printing should be
-        used. By default, this only applies to the integer formatting traits and
-        performs like:
-    * `x` - precedes the argument with a "0x"
-    * `X` - precedes the argument with a "0x"
-    * `t` - precedes the argument with a "0b"
-    * `o` - precedes the argument with a "0o"
-* '0' - This is used to indicate for integer formats that the padding should
-        both be done with a `0` character as well as be sign-aware. A format
-        like `{:08d}` would yield `00000001` for the integer `1`, while the same
-        format would yield `-0000001` for the integer `-1`. Notice that the
-        negative version has one fewer zero than the positive version.
-
-### Width
-
-This is a parameter for the "minimum width" that the format should take up. If
-the value's string does not fill up this many characters, then the padding
-specified by fill/alignment will be used to take up the required space.
-
-The default fill/alignment for non-numerics is a space and left-aligned. The
-defaults for numeric formatters is also a space but with right-alignment. If the
-'0' flag is specified for numerics, then the implicit fill character is '0'.
-
-The value for the width can also be provided as a `uint` in the list of
-parameters by using the `2$` syntax indicating that the second argument is a
-`uint` specifying the width.
-
-### Precision
-
-For non-numeric types, this can be considered a "maximum width". If the
-resulting string is longer than this width, then it is truncated down to this
-many characters and only those are emitted.
-
-For integral types, this has no meaning currently.
-
-For floating-point types, this indicates how many digits after the decimal point
-should be printed.
-
-## Escaping
-
-The literal characters `{`, `}`, or `#` may be included in a string by
-preceding them with the `\` character. Since `\` is already an
-escape character in Rust strings, a string literal using this escape
-will look like `"\\{"`.
-
-*/
-
-use any;
-use cell::Cell;
-use char::Char;
-use cmp;
-use container::Container;
-use intrinsics::TypeId;
-use io::MemWriter;
-use io;
-use iter::{Iterator, range};
-use iter;
-use kinds::Copy;
-use mem;
-use num::Signed;
-use option::{Option, Some, None};
-use owned::Box;
-use repr;
-use result::{Ok, Err, ResultUnwrap};
-use slice::{Vector, ImmutableVector};
-use slice;
-use str::{StrSlice, StrAllocating, UTF16Item, ScalarValue, LoneSurrogate};
-use str;
-use strbuf::StrBuf;
-
-pub use self::num::radix;
-pub use self::num::Radix;
-pub use self::num::RadixFmt;
-
-mod num;
-pub mod rt;
-
-pub type Result = io::IoResult<()>;
-
-/// A struct to represent both where to emit formatting strings to and how they
-/// should be formatted. A mutable version of this is passed to all formatting
-/// traits.
-pub struct Formatter<'a> {
-    /// Flags for formatting (packed version of rt::Flag)
-    pub flags: uint,
-    /// Character used as 'fill' whenever there is alignment
-    pub fill: char,
-    /// Boolean indication of whether the output should be left-aligned
-    pub align: rt::Alignment,
-    /// Optionally specified integer width that the output should be
-    pub width: Option<uint>,
-    /// Optionally specified precision for numeric types
-    pub precision: Option<uint>,
-
-    /// Output buffer.
-    pub buf: &'a mut io::Writer,
-    curarg: slice::Items<'a, Argument<'a>>,
-    args: &'a [Argument<'a>],
-}
-
-/// This struct represents the generic "argument" which is taken by the Xprintf
-/// family of functions. It contains a function to format the given value. At
-/// compile time it is ensured that the function and the value have the correct
-/// types, and then this struct is used to canonicalize arguments to one type.
-pub struct Argument<'a> {
-    formatter: extern "Rust" fn(&any::Void, &mut Formatter) -> Result,
-    value: &'a any::Void,
-}
-
-impl<'a> Arguments<'a> {
-    /// When using the format_args!() macro, this function is used to generate the
-    /// Arguments structure. The compiler inserts an `unsafe` block to call this,
-    /// which is valid because the compiler performs all necessary validation to
-    /// ensure that the resulting call to format/write would be safe.
-    #[doc(hidden)] #[inline]
-    pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
-                          args: &'a [Argument<'a>]) -> Arguments<'a> {
-        Arguments{ fmt: mem::transmute(fmt), args: args }
-    }
-}
-
-/// This structure represents a safely precompiled version of a format string
-/// and its arguments. This cannot be generated at runtime because it cannot
-/// safely be done so, so no constructors are given and the fields are private
-/// to prevent modification.
-///
-/// The `format_args!` macro will safely create an instance of this structure
-/// and pass it to a user-supplied function. The macro validates the format
-/// string at compile-time so usage of the `write` and `format` functions can
-/// be safely performed.
-pub struct Arguments<'a> {
-    fmt: &'a [rt::Piece<'a>],
-    args: &'a [Argument<'a>],
-}
-
-impl<'a> Show for Arguments<'a> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result {
-        write(fmt.buf, self)
-    }
-}
-
-/// When a format is not otherwise specified, types are formatted by ascribing
-/// to this trait. There is not an explicit way of selecting this trait to be
-/// used for formatting, it is only if no other format is specified.
-pub trait Show {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `b` character
-pub trait Bool {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `c` character
-pub trait Char {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `i` and `d` characters
-pub trait Signed {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `u` character
-pub trait Unsigned {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `o` character
-pub trait Octal {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `t` character
-pub trait Binary {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `x` character
-pub trait LowerHex {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `X` character
-pub trait UpperHex {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `s` character
-pub trait String {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `?` character
-pub trait Poly {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `p` character
-pub trait Pointer {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `f` character
-pub trait Float {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `e` character
-pub trait LowerExp {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-/// Format trait for the `E` character
-pub trait UpperExp {
-    /// Formats the value using the given formatter.
-    fn fmt(&self, &mut Formatter) -> Result;
-}
-
-// FIXME #11938 - UFCS would make us able call the above methods
-// directly Show::show(x, fmt).
-macro_rules! uniform_fn_call_workaround {
-    ($( $name: ident, $trait_: ident; )*) => {
-        $(
-            #[doc(hidden)]
-            pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) -> Result {
-                x.fmt(fmt)
-            }
-            )*
-    }
-}
-uniform_fn_call_workaround! {
-    secret_show, Show;
-    secret_bool, Bool;
-    secret_char, Char;
-    secret_signed, Signed;
-    secret_unsigned, Unsigned;
-    secret_octal, Octal;
-    secret_binary, Binary;
-    secret_lower_hex, LowerHex;
-    secret_upper_hex, UpperHex;
-    secret_string, String;
-    secret_poly, Poly;
-    secret_pointer, Pointer;
-    secret_float, Float;
-    secret_lower_exp, LowerExp;
-    secret_upper_exp, UpperExp;
-}
-
-/// The `write` function takes an output stream, a precompiled format string,
-/// and a list of arguments. The arguments will be formatted according to the
-/// specified format string into the output stream provided.
-///
-/// # Arguments
-///
-///   * output - the buffer to write output to
-///   * args - the precompiled arguments generated by `format_args!`
-///
-/// # Example
-///
-/// ```rust
-/// # #![allow(unused_must_use)]
-/// use std::fmt;
-/// use std::io;
-///
-/// let mut w = io::stdout();
-/// format_args!(|args| { fmt::write(&mut w, args); }, "Hello, {}!", "world");
-/// ```
-pub fn write(output: &mut io::Writer, args: &Arguments) -> Result {
-    unsafe { write_unsafe(output, args.fmt, args.args) }
-}
-
-/// The `writeln` function takes the same arguments as `write`, except that it
-/// will also write a newline (`\n`) character at the end of the format string.
-pub fn writeln(output: &mut io::Writer, args: &Arguments) -> Result {
-    let first = unsafe { write_unsafe(output, args.fmt, args.args) };
-    first.and_then(|()| output.write(['\n' as u8]))
-}
-
-/// The `write_unsafe` function takes an output stream, a precompiled format
-/// string, and a list of arguments. The arguments will be formatted according
-/// to the specified format string into the output stream provided.
-///
-/// See the documentation for `format` for why this function is unsafe and care
-/// should be taken if calling it manually.
-///
-/// Thankfully the rust compiler provides macros like `write!` and
-/// `format_args!` which perform all of this validation at compile-time
-/// and provide a safe interface for invoking this function.
-///
-/// # Arguments
-///
-///   * output - the buffer to write output to
-///   * fmts - the precompiled format string to emit
-///   * args - the list of arguments to the format string. These are only the
-///            positional arguments (not named)
-///
-/// Note that this function assumes that there are enough arguments for the
-/// format string.
-pub unsafe fn write_unsafe(output: &mut io::Writer,
-                           fmt: &[rt::Piece],
-                           args: &[Argument]) -> Result {
-    let mut formatter = Formatter {
-        flags: 0,
-        width: None,
-        precision: None,
-        buf: output,
-        align: rt::AlignUnknown,
-        fill: ' ',
-        args: args,
-        curarg: args.iter(),
-    };
-    for piece in fmt.iter() {
-        try!(formatter.run(piece, None));
-    }
-    Ok(())
-}
-
-/// The format function takes a precompiled format string and a list of
-/// arguments, to return the resulting formatted string.
-///
-/// # Arguments
-///
-///   * args - a structure of arguments generated via the `format_args!` macro.
-///            Because this structure can only be safely generated at
-///            compile-time, this function is safe.
-///
-/// # Example
-///
-/// ```rust
-/// use std::fmt;
-///
-/// let s = format_args!(fmt::format, "Hello, {}!", "world");
-/// assert_eq!(s, "Hello, world!".to_owned());
-/// ```
-pub fn format(args: &Arguments) -> ~str {
-    unsafe { format_unsafe(args.fmt, args.args) }
-}
-
-/// Temporary transitionary thing.
-pub fn format_strbuf(args: &Arguments) -> StrBuf {
-    unsafe { format_unsafe_strbuf(args.fmt, args.args) }
-}
-
-/// The unsafe version of the formatting function.
-///
-/// This is currently an unsafe function because the types of all arguments
-/// aren't verified by immediate callers of this function. This currently does
-/// not validate that the correct types of arguments are specified for each
-/// format specifier, nor that each argument itself contains the right function
-/// for formatting the right type value. Because of this, the function is marked
-/// as `unsafe` if this is being called manually.
-///
-/// Thankfully the rust compiler provides the macro `format!` which will perform
-/// all of this validation at compile-time and provides a safe interface for
-/// invoking this function.
-///
-/// # Arguments
-///
-///   * fmts - the precompiled format string to emit.
-///   * args - the list of arguments to the format string. These are only the
-///            positional arguments (not named)
-///
-/// Note that this function assumes that there are enough arguments for the
-/// format string.
-pub unsafe fn format_unsafe(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
-    let mut output = MemWriter::new();
-    write_unsafe(&mut output as &mut io::Writer, fmt, args).unwrap();
-    return str::from_utf8(output.unwrap().as_slice()).unwrap().to_owned();
-}
-
-/// Temporary transitionary thing.
-pub unsafe fn format_unsafe_strbuf(fmt: &[rt::Piece], args: &[Argument])
-                                   -> StrBuf {
-    let mut output = MemWriter::new();
-    write_unsafe(&mut output as &mut io::Writer, fmt, args).unwrap();
-    return str::from_utf8(output.unwrap().as_slice()).unwrap().into_strbuf();
-}
-
-impl<'a> Formatter<'a> {
-
-    // First up is the collection of functions used to execute a format string
-    // at runtime. This consumes all of the compile-time statics generated by
-    // the format! syntax extension.
-
-    fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) -> Result {
-        match *piece {
-            rt::String(s) => self.buf.write(s.as_bytes()),
-            rt::CurrentArgument(()) => self.buf.write(cur.unwrap().as_bytes()),
-            rt::Argument(ref arg) => {
-                // Fill in the format parameters into the formatter
-                self.fill = arg.format.fill;
-                self.align = arg.format.align;
-                self.flags = arg.format.flags;
-                self.width = self.getcount(&arg.format.width);
-                self.precision = self.getcount(&arg.format.precision);
-
-                // Extract the correct argument
-                let value = match arg.position {
-                    rt::ArgumentNext => { *self.curarg.next().unwrap() }
-                    rt::ArgumentIs(i) => self.args[i],
-                };
-
-                // Then actually do some printing
-                match arg.method {
-                    None => (value.formatter)(value.value, self),
-                    Some(ref method) => self.execute(*method, value)
-                }
-            }
-        }
-    }
-
-    fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
-        match *cnt {
-            rt::CountIs(n) => { Some(n) }
-            rt::CountImplied => { None }
-            rt::CountIsParam(i) => {
-                let v = self.args[i].value;
-                unsafe { Some(*(v as *any::Void as *uint)) }
-            }
-            rt::CountIsNextParam => {
-                let v = self.curarg.next().unwrap().value;
-                unsafe { Some(*(v as *any::Void as *uint)) }
-            }
-        }
-    }
-
-    fn execute(&mut self, method: &rt::Method, arg: Argument) -> Result {
-        match *method {
-            // Pluralization is selection upon a numeric value specified as the
-            // parameter.
-            rt::Plural(offset, ref selectors, ref default) => {
-                // This is validated at compile-time to be a pointer to a
-                // '&uint' value.
-                let value: &uint = unsafe { mem::transmute(arg.value) };
-                let value = *value;
-
-                // First, attempt to match against explicit values without the
-                // offsetted value
-                for s in selectors.iter() {
-                    match s.selector {
-                        rt::Literal(val) if value == val => {
-                            return self.runplural(value, s.result);
-                        }
-                        _ => {}
-                    }
-                }
-
-                // Next, offset the value and attempt to match against the
-                // keyword selectors.
-                let value = value - match offset { Some(i) => i, None => 0 };
-                for s in selectors.iter() {
-                    let run = match s.selector {
-                        rt::Keyword(rt::Zero) => value == 0,
-                        rt::Keyword(rt::One) => value == 1,
-                        rt::Keyword(rt::Two) => value == 2,
-
-                        // FIXME: Few/Many should have a user-specified boundary
-                        //      One possible option would be in the function
-                        //      pointer of the 'arg: Argument' struct.
-                        rt::Keyword(rt::Few) => value < 8,
-                        rt::Keyword(rt::Many) => value >= 8,
-
-                        rt::Literal(..) => false
-                    };
-                    if run {
-                        return self.runplural(value, s.result);
-                    }
-                }
-
-                self.runplural(value, *default)
-            }
-
-            // Select is just a matching against the string specified.
-            rt::Select(ref selectors, ref default) => {
-                // This is validated at compile-time to be a pointer to a
-                // string slice,
-                let value: & &str = unsafe { mem::transmute(arg.value) };
-                let value = *value;
-
-                for s in selectors.iter() {
-                    if s.selector == value {
-                        for piece in s.result.iter() {
-                            try!(self.run(piece, Some(value)));
-                        }
-                        return Ok(());
-                    }
-                }
-                for piece in default.iter() {
-                    try!(self.run(piece, Some(value)));
-                }
-                Ok(())
-            }
-        }
-    }
-
-    fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) -> Result {
-        ::uint::to_str_bytes(value, 10, |buf| {
-            let valuestr = str::from_utf8(buf).unwrap();
-            for piece in pieces.iter() {
-                try!(self.run(piece, Some(valuestr)));
-            }
-            Ok(())
-        })
-    }
-
-    // Helper methods used for padding and processing formatting arguments that
-    // all formatting traits can use.
-
-    /// Performs the correct padding for an integer which has already been
-    /// emitted into a byte-array. The byte-array should *not* contain the sign
-    /// for the integer, that will be added by this method.
-    ///
-    /// # Arguments
-    ///
-    /// * is_positive - whether the original integer was positive or not.
-    /// * prefix - if the '#' character (FlagAlternate) is provided, this
-    ///   is the prefix to put in front of the number.
-    /// * buf - the byte array that the number has been formatted into
-    ///
-    /// This function will correctly account for the flags provided as well as
-    /// the minimum width. It will not take precision into account.
-    pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, buf: &[u8]) -> Result {
-        use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
-
-        let mut width = buf.len();
-
-        let mut sign = None;
-        if !is_positive {
-            sign = Some('-'); width += 1;
-        } else if self.flags & (1 << (FlagSignPlus as uint)) != 0 {
-            sign = Some('+'); width += 1;
-        }
-
-        let mut prefixed = false;
-        if self.flags & (1 << (FlagAlternate as uint)) != 0 {
-            prefixed = true; width += prefix.len();
-        }
-
-        // Writes the sign if it exists, and then the prefix if it was requested
-        let write_prefix = |f: &mut Formatter| {
-            for c in sign.move_iter() { try!(f.buf.write_char(c)); }
-            if prefixed { f.buf.write_str(prefix) }
-            else { Ok(()) }
-        };
-
-        // The `width` field is more of a `min-width` parameter at this point.
-        match self.width {
-            // If there's no minimum length requirements then we can just
-            // write the bytes.
-            None => {
-                try!(write_prefix(self)); self.buf.write(buf)
-            }
-            // Check if we're over the minimum width, if so then we can also
-            // just write the bytes.
-            Some(min) if width >= min => {
-                try!(write_prefix(self)); self.buf.write(buf)
-            }
-            // The sign and prefix goes before the padding if the fill character
-            // is zero
-            Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
-                self.fill = '0';
-                try!(write_prefix(self));
-                self.with_padding(min - width, rt::AlignRight, |f| f.buf.write(buf))
-            }
-            // Otherwise, the sign and prefix goes after the padding
-            Some(min) => {
-                self.with_padding(min - width, rt::AlignRight, |f| {
-                    try!(write_prefix(f)); f.buf.write(buf)
-                })
-            }
-        }
-    }
-
-    /// This function takes a string slice and emits it to the internal buffer
-    /// after applying the relevant formatting flags specified. The flags
-    /// recognized for generic strings are:
-    ///
-    /// * width - the minimum width of what to emit
-    /// * fill/align - what to emit and where to emit it if the string
-    ///                provided needs to be padded
-    /// * precision - the maximum length to emit, the string is truncated if it
-    ///               is longer than this length
-    ///
-    /// Notably this function ignored the `flag` parameters
-    pub fn pad(&mut self, s: &str) -> Result {
-        // Make sure there's a fast path up front
-        if self.width.is_none() && self.precision.is_none() {
-            return self.buf.write(s.as_bytes());
-        }
-        // The `precision` field can be interpreted as a `max-width` for the
-        // string being formatted
-        match self.precision {
-            Some(max) => {
-                // If there's a maximum width and our string is longer than
-                // that, then we must always have truncation. This is the only
-                // case where the maximum length will matter.
-                let char_len = s.char_len();
-                if char_len >= max {
-                    let nchars = ::cmp::min(max, char_len);
-                    return self.buf.write(s.slice_chars(0, nchars).as_bytes());
-                }
-            }
-            None => {}
-        }
-        // The `width` field is more of a `min-width` parameter at this point.
-        match self.width {
-            // If we're under the maximum length, and there's no minimum length
-            // requirements, then we can just emit the string
-            None => self.buf.write(s.as_bytes()),
-            // If we're under the maximum width, check if we're over the minimum
-            // width, if so it's as easy as just emitting the string.
-            Some(width) if s.char_len() >= width => {
-                self.buf.write(s.as_bytes())
-            }
-            // If we're under both the maximum and the minimum width, then fill
-            // up the minimum width with the specified string + some alignment.
-            Some(width) => {
-                self.with_padding(width - s.len(), rt::AlignLeft, |me| {
-                    me.buf.write(s.as_bytes())
-                })
-            }
-        }
-    }
-
-    /// Runs a callback, emitting the correct padding either before or
-    /// afterwards depending on whether right or left alingment is requested.
-    fn with_padding(&mut self,
-                    padding: uint,
-                    default: rt::Alignment,
-                    f: |&mut Formatter| -> Result) -> Result {
-        let align = match self.align {
-            rt::AlignUnknown => default,
-            rt::AlignLeft | rt::AlignRight => self.align
-        };
-        if align == rt::AlignLeft {
-            try!(f(self));
-        }
-        let mut fill = [0u8, ..4];
-        let len = self.fill.encode_utf8(fill);
-        for _ in range(0, padding) {
-            try!(self.buf.write(fill.slice_to(len)));
-        }
-        if align == rt::AlignRight {
-            try!(f(self));
-        }
-        Ok(())
-    }
-}
-
-/// This is a function which calls are emitted to by the compiler itself to
-/// create the Argument structures that are passed into the `format` function.
-#[doc(hidden)] #[inline]
-pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result,
-                       t: &'a T) -> Argument<'a> {
-    unsafe {
-        Argument {
-            formatter: mem::transmute(f),
-            value: mem::transmute(t)
-        }
-    }
-}
-
-/// When the compiler determines that the type of an argument *must* be a string
-/// (such as for select), then it invokes this method.
-#[doc(hidden)] #[inline]
-pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
-    argument(secret_string, s)
-}
-
-/// When the compiler determines that the type of an argument *must* be a uint
-/// (such as for plural), then it invokes this method.
-#[doc(hidden)] #[inline]
-pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
-    argument(secret_unsigned, s)
-}
-
-// Implementations of the core formatting traits
-
-impl<T: Show> Show for @T {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
-}
-impl<T: Show> Show for Box<T> {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
-}
-impl<'a, T: Show> Show for &'a T {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
-}
-impl<'a, T: Show> Show for &'a mut T {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
-}
-
-impl Bool for bool {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_string(&(if *self {"true"} else {"false"}), f)
-    }
-}
-
-impl<'a, T: str::Str> String for T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        f.pad(self.as_slice())
-    }
-}
-
-impl Char for char {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        let mut utf8 = [0u8, ..4];
-        let amt = self.encode_utf8(utf8);
-        let s: &str = unsafe { mem::transmute(utf8.slice_to(amt)) };
-        secret_string(&s, f)
-    }
-}
-
-macro_rules! floating(($ty:ident) => {
-    impl Float for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            // FIXME: this shouldn't perform an allocation
-            let s = match fmt.precision {
-                Some(i) => ::$ty::to_str_exact(self.abs(), i),
-                None => ::$ty::to_str_digits(self.abs(), 6)
-            };
-            fmt.pad_integral(*self >= 0.0, "", s.as_bytes())
-        }
-    }
-
-    impl LowerExp for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            // FIXME: this shouldn't perform an allocation
-            let s = match fmt.precision {
-                Some(i) => ::$ty::to_str_exp_exact(self.abs(), i, false),
-                None => ::$ty::to_str_exp_digits(self.abs(), 6, false)
-            };
-            fmt.pad_integral(*self >= 0.0, "", s.as_bytes())
-        }
-    }
-
-    impl UpperExp for $ty {
-        fn fmt(&self, fmt: &mut Formatter) -> Result {
-            // FIXME: this shouldn't perform an allocation
-            let s = match fmt.precision {
-                Some(i) => ::$ty::to_str_exp_exact(self.abs(), i, true),
-                None => ::$ty::to_str_exp_digits(self.abs(), 6, true)
-            };
-            fmt.pad_integral(*self >= 0.0, "", s.as_bytes())
-        }
-    }
-})
-floating!(f32)
-floating!(f64)
-
-impl<T> Poly for T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match (f.width, f.precision) {
-            (None, None) => {
-                repr::write_repr(f.buf, self)
-            }
-
-            // If we have a specified width for formatting, then we have to make
-            // this allocation of a new string
-            _ => {
-                let s = repr::repr_to_str(self);
-                f.pad(s)
-            }
-        }
-    }
-}
-
-impl<T> Pointer for *T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        f.flags |= 1 << (rt::FlagAlternate as uint);
-        secret_lower_hex::<uint>(&(*self as uint), f)
-    }
-}
-impl<T> Pointer for *mut T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_pointer::<*T>(&(*self as *T), f)
-    }
-}
-impl<'a, T> Pointer for &'a T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_pointer::<*T>(&(&**self as *T), f)
-    }
-}
-impl<'a, T> Pointer for &'a mut T {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_pointer::<*T>(&(&**self as *T), f)
-    }
-}
-
-// Implementation of Show for various core types
-
-macro_rules! delegate(($ty:ty to $other:ident) => {
-    impl<'a> Show for $ty {
-        fn fmt(&self, f: &mut Formatter) -> Result {
-            (concat_idents!(secret_, $other)(self, f))
-        }
-    }
-})
-delegate!(~str to string)
-delegate!(&'a str to string)
-delegate!(bool to bool)
-delegate!(char to char)
-delegate!(f32 to float)
-delegate!(f64 to float)
-
-impl<T> Show for *T {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
-}
-impl<T> Show for *mut T {
-    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
-}
-
-macro_rules! peel(($name:ident, $($other:ident,)*) => (tuple!($($other,)*)))
-
-macro_rules! tuple (
-    () => ();
-    ( $($name:ident,)+ ) => (
-        impl<$($name:Show),*> Show for ($($name,)*) {
-            #[allow(uppercase_variables, dead_assignment)]
-            fn fmt(&self, f: &mut Formatter) -> Result {
-                try!(write!(f.buf, "("));
-                let ($(ref $name,)*) = *self;
-                let mut n = 0;
-                $(
-                    if n > 0 {
-                        try!(write!(f.buf, ", "));
-                    }
-                    try!(write!(f.buf, "{}", *$name));
-                    n += 1;
-                )*
-                if n == 1 {
-                    try!(write!(f.buf, ","));
-                }
-                write!(f.buf, ")")
-            }
-        }
-        peel!($($name,)*)
-    )
-)
-
-tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
-
-impl Show for Box<any::Any> {
-    fn fmt(&self, f: &mut Formatter) -> Result { f.pad("Box<Any>") }
-}
-
-impl<'a> Show for &'a any::Any {
-    fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
-}
-
-impl<T: Show> Show for Option<T> {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match *self {
-            Some(ref t) => write!(f.buf, "Some({})", *t),
-            None => write!(f.buf, "None"),
-        }
-    }
-}
-
-impl<T: Show, U: Show> Show for ::result::Result<T, U> {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match *self {
-            Ok(ref t) => write!(f.buf, "Ok({})", *t),
-            Err(ref t) => write!(f.buf, "Err({})", *t),
-        }
-    }
-}
-
-impl<'a, T: Show> Show for &'a [T] {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
-            try!(write!(f.buf, "["));
-        }
-        let mut is_first = true;
-        for x in self.iter() {
-            if is_first {
-                is_first = false;
-            } else {
-                try!(write!(f.buf, ", "));
-            }
-            try!(write!(f.buf, "{}", *x))
-        }
-        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
-            try!(write!(f.buf, "]"));
-        }
-        Ok(())
-    }
-}
-
-impl<'a, T: Show> Show for &'a mut [T] {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_show(&self.as_slice(), f)
-    }
-}
-
-impl<T: Show> Show for ~[T] {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        secret_show(&self.as_slice(), f)
-    }
-}
-
-impl Show for () {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        f.pad("()")
-    }
-}
-
-impl Show for TypeId {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        write!(f.buf, "TypeId \\{ {} \\}", self.hash())
-    }
-}
-
-impl<T: Show> Show for iter::MinMaxResult<T> {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match *self {
-            iter::NoElements =>
-                write!(f.buf, "NoElements"),
-            iter::OneElement(ref t) =>
-                write!(f.buf, "OneElement({})", *t),
-            iter::MinMax(ref t1, ref t2) =>
-                write!(f.buf, "MinMax({}, {})", *t1, *t2),
-        }
-    }
-}
-
-impl Show for cmp::Ordering {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match *self {
-            cmp::Less => write!(f.buf, "Less"),
-            cmp::Greater => write!(f.buf, "Greater"),
-            cmp::Equal => write!(f.buf, "Equal"),
-        }
-    }
-}
-
-impl<T: Copy + Show> Show for Cell<T> {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        write!(f.buf, r"Cell \{ value: {} \}", self.get())
-    }
-}
-
-impl Show for UTF16Item {
-    fn fmt(&self, f: &mut Formatter) -> Result {
-        match *self {
-            ScalarValue(c) => write!(f.buf, "ScalarValue({})", c),
-            LoneSurrogate(u) => write!(f.buf, "LoneSurrogate({})", u),
-        }
-    }
-}
-
-// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
-// it's a lot easier than creating all of the rt::Piece structures here.
diff --git a/src/libstd/fmt/num.rs b/src/libstd/fmt/num.rs
deleted file mode 100644 (file)
index 839b740..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright 2014 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.
-
-//! Integer and floating-point number formatting
-
-// FIXME: #6220 Implement floating point formatting
-
-#![allow(unsigned_negate)]
-
-use container::Container;
-use fmt;
-use iter::{Iterator, DoubleEndedIterator};
-use num::{Int, cast, zero};
-use option::{Some, None};
-use slice::{ImmutableVector, MutableVector};
-
-/// A type that represents a specific radix
-trait GenericRadix {
-    /// The number of digits.
-    fn base(&self) -> u8;
-
-    /// A radix-specific prefix string.
-    fn prefix(&self) -> &'static str { "" }
-
-    /// Converts an integer to corresponding radix digit.
-    fn digit(&self, x: u8) -> u8;
-
-    /// Format an integer using the radix using a formatter.
-    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
-        // The radix can be as low as 2, so we need a buffer of at least 64
-        // characters for a base 2 number.
-        let mut buf = [0u8, ..64];
-        let base = cast(self.base()).unwrap();
-        let mut curr = buf.len();
-        let is_positive = x >= zero();
-        if is_positive {
-            // Accumulate each digit of the number from the least significant
-            // to the most significant figure.
-            for byte in buf.mut_iter().rev() {
-                let n = x % base;                         // Get the current place value.
-                x = x / base;                             // Deaccumulate the number.
-                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
-                curr -= 1;
-                if x == zero() { break; }                 // No more digits left to accumulate.
-            }
-        } else {
-            // Do the same as above, but accounting for two's complement.
-            for byte in buf.mut_iter().rev() {
-                let n = -(x % base);                      // Get the current place value.
-                x = x / base;                             // Deaccumulate the number.
-                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
-                curr -= 1;
-                if x == zero() { break; }                 // No more digits left to accumulate.
-            }
-        }
-        f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr))
-    }
-}
-
-/// A binary (base 2) radix
-#[deriving(Clone, Eq)]
-struct Binary;
-
-/// An octal (base 8) radix
-#[deriving(Clone, Eq)]
-struct Octal;
-
-/// A decimal (base 10) radix
-#[deriving(Clone, Eq)]
-struct Decimal;
-
-/// A hexadecimal (base 16) radix, formatted with lower-case characters
-#[deriving(Clone, Eq)]
-struct LowerHex;
-
-/// A hexadecimal (base 16) radix, formatted with upper-case characters
-#[deriving(Clone, Eq)]
-pub struct UpperHex;
-
-macro_rules! radix {
-    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
-        impl GenericRadix for $T {
-            fn base(&self) -> u8 { $base }
-            fn prefix(&self) -> &'static str { $prefix }
-            fn digit(&self, x: u8) -> u8 {
-                match x {
-                    $($x => $conv,)+
-                    x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
-                }
-            }
-        }
-    }
-}
-
-radix!(Binary,    2, "0b", x @  0 .. 2 => '0' as u8 + x)
-radix!(Octal,     8, "0o", x @  0 .. 7 => '0' as u8 + x)
-radix!(Decimal,  10, "",   x @  0 .. 9 => '0' as u8 + x)
-radix!(LowerHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
-                           x @ 10 ..15 => 'a' as u8 + (x - 10))
-radix!(UpperHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
-                           x @ 10 ..15 => 'A' as u8 + (x - 10))
-
-/// A radix with in the range of `2..36`.
-#[deriving(Clone, Eq)]
-pub struct Radix {
-    base: u8,
-}
-
-impl Radix {
-    fn new(base: u8) -> Radix {
-        assert!(2 <= base && base <= 36, "the base must be in the range of 0..36: {}", base);
-        Radix { base: base }
-    }
-}
-
-impl GenericRadix for Radix {
-    fn base(&self) -> u8 { self.base }
-    fn digit(&self, x: u8) -> u8 {
-        match x {
-            x @  0 ..9 => '0' as u8 + x,
-            x if x < self.base() => 'a' as u8 + (x - 10),
-            x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
-        }
-    }
-}
-
-/// A helper type for formatting radixes.
-pub struct RadixFmt<T, R>(T, R);
-
-/// Constructs a radix formatter in the range of `2..36`.
-///
-/// # Example
-///
-/// ~~~
-/// use std::fmt::radix;
-/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
-/// ~~~
-pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
-    RadixFmt(x, Radix::new(base))
-}
-
-macro_rules! radix_fmt {
-    ($T:ty as $U:ty, $fmt:ident) => {
-        impl fmt::Show for RadixFmt<$T, Radix> {
-            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
-            }
-        }
-    }
-}
-macro_rules! int_base {
-    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
-        impl fmt::$Trait for $T {
-            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                $Radix.fmt_int(*self as $U, f)
-            }
-        }
-    }
-}
-macro_rules! integer {
-    ($Int:ident, $Uint:ident) => {
-        int_base!(Show     for $Int as $Int   -> Decimal)
-        int_base!(Signed   for $Int as $Int   -> Decimal)
-        int_base!(Binary   for $Int as $Uint  -> Binary)
-        int_base!(Octal    for $Int as $Uint  -> Octal)
-        int_base!(LowerHex for $Int as $Uint  -> LowerHex)
-        int_base!(UpperHex for $Int as $Uint  -> UpperHex)
-        radix_fmt!($Int as $Uint, fmt_int)
-
-        int_base!(Show     for $Uint as $Uint -> Decimal)
-        int_base!(Unsigned for $Uint as $Uint -> Decimal)
-        int_base!(Binary   for $Uint as $Uint -> Binary)
-        int_base!(Octal    for $Uint as $Uint -> Octal)
-        int_base!(LowerHex for $Uint as $Uint -> LowerHex)
-        int_base!(UpperHex for $Uint as $Uint -> UpperHex)
-        radix_fmt!($Uint as $Uint, fmt_int)
-    }
-}
-integer!(int, uint)
-integer!(i8, u8)
-integer!(i16, u16)
-integer!(i32, u32)
-integer!(i64, u64)
-
-#[cfg(test)]
-mod tests {
-    use fmt::radix;
-    use super::{Binary, Octal, Decimal, LowerHex, UpperHex};
-    use super::{GenericRadix, Radix};
-    use str::StrAllocating;
-
-    #[test]
-    fn test_radix_base() {
-        assert_eq!(Binary.base(), 2);
-        assert_eq!(Octal.base(), 8);
-        assert_eq!(Decimal.base(), 10);
-        assert_eq!(LowerHex.base(), 16);
-        assert_eq!(UpperHex.base(), 16);
-        assert_eq!(Radix { base: 36 }.base(), 36);
-    }
-
-    #[test]
-    fn test_radix_prefix() {
-        assert_eq!(Binary.prefix(), "0b");
-        assert_eq!(Octal.prefix(), "0o");
-        assert_eq!(Decimal.prefix(), "");
-        assert_eq!(LowerHex.prefix(), "0x");
-        assert_eq!(UpperHex.prefix(), "0x");
-        assert_eq!(Radix { base: 36 }.prefix(), "");
-    }
-
-    #[test]
-    fn test_radix_digit() {
-        assert_eq!(Binary.digit(0), '0' as u8);
-        assert_eq!(Binary.digit(2), '2' as u8);
-        assert_eq!(Octal.digit(0), '0' as u8);
-        assert_eq!(Octal.digit(7), '7' as u8);
-        assert_eq!(Decimal.digit(0), '0' as u8);
-        assert_eq!(Decimal.digit(9), '9' as u8);
-        assert_eq!(LowerHex.digit(0), '0' as u8);
-        assert_eq!(LowerHex.digit(10), 'a' as u8);
-        assert_eq!(LowerHex.digit(15), 'f' as u8);
-        assert_eq!(UpperHex.digit(0), '0' as u8);
-        assert_eq!(UpperHex.digit(10), 'A' as u8);
-        assert_eq!(UpperHex.digit(15), 'F' as u8);
-        assert_eq!(Radix { base: 36 }.digit(0), '0' as u8);
-        assert_eq!(Radix { base: 36 }.digit(15), 'f' as u8);
-        assert_eq!(Radix { base: 36 }.digit(35), 'z' as u8);
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_hex_radix_digit_overflow() {
-        let _ = LowerHex.digit(16);
-    }
-
-    #[test]
-    fn test_format_int() {
-        // Formatting integers should select the right implementation based off
-        // the type of the argument. Also, hex/octal/binary should be defined
-        // for integers, but they shouldn't emit the negative sign.
-        assert_eq!(format!("{}", 1i), "1".to_owned());
-        assert_eq!(format!("{}", 1i8), "1".to_owned());
-        assert_eq!(format!("{}", 1i16), "1".to_owned());
-        assert_eq!(format!("{}", 1i32), "1".to_owned());
-        assert_eq!(format!("{}", 1i64), "1".to_owned());
-        assert_eq!(format!("{:d}", -1i), "-1".to_owned());
-        assert_eq!(format!("{:d}", -1i8), "-1".to_owned());
-        assert_eq!(format!("{:d}", -1i16), "-1".to_owned());
-        assert_eq!(format!("{:d}", -1i32), "-1".to_owned());
-        assert_eq!(format!("{:d}", -1i64), "-1".to_owned());
-        assert_eq!(format!("{:t}", 1i), "1".to_owned());
-        assert_eq!(format!("{:t}", 1i8), "1".to_owned());
-        assert_eq!(format!("{:t}", 1i16), "1".to_owned());
-        assert_eq!(format!("{:t}", 1i32), "1".to_owned());
-        assert_eq!(format!("{:t}", 1i64), "1".to_owned());
-        assert_eq!(format!("{:x}", 1i), "1".to_owned());
-        assert_eq!(format!("{:x}", 1i8), "1".to_owned());
-        assert_eq!(format!("{:x}", 1i16), "1".to_owned());
-        assert_eq!(format!("{:x}", 1i32), "1".to_owned());
-        assert_eq!(format!("{:x}", 1i64), "1".to_owned());
-        assert_eq!(format!("{:X}", 1i), "1".to_owned());
-        assert_eq!(format!("{:X}", 1i8), "1".to_owned());
-        assert_eq!(format!("{:X}", 1i16), "1".to_owned());
-        assert_eq!(format!("{:X}", 1i32), "1".to_owned());
-        assert_eq!(format!("{:X}", 1i64), "1".to_owned());
-        assert_eq!(format!("{:o}", 1i), "1".to_owned());
-        assert_eq!(format!("{:o}", 1i8), "1".to_owned());
-        assert_eq!(format!("{:o}", 1i16), "1".to_owned());
-        assert_eq!(format!("{:o}", 1i32), "1".to_owned());
-        assert_eq!(format!("{:o}", 1i64), "1".to_owned());
-
-        assert_eq!(format!("{}", 1u), "1".to_owned());
-        assert_eq!(format!("{}", 1u8), "1".to_owned());
-        assert_eq!(format!("{}", 1u16), "1".to_owned());
-        assert_eq!(format!("{}", 1u32), "1".to_owned());
-        assert_eq!(format!("{}", 1u64), "1".to_owned());
-        assert_eq!(format!("{:u}", 1u), "1".to_owned());
-        assert_eq!(format!("{:u}", 1u8), "1".to_owned());
-        assert_eq!(format!("{:u}", 1u16), "1".to_owned());
-        assert_eq!(format!("{:u}", 1u32), "1".to_owned());
-        assert_eq!(format!("{:u}", 1u64), "1".to_owned());
-        assert_eq!(format!("{:t}", 1u), "1".to_owned());
-        assert_eq!(format!("{:t}", 1u8), "1".to_owned());
-        assert_eq!(format!("{:t}", 1u16), "1".to_owned());
-        assert_eq!(format!("{:t}", 1u32), "1".to_owned());
-        assert_eq!(format!("{:t}", 1u64), "1".to_owned());
-        assert_eq!(format!("{:x}", 1u), "1".to_owned());
-        assert_eq!(format!("{:x}", 1u8), "1".to_owned());
-        assert_eq!(format!("{:x}", 1u16), "1".to_owned());
-        assert_eq!(format!("{:x}", 1u32), "1".to_owned());
-        assert_eq!(format!("{:x}", 1u64), "1".to_owned());
-        assert_eq!(format!("{:X}", 1u), "1".to_owned());
-        assert_eq!(format!("{:X}", 1u8), "1".to_owned());
-        assert_eq!(format!("{:X}", 1u16), "1".to_owned());
-        assert_eq!(format!("{:X}", 1u32), "1".to_owned());
-        assert_eq!(format!("{:X}", 1u64), "1".to_owned());
-        assert_eq!(format!("{:o}", 1u), "1".to_owned());
-        assert_eq!(format!("{:o}", 1u8), "1".to_owned());
-        assert_eq!(format!("{:o}", 1u16), "1".to_owned());
-        assert_eq!(format!("{:o}", 1u32), "1".to_owned());
-        assert_eq!(format!("{:o}", 1u64), "1".to_owned());
-
-        // Test a larger number
-        assert_eq!(format!("{:t}", 55), "110111".to_owned());
-        assert_eq!(format!("{:o}", 55), "67".to_owned());
-        assert_eq!(format!("{:d}", 55), "55".to_owned());
-        assert_eq!(format!("{:x}", 55), "37".to_owned());
-        assert_eq!(format!("{:X}", 55), "37".to_owned());
-    }
-
-    #[test]
-    fn test_format_int_zero() {
-        assert_eq!(format!("{}", 0i), "0".to_owned());
-        assert_eq!(format!("{:d}", 0i), "0".to_owned());
-        assert_eq!(format!("{:t}", 0i), "0".to_owned());
-        assert_eq!(format!("{:o}", 0i), "0".to_owned());
-        assert_eq!(format!("{:x}", 0i), "0".to_owned());
-        assert_eq!(format!("{:X}", 0i), "0".to_owned());
-
-        assert_eq!(format!("{}", 0u), "0".to_owned());
-        assert_eq!(format!("{:u}", 0u), "0".to_owned());
-        assert_eq!(format!("{:t}", 0u), "0".to_owned());
-        assert_eq!(format!("{:o}", 0u), "0".to_owned());
-        assert_eq!(format!("{:x}", 0u), "0".to_owned());
-        assert_eq!(format!("{:X}", 0u), "0".to_owned());
-    }
-
-    #[test]
-    fn test_format_int_flags() {
-        assert_eq!(format!("{:3d}", 1), "  1".to_owned());
-        assert_eq!(format!("{:>3d}", 1), "  1".to_owned());
-        assert_eq!(format!("{:>+3d}", 1), " +1".to_owned());
-        assert_eq!(format!("{:<3d}", 1), "1  ".to_owned());
-        assert_eq!(format!("{:#d}", 1), "1".to_owned());
-        assert_eq!(format!("{:#x}", 10), "0xa".to_owned());
-        assert_eq!(format!("{:#X}", 10), "0xA".to_owned());
-        assert_eq!(format!("{:#5x}", 10), "  0xa".to_owned());
-        assert_eq!(format!("{:#o}", 10), "0o12".to_owned());
-        assert_eq!(format!("{:08x}", 10), "0000000a".to_owned());
-        assert_eq!(format!("{:8x}", 10), "       a".to_owned());
-        assert_eq!(format!("{:<8x}", 10), "a       ".to_owned());
-        assert_eq!(format!("{:>8x}", 10), "       a".to_owned());
-        assert_eq!(format!("{:#08x}", 10), "0x00000a".to_owned());
-        assert_eq!(format!("{:08d}", -10), "-0000010".to_owned());
-        assert_eq!(format!("{:x}", -1u8), "ff".to_owned());
-        assert_eq!(format!("{:X}", -1u8), "FF".to_owned());
-        assert_eq!(format!("{:t}", -1u8), "11111111".to_owned());
-        assert_eq!(format!("{:o}", -1u8), "377".to_owned());
-        assert_eq!(format!("{:#x}", -1u8), "0xff".to_owned());
-        assert_eq!(format!("{:#X}", -1u8), "0xFF".to_owned());
-        assert_eq!(format!("{:#t}", -1u8), "0b11111111".to_owned());
-        assert_eq!(format!("{:#o}", -1u8), "0o377".to_owned());
-    }
-
-    #[test]
-    fn test_format_int_sign_padding() {
-        assert_eq!(format!("{:+5d}", 1), "   +1".to_owned());
-        assert_eq!(format!("{:+5d}", -1), "   -1".to_owned());
-        assert_eq!(format!("{:05d}", 1), "00001".to_owned());
-        assert_eq!(format!("{:05d}", -1), "-0001".to_owned());
-        assert_eq!(format!("{:+05d}", 1), "+0001".to_owned());
-        assert_eq!(format!("{:+05d}", -1), "-0001".to_owned());
-    }
-
-    #[test]
-    fn test_format_int_twos_complement() {
-        use {i8, i16, i32, i64};
-        assert_eq!(format!("{}", i8::MIN), "-128".to_owned());
-        assert_eq!(format!("{}", i16::MIN), "-32768".to_owned());
-        assert_eq!(format!("{}", i32::MIN), "-2147483648".to_owned());
-        assert_eq!(format!("{}", i64::MIN), "-9223372036854775808".to_owned());
-    }
-
-    #[test]
-    fn test_format_radix() {
-        assert_eq!(format!("{:04}", radix(3, 2)), "0011".to_owned());
-        assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_radix_base_too_large() {
-        let _ = radix(55, 37);
-    }
-}
-
-#[cfg(test)]
-mod bench {
-    extern crate test;
-
-    mod uint {
-        use super::test::Bencher;
-        use fmt::radix;
-        use rand::{XorShiftRng, Rng};
-        use realstd::result::ResultUnwrap;
-
-        #[bench]
-        fn format_bin(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:t}", rng.gen::<uint>()); })
-        }
-
-        #[bench]
-        fn format_oct(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:o}", rng.gen::<uint>()); })
-        }
-
-        #[bench]
-        fn format_dec(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:u}", rng.gen::<uint>()); })
-        }
-
-        #[bench]
-        fn format_hex(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:x}", rng.gen::<uint>()); })
-        }
-
-        #[bench]
-        fn format_base_36(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{}", radix(rng.gen::<uint>(), 36)); })
-        }
-    }
-
-    mod int {
-        use super::test::Bencher;
-        use fmt::radix;
-        use rand::{XorShiftRng, Rng};
-        use realstd::result::ResultUnwrap;
-
-        #[bench]
-        fn format_bin(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:t}", rng.gen::<int>()); })
-        }
-
-        #[bench]
-        fn format_oct(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:o}", rng.gen::<int>()); })
-        }
-
-        #[bench]
-        fn format_dec(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:d}", rng.gen::<int>()); })
-        }
-
-        #[bench]
-        fn format_hex(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{:x}", rng.gen::<int>()); })
-        }
-
-        #[bench]
-        fn format_base_36(b: &mut Bencher) {
-            let mut rng = XorShiftRng::new().unwrap();
-            b.iter(|| { format!("{}", radix(rng.gen::<int>(), 36)); })
-        }
-    }
-}
diff --git a/src/libstd/fmt/rt.rs b/src/libstd/fmt/rt.rs
deleted file mode 100644 (file)
index 00c8661..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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 is an internal module used by the ifmt! runtime. These structures are
-//! emitted to static arrays to precompile format strings ahead of time.
-//!
-//! These definitions are similar to their `ct` equivalents, but differ in that
-//! these can be statically allocated and are slightly optimized for the runtime
-
-#![allow(missing_doc)]
-#![doc(hidden)]
-
-use option::Option;
-
-pub enum Piece<'a> {
-    String(&'a str),
-    // FIXME(#8259): this shouldn't require the unit-value here
-    CurrentArgument(()),
-    Argument(Argument<'a>),
-}
-
-pub struct Argument<'a> {
-    pub position: Position,
-    pub format: FormatSpec,
-    pub method: Option<&'a Method<'a>>
-}
-
-pub struct FormatSpec {
-    pub fill: char,
-    pub align: Alignment,
-    pub flags: uint,
-    pub precision: Count,
-    pub width: Count,
-}
-
-#[deriving(Eq)]
-pub enum Alignment {
-    AlignLeft,
-    AlignRight,
-    AlignUnknown,
-}
-
-pub enum Count {
-    CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
-}
-
-pub enum Position {
-    ArgumentNext, ArgumentIs(uint)
-}
-
-pub enum Flag {
-    FlagSignPlus,
-    FlagSignMinus,
-    FlagAlternate,
-    FlagSignAwareZeroPad,
-}
-
-pub enum Method<'a> {
-    Plural(Option<uint>, &'a [PluralArm<'a>], &'a [Piece<'a>]),
-    Select(&'a [SelectArm<'a>], &'a [Piece<'a>]),
-}
-
-pub enum PluralSelector {
-    Keyword(PluralKeyword),
-    Literal(uint),
-}
-
-pub enum PluralKeyword {
-    Zero,
-    One,
-    Two,
-    Few,
-    Many,
-}
-
-pub struct PluralArm<'a> {
-    pub selector: PluralSelector,
-    pub result: &'a [Piece<'a>],
-}
-
-pub struct SelectArm<'a> {
-    pub selector: &'a str,
-    pub result: &'a [Piece<'a>],
-}
index a8e7b324bd755e3285abdc705b561fdecf9c1b70..2880365cf348f5c6a15f63988af56ded515bb8b9 100644 (file)
@@ -16,7 +16,7 @@
 use iter::ExactSize;
 use ops::Drop;
 use option::{Some, None, Option};
-use result::{Ok, Err, ResultUnwrap};
+use result::{Ok, Err};
 use slice::{ImmutableVector, MutableVector};
 use slice;
 use vec::Vec;
@@ -209,7 +209,7 @@ fn flush(&mut self) -> IoResult<()> {
 impl<W: Writer> Drop for BufferedWriter<W> {
     fn drop(&mut self) {
         if self.inner.is_some() {
-            // FIXME(#12628): should this error be ignored?
+            // dtors should not fail, so we ignore a failed flush
             let _ = self.flush_buf();
         }
     }
@@ -370,6 +370,7 @@ mod test {
     use io;
     use prelude::*;
     use super::*;
+    use super::super::{IoResult, EndOfFile};
     use super::super::mem::{MemReader, MemWriter, BufReader};
     use self::test::Bencher;
     use str::StrSlice;
@@ -584,6 +585,24 @@ fn test_chars() {
         assert_eq!(it.next(), None);
     }
 
+    #[test]
+    #[should_fail]
+    fn dont_fail_in_drop_on_failed_flush() {
+        struct FailFlushWriter;
+
+        impl Writer for FailFlushWriter {
+            fn write(&mut self, _buf: &[u8]) -> IoResult<()> { Ok(()) }
+            fn flush(&mut self) -> IoResult<()> { Err(io::standard_error(EndOfFile)) }
+        }
+
+        let writer = FailFlushWriter;
+        let _writer = BufferedWriter::new(writer);
+
+        // Trigger failure. If writer fails *again* due to the flush
+        // error then the process will abort.
+        fail!();
+    }
+
     #[bench]
     fn bench_buffered_reader(b: &mut Bencher) {
         b.iter(|| {
diff --git a/src/libstd/io/flate.rs b/src/libstd/io/flate.rs
deleted file mode 100644 (file)
index 0cf00b2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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.
-
-//! Some various other I/O types
-
-// FIXME(#3660): should move to libextra
-
-use prelude::*;
-use super::*;
-
-/// A Writer decorator that compresses using the 'deflate' scheme
-pub struct DeflateWriter<W> {
-    priv inner_writer: W
-}
-
-impl<W: Writer> DeflateWriter<W> {
-    pub fn new(inner_writer: W) -> DeflateWriter<W> {
-        DeflateWriter {
-            inner_writer: inner_writer
-        }
-    }
-}
-
-impl<W: Writer> Writer for DeflateWriter<W> {
-    fn write(&mut self, _buf: &[u8]) { fail!() }
-
-    fn flush(&mut self) { fail!() }
-}
-
-/// A Reader decorator that decompresses using the 'deflate' scheme
-pub struct InflateReader<R> {
-    priv inner_reader: R
-}
-
-impl<R: Reader> InflateReader<R> {
-    pub fn new(inner_reader: R) -> InflateReader<R> {
-        InflateReader {
-            inner_reader: inner_reader
-        }
-    }
-}
-
-impl<R: Reader> Reader for InflateReader<R> {
-    fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() }
-}
index 2ee3ee597313bb063806d9b37d8c68704b6add26..a043722581ba26d337d839bfed215c293b41a312 100644 (file)
@@ -245,7 +245,7 @@ fn file_product(p: &Path) -> IoResult<u32> {
 pub use self::net::tcp::TcpStream;
 pub use self::net::udp::UdpStream;
 pub use self::pipe::PipeStream;
-pub use self::process::{Process, ProcessConfig};
+pub use self::process::{Process, Command};
 pub use self::tempfile::TempDir;
 
 pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
@@ -381,9 +381,9 @@ pub fn last_error() -> IoError {
 
 impl fmt::Show for IoError {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        try!(fmt.buf.write_str(self.desc));
+        try!(write!(fmt, "{}", self.desc));
         match self.detail {
-            Some(ref s) => write!(fmt.buf, " ({})", *s),
+            Some(ref s) => write!(fmt, " ({})", *s),
             None => Ok(())
         }
     }
@@ -964,6 +964,42 @@ pub trait Writer {
     /// decide whether their stream needs to be buffered or not.
     fn flush(&mut self) -> IoResult<()> { Ok(()) }
 
+    /// Writes a formatted string into this writer, returning any error
+    /// encountered.
+    ///
+    /// This method is primarily used to interface with the `format_args!`
+    /// macro, but it is rare that this should explicitly be called. The
+    /// `write!` macro should be favored to invoke this method instead.
+    ///
+    /// # Errors
+    ///
+    /// This function will return any I/O error reported while formatting.
+    fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
+        // Create a shim which translates a Writer to a FormatWriter and saves
+        // off I/O errors. instead of discarding them
+        struct Adaptor<'a, T> {
+            inner: &'a mut T,
+            error: IoResult<()>,
+        }
+        impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
+            fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+                match self.inner.write(bytes) {
+                    Ok(()) => Ok(()),
+                    Err(e) => {
+                        self.error = Err(e);
+                        Err(fmt::WriteError)
+                    }
+                }
+            }
+        }
+
+        let mut output = Adaptor { inner: self, error: Ok(()) };
+        match fmt::write(&mut output, fmt) {
+            Ok(()) => Ok(()),
+            Err(..) => output.error
+        }
+    }
+
     /// Write a rust string into this sink.
     ///
     /// The bytes written will be the UTF-8 encoded version of the input string.
index 7621a7ec4cd5efdc948a9d9e20438225a1f7429b..f469c419e8ef7962b0994a7a8f1c8082aed5fd1b 100644 (file)
@@ -35,22 +35,22 @@ impl fmt::Show for IpAddr {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             Ipv4Addr(a, b, c, d) =>
-                write!(fmt.buf, "{}.{}.{}.{}", a, b, c, d),
+                write!(fmt, "{}.{}.{}.{}", a, b, c, d),
 
             // Ipv4 Compatible address
             Ipv6Addr(0, 0, 0, 0, 0, 0, g, h) => {
-                write!(fmt.buf, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+                write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
                        (h >> 8) as u8, h as u8)
             }
 
             // Ipv4-Mapped address
             Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => {
-                write!(fmt.buf, "::FFFF:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+                write!(fmt, "::FFFF:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
                        (h >> 8) as u8, h as u8)
             }
 
             Ipv6Addr(a, b, c, d, e, f, g, h) =>
-                write!(fmt.buf, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
+                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                        a, b, c, d, e, f, g, h)
         }
     }
@@ -65,8 +65,8 @@ pub struct SocketAddr {
 impl fmt::Show for SocketAddr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.ip {
-            Ipv4Addr(..) => write!(f.buf, "{}:{}", self.ip, self.port),
-            Ipv6Addr(..) => write!(f.buf, "[{}]:{}", self.ip, self.port),
+            Ipv4Addr(..) => write!(f, "{}:{}", self.ip, self.port),
+            Ipv6Addr(..) => write!(f, "[{}]:{}", self.ip, self.port),
         }
     }
 }
index 864a70105412ab30c2e75c6cb531ce751344a06f..875dd01be823bfcf6f99bb6235824a98e2f65b61 100644 (file)
@@ -384,8 +384,6 @@ mod test {
     })
 
     pub fn socket_name(addr: SocketAddr) {
-        use result::ResultUnwrap;
-
         let server = UdpSocket::bind(addr);
 
         assert!(server.is_ok());
index 349cac723ff5b3303d487accbcb7283c6fd14599..fc760e6fe4ca312cd874369a7ac17df517b2dc1a 100644 (file)
 
 use prelude::*;
 
+use std::str;
 use fmt;
 use io::IoResult;
 use io;
 use libc;
 use mem;
 use owned::Box;
-use rt::rtio::{RtioProcess, IoFactory, LocalIo};
+use rt::rtio::{RtioProcess, ProcessConfig, IoFactory, LocalIo};
+use c_str::CString;
 
 /// Signal a process to exit, without forcibly killing it. Corresponds to
 /// SIGTERM on unix platforms.
 
 /// Representation of a running or exited child process.
 ///
-/// This structure is used to create, run, and manage child processes. A process
-/// is configured with the `ProcessConfig` struct which contains specific
-/// options for dictating how the child is spawned.
+/// This structure is used to represent and manage child processes. A child
+/// process is created via the `Command` struct, which configures the spawning
+/// process and can itself be constructed using a builder-style interface.
 ///
 /// # Example
 ///
 /// ```should_fail
-/// use std::io::Process;
+/// use std::io::Command;
 ///
-/// let mut child = match Process::new("/bin/cat", ["file.txt".to_owned()]) {
+/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() {
 ///     Ok(child) => child,
 ///     Err(e) => fail!("failed to execute child: {}", e),
 /// };
@@ -74,71 +76,244 @@ pub struct Process {
     pub extra_io: Vec<Option<io::PipeStream>>,
 }
 
-/// This configuration describes how a new process should be spawned. A blank
-/// configuration can be created with `ProcessConfig::new()`. It is also
-/// recommented to use a functional struct update pattern when creating process
-/// configuration:
+/// The `Command` type acts as a process builder, providing fine-grained control
+/// over how a new process should be spawned. A default configuration can be
+/// generated using `Command::new(program)`, where `program` gives a path to the
+/// program to be executed. Additional builder methods allow the configuration
+/// to be changed (for example, by adding arguments) prior to spawning:
 ///
 /// ```
-/// use std::io::ProcessConfig;
+/// use std::io::Command;
 ///
-/// let config = ProcessConfig {
-///     program: "/bin/sh",
-///     args: &["-c".to_owned(), "true".to_owned()],
-///     .. ProcessConfig::new()
+/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() {
+///   Ok(p) => p,
+///   Err(e) => fail!("failed to execute process: {}", e),
 /// };
+///
+/// let output = process.stdout.get_mut_ref().read_to_end();
 /// ```
-pub struct ProcessConfig<'a> {
-    /// Path to the program to run
-    pub program: &'a str,
+pub struct Command {
+    // The internal data for the builder. Documented by the builder
+    // methods below, and serialized into rt::rtio::ProcessConfig.
+    program: CString,
+    args: Vec<CString>,
+    env: Option<Vec<(CString, CString)>>,
+    cwd: Option<CString>,
+    stdin: StdioContainer,
+    stdout: StdioContainer,
+    stderr: StdioContainer,
+    extra_io: Vec<StdioContainer>,
+    uid: Option<uint>,
+    gid: Option<uint>,
+    detach: bool,
+}
+
+// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
+// we cannot usefully take ToCStr arguments by reference (without forcing an
+// additional & around &str). So we are instead temporarily adding an instance
+// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
+// instance should be removed, and arguments bound by ToCStr should be passed by
+// reference. (Here: {new, arg, args, env}.)
+
+impl Command {
+    /// Constructs a new `Command` for launching the program at
+    /// path `program`, with the following default configuration:
+    ///
+    /// * No arguments to the program
+    /// * Inherit the current process's environment
+    /// * Inherit the current process's working directory
+    /// * A readable pipe for stdin (file descriptor 0)
+    /// * A writeable pipe for stdour and stderr (file descriptors 1 and 2)
+    ///
+    /// Builder methods are provided to change these defaults and
+    /// otherwise configure the process.
+    pub fn new<T:ToCStr>(program: T) -> Command {
+        Command {
+            program: program.to_c_str(),
+            args: Vec::new(),
+            env: None,
+            cwd: None,
+            stdin: CreatePipe(true, false),
+            stdout: CreatePipe(false, true),
+            stderr: CreatePipe(false, true),
+            extra_io: Vec::new(),
+            uid: None,
+            gid: None,
+            detach: false,
+        }
+    }
+
+    /// Add an argument to pass to the program.
+    pub fn arg<'a, T:ToCStr>(&'a mut self, arg: T) -> &'a mut Command {
+        self.args.push(arg.to_c_str());
+        self
+    }
 
-    /// Arguments to pass to the program (doesn't include the program itself)
-    pub args: &'a [~str],
+    /// Add multiple arguments to pass to the program.
+    pub fn args<'a, T:ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command {
+        self.args.extend(args.iter().map(|arg| arg.to_c_str()));;
+        self
+    }
 
-    /// Optional environment to specify for the program. If this is None, then
-    /// it will inherit the current process's environment.
-    pub env: Option<&'a [(~str, ~str)]>,
+    /// Sets the environment for the child process (rather than inheriting it
+    /// from the current process).
+
+    // FIXME (#13851): We should change this interface to allow clients to (1)
+    // build up the env vector incrementally and (2) allow both inheriting the
+    // current process's environment AND overriding/adding additional
+    // environment variables. The underlying syscalls assume that the
+    // environment has no duplicate names, so we really want to use a hashtable
+    // to compute the environment to pass down to the syscall; resolving issue
+    // #13851 will make it possible to use the standard hashtable.
+    pub fn env<'a, T:ToCStr>(&'a mut self, env: &[(T,T)]) -> &'a mut Command {
+        self.env = Some(env.iter().map(|&(ref name, ref val)| {
+            (name.to_c_str(), val.to_c_str())
+        }).collect());
+        self
+    }
 
-    /// Optional working directory for the new process. If this is None, then
-    /// the current directory of the running process is inherited.
-    pub cwd: Option<&'a Path>,
+    /// Set the working directory for the child process.
+    pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command {
+        self.cwd = Some(dir.to_c_str());
+        self
+    }
 
     /// Configuration for the child process's stdin handle (file descriptor 0).
-    /// This field defaults to `CreatePipe(true, false)` so the input can be
-    /// written to.
-    pub stdin: StdioContainer,
+    /// Defaults to `CreatePipe(true, false)` so the input can be written to.
+    pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
+        self.stdin = cfg;
+        self
+    }
 
     /// Configuration for the child process's stdout handle (file descriptor 1).
-    /// This field defaults to `CreatePipe(false, true)` so the output can be
-    /// collected.
-    pub stdout: StdioContainer,
-
-    /// Configuration for the child process's stdout handle (file descriptor 2).
-    /// This field defaults to `CreatePipe(false, true)` so the output can be
-    /// collected.
-    pub stderr: StdioContainer,
-
-    /// 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
-    /// 3 and go to the length of this array. The first three file descriptors
-    /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
-    /// `stderr` fields.
-    pub extra_io: &'a [StdioContainer],
+    /// Defaults to `CreatePipe(false, true)` so the output can be collected.
+    pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
+        self.stdout = cfg;
+        self
+    }
+
+    /// Configuration for the child process's stderr handle (file descriptor 2).
+    /// Defaults to `CreatePipe(false, true)` so the output can be collected.
+    pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
+        self.stderr = cfg;
+        self
+    }
+    /// Attaches a stream/file descriptor/pipe to the child process. Inherited
+    /// file descriptors are numbered consecutively, starting at 3; the first
+    /// three file descriptors (stdin/stdout/stderr) are configured with the
+    /// `stdin`, `stdout`, and `stderr` methods.
+    pub fn extra_io<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command {
+        self.extra_io.push(cfg);
+        self
+    }
 
     /// Sets the child process's user id. This translates to a `setuid` call in
     /// the child process. Setting this value on windows will cause the spawn to
     /// fail. Failure in the `setuid` call on unix will also cause the spawn to
     /// fail.
-    pub uid: Option<uint>,
+    pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command {
+        self.uid = Some(id);
+        self
+    }
 
     /// Similar to `uid`, but sets the group id of the child process. This has
     /// the same semantics as the `uid` field.
-    pub gid: Option<uint>,
+    pub fn gid<'a>(&'a mut self, id: uint) -> &'a mut Command {
+        self.gid = Some(id);
+        self
+    }
 
-    /// If true, the child process is spawned in a detached state. On unix, this
+    /// Sets the child process to be spawned in a detached state. On unix, this
     /// means that the child is the leader of a new process group.
-    pub detach: bool,
+    pub fn detached<'a>(&'a mut self) -> &'a mut Command {
+        self.detach = true;
+        self
+    }
+
+    /// Executes the command as a child process, which is returned.
+    pub fn spawn(&self) -> IoResult<Process> {
+        LocalIo::maybe_raise(|io| {
+            let cfg = ProcessConfig {
+                program: &self.program,
+                args: self.args.as_slice(),
+                env: self.env.as_ref().map(|env| env.as_slice()),
+                cwd: self.cwd.as_ref(),
+                stdin: self.stdin,
+                stdout: self.stdout,
+                stderr: self.stderr,
+                extra_io: self.extra_io.as_slice(),
+                uid: self.uid,
+                gid: self.gid,
+                detach: self.detach,
+            };
+            io.spawn(cfg).map(|(p, io)| {
+                let mut io = io.move_iter().map(|p| {
+                    p.map(|p| io::PipeStream::new(p))
+                });
+                Process {
+                    handle: p,
+                    stdin: io.next().unwrap(),
+                    stdout: io.next().unwrap(),
+                    stderr: io.next().unwrap(),
+                    extra_io: io.collect(),
+                }
+            })
+        })
+    }
+
+    /// Executes the command as a child process, waiting for it to finish and
+    /// collecting all of its output.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::io::Command;
+    /// use std::str;
+    ///
+    /// let output = match Command::new("cat").arg("foot.txt").output() {
+    ///     Ok(output) => output,
+    ///     Err(e) => fail!("failed to execute process: {}", e),
+    /// };
+    ///
+    /// println!("status: {}", output.status);
+    /// println!("stdout: {}", str::from_utf8_lossy(output.output.as_slice()));
+    /// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
+    /// ```
+    pub fn output(&self) -> IoResult<ProcessOutput> {
+        self.spawn().and_then(|p| p.wait_with_output())
+    }
+
+    /// Executes a command as a child process, waiting for it to finish and
+    /// collecting its exit status.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use std::io::Command;
+    ///
+    /// let status = match Command::new("ls").status() {
+    ///     Ok(status) => status,
+    ///     Err(e) => fail!("failed to execute process: {}", e),
+    /// };
+    ///
+    /// println!("process exited with: {}", status);
+    /// ```
+    pub fn status(&self) -> IoResult<ProcessExit> {
+        self.spawn().and_then(|mut p| p.wait())
+    }
+}
+
+impl fmt::Show for Command {
+    /// Format the program and arguments of a Command for display. Any
+    /// non-utf8 data is lossily converted using the utf8 replacement
+    /// character.
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        try!(write!(f, "{}", str::from_utf8_lossy(self.program.as_bytes_no_nul())));
+        for arg in self.args.iter() {
+            try!(write!(f, " '{}'", str::from_utf8_lossy(arg.as_bytes_no_nul())));
+        }
+        Ok(())
+    }
 }
 
 /// The output of a finished process.
@@ -186,8 +361,8 @@ impl fmt::Show for ProcessExit {
     /// Format a ProcessExit enum, to nicely present the information.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            ExitStatus(code) =>  write!(f.buf, "exit code: {}", code),
-            ExitSignal(code) =>  write!(f.buf, "signal: {}", code),
+            ExitStatus(code) =>  write!(f, "exit code: {}", code),
+            ExitSignal(code) =>  write!(f, "signal: {}", code),
         }
     }
 }
@@ -206,127 +381,7 @@ pub fn matches_exit_status(&self, wanted: int) -> bool {
     }
 }
 
-impl<'a> ProcessConfig<'a> {
-    /// Creates a new configuration with blanks as all of the defaults. This is
-    /// useful when using functional struct updates:
-    ///
-    /// ```rust
-    /// use std::io::process::{ProcessConfig, Process};
-    ///
-    /// let config = ProcessConfig {
-    ///     program: "/bin/sh",
-    ///     args: &["-c".to_owned(), "echo hello".to_owned()],
-    ///     .. ProcessConfig::new()
-    /// };
-    ///
-    /// let p = Process::configure(config);
-    /// ```
-    ///
-    pub fn new<'a>() -> ProcessConfig<'a> {
-        ProcessConfig {
-            program: "",
-            args: &[],
-            env: None,
-            cwd: None,
-            stdin: CreatePipe(true, false),
-            stdout: CreatePipe(false, true),
-            stderr: CreatePipe(false, true),
-            extra_io: &[],
-            uid: None,
-            gid: None,
-            detach: false,
-        }
-    }
-}
-
 impl Process {
-    /// Creates a new process for the specified program/arguments, using
-    /// otherwise default configuration.
-    ///
-    /// By default, new processes have their stdin/stdout/stderr handles created
-    /// as pipes the can be manipulated through the respective fields of the
-    /// returned `Process`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use std::io::Process;
-    ///
-    /// let mut process = match Process::new("sh", &["c".to_owned(), "echo hello".to_owned()]) {
-    ///     Ok(p) => p,
-    ///     Err(e) => fail!("failed to execute process: {}", e),
-    /// };
-    ///
-    /// let output = process.stdout.get_mut_ref().read_to_end();
-    /// ```
-    pub fn new(prog: &str, args: &[~str]) -> IoResult<Process> {
-        Process::configure(ProcessConfig {
-            program: prog,
-            args: args,
-            .. ProcessConfig::new()
-        })
-    }
-
-    /// Executes the specified program with arguments, waiting for it to finish
-    /// and collecting all of its output.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use std::io::Process;
-    /// use std::str;
-    ///
-    /// let output = match Process::output("cat", ["foo.txt".to_owned()]) {
-    ///     Ok(output) => output,
-    ///     Err(e) => fail!("failed to execute process: {}", e),
-    /// };
-    ///
-    /// println!("status: {}", output.status);
-    /// println!("stdout: {}", str::from_utf8_lossy(output.output.as_slice()));
-    /// println!("stderr: {}", str::from_utf8_lossy(output.error.as_slice()));
-    /// ```
-    pub fn output(prog: &str, args: &[~str]) -> IoResult<ProcessOutput> {
-        Process::new(prog, args).and_then(|p| p.wait_with_output())
-    }
-
-    /// Executes a child process and collects its exit status. This will block
-    /// waiting for the child to exit.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use std::io::Process;
-    ///
-    /// let status = match Process::status("ls", []) {
-    ///     Ok(status) => status,
-    ///     Err(e) => fail!("failed to execute process: {}", e),
-    /// };
-    ///
-    /// println!("process exited with: {}", status);
-    /// ```
-    pub fn status(prog: &str, args: &[~str]) -> IoResult<ProcessExit> {
-        Process::new(prog, args).and_then(|mut p| p.wait())
-    }
-
-    /// Creates a new process with the specified configuration.
-    pub fn configure(config: ProcessConfig) -> IoResult<Process> {
-        let mut config = Some(config);
-        LocalIo::maybe_raise(|io| {
-            io.spawn(config.take_unwrap()).map(|(p, io)| {
-                let mut io = io.move_iter().map(|p| {
-                    p.map(|p| io::PipeStream::new(p))
-                });
-                Process {
-                    handle: p,
-                    stdin: io.next().unwrap(),
-                    stdout: io.next().unwrap(),
-                    stderr: io.next().unwrap(),
-                    extra_io: io.collect(),
-                }
-            })
-        })
-    }
-
     /// Sends `signal` to another process in the system identified by `id`.
     ///
     /// Note that windows doesn't quite have the same model as unix, so some
@@ -403,11 +458,11 @@ pub fn wait(&mut self) -> IoResult<ProcessExit> {
     ///
     /// ```no_run
     /// # #![allow(experimental)]
-    /// use std::io::process::{Process, ProcessExit};
+    /// use std::io::process::{Command, ProcessExit};
     /// use std::io::IoResult;
     ///
     /// fn run_gracefully(prog: &str) -> IoResult<ProcessExit> {
-    ///     let mut p = try!(Process::new("long-running-process", []));
+    ///     let mut p = try!(Command::new("long-running-process").spawn());
     ///
     ///     // give the process 10 seconds to finish completely
     ///     p.set_timeout(Some(10_000));
@@ -487,18 +542,14 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
-    use io::process::{ProcessConfig, Process};
+    use io::process::{Command, Process};
     use prelude::*;
 
     // FIXME(#10380) these tests should not all be ignored on android.
 
     #[cfg(not(target_os="android"))]
     iotest!(fn smoke() {
-        let args = ProcessConfig {
-            program: "true",
-            .. ProcessConfig::new()
-        };
-        let p = Process::configure(args);
+        let p = Command::new("true").spawn();
         assert!(p.is_ok());
         let mut p = p.unwrap();
         assert!(p.wait().unwrap().success());
@@ -506,11 +557,7 @@ mod tests {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn smoke_failure() {
-        let args = ProcessConfig {
-            program: "if-this-is-a-binary-then-the-world-has-ended",
-            .. ProcessConfig::new()
-        };
-        match Process::configure(args) {
+        match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
             Ok(..) => fail!(),
             Err(..) => {}
         }
@@ -518,11 +565,7 @@ mod tests {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn exit_reported_right() {
-        let args = ProcessConfig {
-            program: "false",
-            .. ProcessConfig::new()
-        };
-        let p = Process::configure(args);
+        let p = Command::new("false").spawn();
         assert!(p.is_ok());
         let mut p = p.unwrap();
         assert!(p.wait().unwrap().matches_exit_status(1));
@@ -531,12 +574,7 @@ mod tests {
 
     #[cfg(unix, not(target_os="android"))]
     iotest!(fn signal_reported_right() {
-        let args = ProcessConfig {
-            program: "/bin/sh",
-            args: &["-c".to_owned(), "kill -1 $$".to_owned()],
-            .. ProcessConfig::new()
-        };
-        let p = Process::configure(args);
+        let p = Command::new("/bin/sh").arg("-c").arg("kill -1 $$").spawn();
         assert!(p.is_ok());
         let mut p = p.unwrap();
         match p.wait().unwrap() {
@@ -549,8 +587,8 @@ pub fn read_all(input: &mut Reader) -> ~str {
         input.read_to_str().unwrap()
     }
 
-    pub fn run_output(args: ProcessConfig) -> ~str {
-        let p = Process::configure(args);
+    pub fn run_output(cmd: Command) -> ~str {
+        let p = cmd.spawn();
         assert!(p.is_ok());
         let mut p = p.unwrap();
         assert!(p.stdout.is_some());
@@ -561,38 +599,27 @@ pub fn run_output(args: ProcessConfig) -> ~str {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn stdout_works() {
-        let args = ProcessConfig {
-            program: "echo",
-            args: &["foobar".to_owned()],
-            stdout: CreatePipe(false, true),
-            .. ProcessConfig::new()
-        };
-        assert_eq!(run_output(args), "foobar\n".to_owned());
+        let mut cmd = Command::new("echo");
+        cmd.arg("foobar").stdout(CreatePipe(false, true));
+        assert_eq!(run_output(cmd), "foobar\n".to_owned());
     })
 
     #[cfg(unix, not(target_os="android"))]
     iotest!(fn set_cwd_works() {
-        let cwd = Path::new("/");
-        let args = ProcessConfig {
-            program: "/bin/sh",
-            args: &["-c".to_owned(), "pwd".to_owned()],
-            cwd: Some(&cwd),
-            stdout: CreatePipe(false, true),
-            .. ProcessConfig::new()
-        };
-        assert_eq!(run_output(args), "/\n".to_owned());
+        let mut cmd = Command::new("/bin/sh");
+        cmd.arg("-c").arg("pwd")
+           .cwd(&Path::new("/"))
+           .stdout(CreatePipe(false, true));
+        assert_eq!(run_output(cmd), "/\n".to_owned());
     })
 
     #[cfg(unix, not(target_os="android"))]
     iotest!(fn stdin_works() {
-        let args = ProcessConfig {
-            program: "/bin/sh",
-            args: &["-c".to_owned(), "read line; echo $line".to_owned()],
-            stdin: CreatePipe(true, false),
-            stdout: CreatePipe(false, true),
-            .. ProcessConfig::new()
-        };
-        let mut p = Process::configure(args).unwrap();
+        let mut p = Command::new("/bin/sh")
+                            .arg("-c").arg("read line; echo $line")
+                            .stdin(CreatePipe(true, false))
+                            .stdout(CreatePipe(false, true))
+                            .spawn().unwrap();
         p.stdin.get_mut_ref().write("foobar".as_bytes()).unwrap();
         drop(p.stdin.take());
         let out = read_all(p.stdout.get_mut_ref() as &mut Reader);
@@ -602,36 +629,23 @@ pub fn run_output(args: ProcessConfig) -> ~str {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn detach_works() {
-        let args = ProcessConfig {
-            program: "true",
-            detach: true,
-            .. ProcessConfig::new()
-        };
-        let mut p = Process::configure(args).unwrap();
+        let mut p = Command::new("true").detached().spawn().unwrap();
         assert!(p.wait().unwrap().success());
     })
 
     #[cfg(windows)]
     iotest!(fn uid_fails_on_windows() {
-        let args = ProcessConfig {
-            program: "test",
-            uid: Some(10),
-            .. ProcessConfig::new()
-        };
-        assert!(Process::configure(args).is_err());
+        assert!(Command::new("test").uid(10).spawn().is_err());
     })
 
     #[cfg(unix, not(target_os="android"))]
     iotest!(fn uid_works() {
         use libc;
-        let args = ProcessConfig {
-            program: "/bin/sh",
-            args: &["-c".to_owned(), "true".to_owned()],
-            uid: Some(unsafe { libc::getuid() as uint }),
-            gid: Some(unsafe { libc::getgid() as uint }),
-            .. ProcessConfig::new()
-        };
-        let mut p = Process::configure(args).unwrap();
+        let mut p = Command::new("/bin/sh")
+                            .arg("-c").arg("true")
+                            .uid(unsafe { libc::getuid() as uint })
+                            .gid(unsafe { libc::getgid() as uint })
+                            .spawn().unwrap();
         assert!(p.wait().unwrap().success());
     })
 
@@ -642,26 +656,20 @@ pub fn run_output(args: ProcessConfig) -> ~str {
         // if we're already root, this isn't a valid test. Most of the bots run
         // as non-root though (android is an exception).
         if unsafe { libc::getuid() == 0 } { return }
-        let args = ProcessConfig {
-            program: "/bin/ls",
-            uid: Some(0),
-            gid: Some(0),
-            .. ProcessConfig::new()
-        };
-        assert!(Process::configure(args).is_err());
+        assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
     })
 
     #[cfg(not(target_os="android"))]
     iotest!(fn test_process_status() {
-        let mut status = Process::status("false", []).unwrap();
+        let mut status = Command::new("false").status().unwrap();
         assert!(status.matches_exit_status(1));
 
-        status = Process::status("true", []).unwrap();
+        status = Command::new("true").status().unwrap();
         assert!(status.success());
     })
 
     iotest!(fn test_process_output_fail_to_start() {
-        match Process::output("/no-binary-by-this-name-should-exist", []) {
+        match Command::new("/no-binary-by-this-name-should-exist").output() {
             Err(e) => assert_eq!(e.kind, FileNotFound),
             Ok(..) => fail!()
         }
@@ -669,9 +677,8 @@ pub fn run_output(args: ProcessConfig) -> ~str {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn test_process_output_output() {
-
         let ProcessOutput {status, output, error}
-             = Process::output("echo", ["hello".to_owned()]).unwrap();
+             = Command::new("echo").arg("hello").output().unwrap();
         let output_str = str::from_utf8(output.as_slice()).unwrap();
 
         assert!(status.success());
@@ -685,7 +692,7 @@ pub fn run_output(args: ProcessConfig) -> ~str {
     #[cfg(not(target_os="android"))]
     iotest!(fn test_process_output_error() {
         let ProcessOutput {status, output, error}
-             = Process::output("mkdir", [".".to_owned()]).unwrap();
+             = Command::new("mkdir").arg(".").output().unwrap();
 
         assert!(status.matches_exit_status(1));
         assert_eq!(output, Vec::new());
@@ -694,21 +701,20 @@ pub fn run_output(args: ProcessConfig) -> ~str {
 
     #[cfg(not(target_os="android"))]
     iotest!(fn test_finish_once() {
-        let mut prog = Process::new("false", []).unwrap();
+        let mut prog = Command::new("false").spawn().unwrap();
         assert!(prog.wait().unwrap().matches_exit_status(1));
     })
 
     #[cfg(not(target_os="android"))]
     iotest!(fn test_finish_twice() {
-        let mut prog = Process::new("false", []).unwrap();
+        let mut prog = Command::new("false").spawn().unwrap();
         assert!(prog.wait().unwrap().matches_exit_status(1));
         assert!(prog.wait().unwrap().matches_exit_status(1));
     })
 
     #[cfg(not(target_os="android"))]
     iotest!(fn test_wait_with_output_once() {
-
-        let prog = Process::new("echo", ["hello".to_owned()]).unwrap();
+        let prog = Command::new("echo").arg("hello").spawn().unwrap();
         let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap();
         let output_str = str::from_utf8(output.as_slice()).unwrap();
 
@@ -721,36 +727,26 @@ pub fn run_output(args: ProcessConfig) -> ~str {
     })
 
     #[cfg(unix,not(target_os="android"))]
-    pub fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "pwd",
-            cwd: dir,
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn pwd_cmd() -> Command {
+        Command::new("pwd")
     }
     #[cfg(target_os="android")]
-    pub fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "/system/bin/sh",
-            args: &["-c".to_owned(),"pwd".to_owned()],
-            cwd: dir.map(|a| &*a),
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn pwd_cmd() -> Command {
+        let mut cmd = Command::new("/system/bin/sh");
+        cmd.arg("-c").arg("pwd");
+        cmd
     }
 
     #[cfg(windows)]
-    pub fn run_pwd(dir: Option<&Path>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "cmd",
-            args: &["/c".to_owned(), "cd".to_owned()],
-            cwd: dir.map(|a| &*a),
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn pwd_cmd() -> Command {
+        let mut cmd = Command::new("cmd");
+        cmd.arg("/c").arg("cd");
+        cmd
     }
 
     iotest!(fn test_keep_current_working_dir() {
         use os;
-        let prog = run_pwd(None);
+        let prog = pwd_cmd().spawn().unwrap();
 
         let output = str::from_utf8(prog.wait_with_output().unwrap()
                                         .output.as_slice()).unwrap().to_owned();
@@ -769,7 +765,7 @@ pub fn run_pwd(dir: Option<&Path>) -> Process {
         // test changing to the parent of os::getcwd() because we know
         // the path exists (and os::getcwd() is not expected to be root)
         let parent_dir = os::getcwd().dir_path();
-        let prog = run_pwd(Some(&parent_dir));
+        let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
 
         let output = str::from_utf8(prog.wait_with_output().unwrap()
                                         .output.as_slice()).unwrap().to_owned();
@@ -783,31 +779,21 @@ pub fn run_pwd(dir: Option<&Path>) -> Process {
     })
 
     #[cfg(unix,not(target_os="android"))]
-    pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "env",
-            env: env.as_ref().map(|e| e.as_slice()),
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn env_cmd() -> Command {
+        Command::new("env")
     }
     #[cfg(target_os="android")]
-    pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "/system/bin/sh",
-            args: &["-c".to_owned(),"set".to_owned()],
-            env: env.as_ref().map(|e| e.as_slice()),
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn env_cmd() -> Command {
+        let mut cmd = Command::new("/system/bin/sh");
+        cmd.arg("-c").arg("set");
+        cmd
     }
 
     #[cfg(windows)]
-    pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
-        Process::configure(ProcessConfig {
-            program: "cmd",
-            args: &["/c".to_owned(), "set".to_owned()],
-            env: env.as_ref().map(|e| e.as_slice()),
-            .. ProcessConfig::new()
-        }).unwrap()
+    pub fn env_cmd() -> Command {
+        let mut cmd = Command::new("cmd");
+        cmd.arg("/c").arg("set");
+        cmd
     }
 
     #[cfg(not(target_os="android"))]
@@ -815,7 +801,7 @@ pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
         use os;
         if running_on_valgrind() { return; }
 
-        let prog = run_env(None);
+        let prog = env_cmd().spawn().unwrap();
         let output = str::from_utf8(prog.wait_with_output().unwrap()
                                         .output.as_slice()).unwrap().to_owned();
 
@@ -830,7 +816,7 @@ pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
         use os;
         if running_on_valgrind() { return; }
 
-        let prog = run_env(None);
+        let mut prog = env_cmd().spawn().unwrap();
         let output = str::from_utf8(prog.wait_with_output()
                                         .unwrap().output.as_slice())
                                    .unwrap().to_owned();
@@ -846,9 +832,8 @@ pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
     })
 
     iotest!(fn test_add_to_env() {
-        let new_env = box [("RUN_TEST_NEW_ENV".to_owned(), "123".to_owned())];
-
-        let prog = run_env(Some(new_env));
+        let new_env = box [("RUN_TEST_NEW_ENV", "123")];
+        let prog = env_cmd().env(new_env).spawn().unwrap();
         let result = prog.wait_with_output().unwrap();
         let output = str::from_utf8_lossy(result.output.as_slice()).into_owned();
 
@@ -858,14 +843,14 @@ pub fn run_env(env: Option<~[(~str, ~str)]>) -> Process {
 
     #[cfg(unix)]
     pub fn sleeper() -> Process {
-        Process::new("sleep", ["1000".to_owned()]).unwrap()
+        Command::new("sleep").arg("1000").spawn().unwrap()
     }
     #[cfg(windows)]
     pub fn sleeper() -> Process {
         // There's a `timeout` command on windows, but it doesn't like having
         // its output piped, so instead just ping ourselves a few times with
         // gaps inbetweeen so we're sure this process is alive for awhile
-        Process::new("ping", ["127.0.0.1".to_owned(), "-n".to_owned(), "1000".to_owned()]).unwrap()
+        Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
     }
 
     iotest!(fn test_kill() {
index 69ba0fb20ee1c28c2b8b5bb05e1b93939e348e4c..e6d416164d008831ad2af668ba3154916f7298d5 100644 (file)
@@ -36,7 +36,7 @@
 use option::{Option, Some, None};
 use owned::Box;
 use prelude::drop;
-use result::{Ok, Err, ResultUnwrap};
+use result::{Ok, Err};
 use rt;
 use rt::local::Local;
 use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
@@ -276,13 +276,13 @@ pub fn println(s: &str) {
 /// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
 /// with the `format_args!` macro.
 pub fn print_args(fmt: &fmt::Arguments) {
-    with_task_stdout(|io| fmt::write(io, fmt))
+    with_task_stdout(|io| write!(io, "{}", fmt))
 }
 
 /// Similar to `println`, but takes a `fmt::Arguments` structure to be
 /// compatible with the `format_args!` macro.
 pub fn println_args(fmt: &fmt::Arguments) {
-    with_task_stdout(|io| fmt::writeln(io, fmt))
+    with_task_stdout(|io| writeln!(io, "{}", fmt))
 }
 
 /// Representation of a reader of a standard input stream
index 8c28caa988a5c05d0671b446e3b3e3a1fcba8bcc..b4fb95c8af7702769858038a2a4180a99d561df4 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Temporary files and directories
 
-use io::fs;
+use io::{fs, IoResult};
 use io;
 use iter::{Iterator, range};
 use libc;
 use option::{Option, None, Some};
 use os;
 use path::{Path, GenericPath};
-use result::{Ok, Err, ResultUnwrap};
+use result::{Ok, Err};
 use sync::atomics;
 
 /// A wrapper for a path to temporary directory implementing automatic
 /// scope-based deletion.
 pub struct TempDir {
-    path: Option<Path>
+    path: Option<Path>,
+    disarmed: bool
 }
 
 impl TempDir {
@@ -48,7 +49,7 @@ pub fn new_in(tmpdir: &Path, suffix: &str) -> Option<TempDir> {
             let p = tmpdir.join(filename);
             match fs::mkdir(&p, io::UserRWX) {
                 Err(..) => {}
-                Ok(()) => return Some(TempDir { path: Some(p) })
+                Ok(()) => return Some(TempDir { path: Some(p), disarmed: false })
             }
         }
         None
@@ -75,15 +76,32 @@ pub fn unwrap(self) -> Path {
     pub fn path<'a>(&'a self) -> &'a Path {
         self.path.get_ref()
     }
+
+    /// Close and remove the temporary directory
+    ///
+    /// Although `TempDir` removes the directory on drop, in the destructor
+    /// any errors are ignored. To detect errors cleaning up the temporary
+    /// directory, call `close` instead.
+    pub fn close(mut self) -> IoResult<()> {
+        self.cleanup_dir()
+    }
+
+    fn cleanup_dir(&mut self) -> IoResult<()> {
+        assert!(!self.disarmed);
+        self.disarmed = true;
+        match self.path {
+            Some(ref p) => {
+                fs::rmdir_recursive(p)
+            }
+            None => Ok(())
+        }
+    }
 }
 
 impl Drop for TempDir {
     fn drop(&mut self) {
-        for path in self.path.iter() {
-            if path.exists() {
-                // FIXME: is failing the right thing to do?
-                fs::rmdir_recursive(path).unwrap();
-            }
+        if !self.disarmed {
+            let _ = self.cleanup_dir();
         }
     }
 }
index a37f9a516fdb92afda011f05a15d4869ae14ffc4..119cd9aa2ca8848159a7dade3b5c94187a9ed6fd 100644 (file)
 #[cfg(test)] pub use ops = realstd::ops;
 #[cfg(test)] pub use cmp = realstd::cmp;
 #[cfg(test)] pub use ty = realstd::ty;
-#[cfg(not(stage0), test)] pub use owned = realstd::owned;
+#[cfg(test)] pub use owned = realstd::owned;
 
 #[cfg(not(test))] pub use cmp = core::cmp;
 #[cfg(not(test))] pub use kinds = core::kinds;
 #[cfg(not(test))] pub use ops = core::ops;
 #[cfg(not(test))] pub use ty = core::ty;
 
-#[cfg(stage0, test)] pub use owned = realstd::owned;
-#[cfg(stage0, not(test))] pub use owned = core::owned;
-
 pub use core::any;
 pub use core::bool;
 pub use core::cell;
 pub use core::ptr;
 pub use core::raw;
 pub use core::tuple;
+pub use core::result;
 
 // Run tests with libgreen instead of libnative.
 //
@@ -209,7 +207,7 @@ fn start(argc: int, argv: **u8) -> int {
 
 pub mod rc;
 pub mod gc;
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
 pub mod owned;
 
 /* Common traits */
@@ -221,7 +219,6 @@ fn start(argc: int, argv: **u8) -> int {
 
 /* Common data structures */
 
-pub mod result;
 pub mod option;
 
 /* Tasks and communication */
index 3a0e78b39d13dc3682f2663858c67e4477d598f2..b260f685a34777fbe488d49044d18bff81f64a51 100644 (file)
@@ -251,10 +251,17 @@ macro_rules! format_strbuf(
 /// write!(&mut w, "formatted {}", "arguments");
 /// ```
 #[macro_export]
+#[cfg(not(stage0))]
 macro_rules! write(
     ($dst:expr, $($arg:tt)*) => ({
-        let dst: &mut ::std::io::Writer = $dst;
-        format_args!(|args| { ::std::fmt::write(dst, args) }, $($arg)*)
+        format_args_method!($dst, write_fmt, $($arg)*)
+    })
+)
+#[cfg(stage0)]
+#[macro_export]
+macro_rules! write(
+    ($dst:expr, $($arg:tt)*) => ({
+        format_args!(|args| { $dst.write_fmt(args) }, $($arg)*)
     })
 )
 
@@ -262,10 +269,9 @@ macro_rules! write(
 /// the message is written.
 #[macro_export]
 macro_rules! writeln(
-    ($dst:expr, $($arg:tt)*) => ({
-        let dst: &mut ::std::io::Writer = $dst;
-        format_args!(|args| { ::std::fmt::writeln(dst, args) }, $($arg)*)
-    })
+    ($dst:expr, $fmt:expr $($arg:tt)*) => (
+        write!($dst, concat!($fmt, "\n") $($arg)*)
+    )
 )
 
 /// Equivalent to the `println!` macro except that a newline is not printed at
index 29c206b32fc36a89617360bfbadda42993166071..e9ea0df2a7b9e4f02b3706a9f6b849827bc75f51 100644 (file)
@@ -18,9 +18,7 @@
 use from_str::FromStr;
 use intrinsics;
 use libc::c_int;
-use mem;
 use num::strconv;
-use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
 use num;
 
 pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE};
@@ -69,82 +67,7 @@ mod cmath {
     }
 }
 
-impl Float for f32 {
-    #[inline]
-    fn nan() -> f32 { NAN }
-
-    #[inline]
-    fn infinity() -> f32 { INFINITY }
-
-    #[inline]
-    fn neg_infinity() -> f32 { NEG_INFINITY }
-
-    #[inline]
-    fn neg_zero() -> f32 { -0.0 }
-
-    /// Returns `true` if the number is NaN
-    #[inline]
-    fn is_nan(self) -> bool { self != self }
-
-    /// Returns `true` if the number is infinite
-    #[inline]
-    fn is_infinite(self) -> bool {
-        self == Float::infinity() || self == Float::neg_infinity()
-    }
-
-    /// Returns `true` if the number is neither infinite or NaN
-    #[inline]
-    fn is_finite(self) -> bool {
-        !(self.is_nan() || self.is_infinite())
-    }
-
-    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
-    #[inline]
-    fn is_normal(self) -> bool {
-        self.classify() == FPNormal
-    }
-
-    /// Returns the floating point category of the number. If only one property
-    /// is going to be tested, it is generally faster to use the specific
-    /// predicate instead.
-    fn classify(self) -> FPCategory {
-        static EXP_MASK: u32 = 0x7f800000;
-        static MAN_MASK: u32 = 0x007fffff;
-
-        let bits: u32 = unsafe { mem::transmute(self) };
-        match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0)        => FPZero,
-            (_, 0)        => FPSubnormal,
-            (0, EXP_MASK) => FPInfinite,
-            (_, EXP_MASK) => FPNaN,
-            _             => FPNormal,
-        }
-    }
-
-    #[inline]
-    fn mantissa_digits(_: Option<f32>) -> uint { MANTISSA_DIGITS }
-
-    #[inline]
-    fn digits(_: Option<f32>) -> uint { DIGITS }
-
-    #[inline]
-    fn epsilon() -> f32 { EPSILON }
-
-    #[inline]
-    fn min_exp(_: Option<f32>) -> int { MIN_EXP }
-
-    #[inline]
-    fn max_exp(_: Option<f32>) -> int { MAX_EXP }
-
-    #[inline]
-    fn min_10_exp(_: Option<f32>) -> int { MIN_10_EXP }
-
-    #[inline]
-    fn max_10_exp(_: Option<f32>) -> int { MAX_10_EXP }
-
-    #[inline]
-    fn min_pos_value(_: Option<f32>) -> f32 { MIN_POS_VALUE }
-
+impl FloatMath for f32 {
     /// Constructs a floating point number by multiplying `x` by 2 raised to the
     /// power of `exp`
     #[inline]
@@ -166,21 +89,6 @@ fn frexp(self) -> (f32, int) {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u32 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0x7fffff) << 1
-        } else {
-            (bits & 0x7fffff) | 0x800000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 127 + 23;
-        (mantissa as u64, exponent, sign)
-    }
-
     /// Returns the next representable floating-point value in the direction of
     /// `other`.
     #[inline]
@@ -188,39 +96,6 @@ fn next_after(self, other: f32) -> f32 {
         unsafe { cmath::nextafterf(self, other) }
     }
 
-    /// Round half-way cases toward `NEG_INFINITY`
-    #[inline]
-    fn floor(self) -> f32 {
-        unsafe { intrinsics::floorf32(self) }
-    }
-
-    /// Round half-way cases toward `INFINITY`
-    #[inline]
-    fn ceil(self) -> f32 {
-        unsafe { intrinsics::ceilf32(self) }
-    }
-
-    /// Round half-way cases away from `0.0`
-    #[inline]
-    fn round(self) -> f32 {
-        unsafe { intrinsics::roundf32(self) }
-    }
-
-    /// The integer part of the number (rounds towards `0.0`)
-    #[inline]
-    fn trunc(self) -> f32 {
-        unsafe { intrinsics::truncf32(self) }
-    }
-
-    /// The fractional part of the number, satisfying:
-    ///
-    /// ```rust
-    /// let x = 1.65f32;
-    /// assert!(x == x.trunc() + x.fract())
-    /// ```
-    #[inline]
-    fn fract(self) -> f32 { self - self.trunc() }
-
     #[inline]
     fn max(self, other: f32) -> f32 {
         unsafe { cmath::fmaxf(self, other) }
@@ -231,43 +106,6 @@ fn min(self, other: f32) -> f32 {
         unsafe { cmath::fminf(self, other) }
     }
 
-    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
-    #[inline]
-    fn mul_add(self, a: f32, b: f32) -> f32 {
-        unsafe { intrinsics::fmaf32(self, a, b) }
-    }
-
-    /// The reciprocal (multiplicative inverse) of the number
-    #[inline]
-    fn recip(self) -> f32 { 1.0 / self }
-
-    fn powi(self, n: i32) -> f32 {
-        unsafe { intrinsics::powif32(self, n) }
-    }
-
-    #[inline]
-    fn powf(self, n: f32) -> f32 {
-        unsafe { intrinsics::powf32(self, n) }
-    }
-
-    /// sqrt(2.0)
-    #[inline]
-    fn sqrt2() -> f32 { consts::SQRT2 }
-
-    /// 1.0 / sqrt(2.0)
-    #[inline]
-    fn frac_1_sqrt2() -> f32 { consts::FRAC_1_SQRT2 }
-
-    #[inline]
-    fn sqrt(self) -> f32 {
-        unsafe { intrinsics::sqrtf32(self) }
-    }
-
-    #[inline]
-    fn rsqrt(self) -> f32 { self.sqrt().recip() }
-
     #[inline]
     fn cbrt(self) -> f32 {
         unsafe { cmath::cbrtf(self) }
@@ -278,46 +116,6 @@ fn hypot(self, other: f32) -> f32 {
         unsafe { cmath::hypotf(self, other) }
     }
 
-    /// Archimedes' constant
-    #[inline]
-    fn pi() -> f32 { consts::PI }
-
-    /// 2.0 * pi
-    #[inline]
-    fn two_pi() -> f32 { consts::PI_2 }
-
-    /// pi / 2.0
-    #[inline]
-    fn frac_pi_2() -> f32 { consts::FRAC_PI_2 }
-
-    /// pi / 3.0
-    #[inline]
-    fn frac_pi_3() -> f32 { consts::FRAC_PI_3 }
-
-    /// pi / 4.0
-    #[inline]
-    fn frac_pi_4() -> f32 { consts::FRAC_PI_4 }
-
-    /// pi / 6.0
-    #[inline]
-    fn frac_pi_6() -> f32 { consts::FRAC_PI_6 }
-
-    /// pi / 8.0
-    #[inline]
-    fn frac_pi_8() -> f32 { consts::FRAC_PI_8 }
-
-    /// 1 .0/ pi
-    #[inline]
-    fn frac_1_pi() -> f32 { consts::FRAC_1_PI }
-
-    /// 2.0 / pi
-    #[inline]
-    fn frac_2_pi() -> f32 { consts::FRAC_2_PI }
-
-    /// 2.0 / sqrt(pi)
-    #[inline]
-    fn frac_2_sqrtpi() -> f32 { consts::FRAC_2_SQRTPI }
-
     #[inline]
     fn sin(self) -> f32 {
         unsafe { intrinsics::sinf32(self) }
@@ -359,38 +157,6 @@ fn sin_cos(self) -> (f32, f32) {
         (self.sin(), self.cos())
     }
 
-    /// Euler's number
-    #[inline]
-    fn e() -> f32 { consts::E }
-
-    /// log2(e)
-    #[inline]
-    fn log2_e() -> f32 { consts::LOG2_E }
-
-    /// log10(e)
-    #[inline]
-    fn log10_e() -> f32 { consts::LOG10_E }
-
-    /// ln(2.0)
-    #[inline]
-    fn ln_2() -> f32 { consts::LN_2 }
-
-    /// ln(10.0)
-    #[inline]
-    fn ln_10() -> f32 { consts::LN_10 }
-
-    /// Returns the exponential of the number
-    #[inline]
-    fn exp(self) -> f32 {
-        unsafe { intrinsics::expf32(self) }
-    }
-
-    /// Returns 2 raised to the power of the number
-    #[inline]
-    fn exp2(self) -> f32 {
-        unsafe { intrinsics::exp2f32(self) }
-    }
-
     /// Returns the exponential of the number, minus `1`, in a way that is
     /// accurate even if the number is close to zero
     #[inline]
@@ -398,28 +164,6 @@ fn exp_m1(self) -> f32 {
         unsafe { cmath::expm1f(self) }
     }
 
-    /// Returns the natural logarithm of the number
-    #[inline]
-    fn ln(self) -> f32 {
-        unsafe { intrinsics::logf32(self) }
-    }
-
-    /// Returns the logarithm of the number with respect to an arbitrary base
-    #[inline]
-    fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
-
-    /// Returns the base 2 logarithm of the number
-    #[inline]
-    fn log2(self) -> f32 {
-        unsafe { intrinsics::log2f32(self) }
-    }
-
-    /// Returns the base 10 logarithm of the number
-    #[inline]
-    fn log10(self) -> f32 {
-        unsafe { intrinsics::log10f32(self) }
-    }
-
     /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more
     /// accurately than if the operations were performed separately
     #[inline]
@@ -486,17 +230,6 @@ fn acosh(self) -> f32 {
     fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
-
-    /// Converts to degrees, assuming the number is in radians
-    #[inline]
-    fn to_degrees(self) -> f32 { self * (180.0f32 / Float::pi()) }
-
-    /// Converts to radians, assuming the number is in degrees
-    #[inline]
-    fn to_radians(self) -> f32 {
-        let value: f32 = Float::pi();
-        self * (value / 180.0f32)
-    }
 }
 
 //
@@ -1000,18 +733,18 @@ fn test_ldexp() {
         // are supported in floating-point literals
         let f1: f32 = from_str_hex("1p-123").unwrap();
         let f2: f32 = from_str_hex("1p-111").unwrap();
-        assert_eq!(Float::ldexp(1f32, -123), f1);
-        assert_eq!(Float::ldexp(1f32, -111), f2);
+        assert_eq!(FloatMath::ldexp(1f32, -123), f1);
+        assert_eq!(FloatMath::ldexp(1f32, -111), f2);
 
-        assert_eq!(Float::ldexp(0f32, -123), 0f32);
-        assert_eq!(Float::ldexp(-0f32, -123), -0f32);
+        assert_eq!(FloatMath::ldexp(0f32, -123), 0f32);
+        assert_eq!(FloatMath::ldexp(-0f32, -123), -0f32);
 
         let inf: f32 = Float::infinity();
         let neg_inf: f32 = Float::neg_infinity();
         let nan: f32 = Float::nan();
-        assert_eq!(Float::ldexp(inf, -123), inf);
-        assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
-        assert!(Float::ldexp(nan, -123).is_nan());
+        assert_eq!(FloatMath::ldexp(inf, -123), inf);
+        assert_eq!(FloatMath::ldexp(neg_inf, -123), neg_inf);
+        assert!(FloatMath::ldexp(nan, -123).is_nan());
     }
 
     #[test]
@@ -1024,8 +757,8 @@ fn test_frexp() {
         let (x2, exp2) = f2.frexp();
         assert_eq!((x1, exp1), (0.5f32, -122));
         assert_eq!((x2, exp2), (0.5f32, -110));
-        assert_eq!(Float::ldexp(x1, exp1), f1);
-        assert_eq!(Float::ldexp(x2, exp2), f2);
+        assert_eq!(FloatMath::ldexp(x1, exp1), f1);
+        assert_eq!(FloatMath::ldexp(x2, exp2), f2);
 
         assert_eq!(0f32.frexp(), (0f32, 0));
         assert_eq!((-0f32).frexp(), (-0f32, 0));
index c18ea5caba6298c3a1ce5fcefbc691262495137d..869a275b1d4089b57eb983bc99b599b54dd3f17a 100644 (file)
 
 use from_str::FromStr;
 use intrinsics;
-use libc::{c_int};
-use mem;
-use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
-use num::{strconv};
+use libc::c_int;
+use num::strconv;
 use num;
 
 pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE};
@@ -77,82 +75,7 @@ mod cmath {
     }
 }
 
-impl Float for f64 {
-    #[inline]
-    fn nan() -> f64 { NAN }
-
-    #[inline]
-    fn infinity() -> f64 { INFINITY }
-
-    #[inline]
-    fn neg_infinity() -> f64 { NEG_INFINITY }
-
-    #[inline]
-    fn neg_zero() -> f64 { -0.0 }
-
-    /// Returns `true` if the number is NaN
-    #[inline]
-    fn is_nan(self) -> bool { self != self }
-
-    /// Returns `true` if the number is infinite
-    #[inline]
-    fn is_infinite(self) -> bool {
-        self == Float::infinity() || self == Float::neg_infinity()
-    }
-
-    /// Returns `true` if the number is neither infinite or NaN
-    #[inline]
-    fn is_finite(self) -> bool {
-        !(self.is_nan() || self.is_infinite())
-    }
-
-    /// Returns `true` if the number is neither zero, infinite, subnormal or NaN
-    #[inline]
-    fn is_normal(self) -> bool {
-        self.classify() == FPNormal
-    }
-
-    /// Returns the floating point category of the number. If only one property
-    /// is going to be tested, it is generally faster to use the specific
-    /// predicate instead.
-    fn classify(self) -> FPCategory {
-        static EXP_MASK: u64 = 0x7ff0000000000000;
-        static MAN_MASK: u64 = 0x000fffffffffffff;
-
-        let bits: u64 = unsafe { mem::transmute(self) };
-        match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0)        => FPZero,
-            (_, 0)        => FPSubnormal,
-            (0, EXP_MASK) => FPInfinite,
-            (_, EXP_MASK) => FPNaN,
-            _             => FPNormal,
-        }
-    }
-
-    #[inline]
-    fn mantissa_digits(_: Option<f64>) -> uint { MANTISSA_DIGITS }
-
-    #[inline]
-    fn digits(_: Option<f64>) -> uint { DIGITS }
-
-    #[inline]
-    fn epsilon() -> f64 { EPSILON }
-
-    #[inline]
-    fn min_exp(_: Option<f64>) -> int { MIN_EXP }
-
-    #[inline]
-    fn max_exp(_: Option<f64>) -> int { MAX_EXP }
-
-    #[inline]
-    fn min_10_exp(_: Option<f64>) -> int { MIN_10_EXP }
-
-    #[inline]
-    fn max_10_exp(_: Option<f64>) -> int { MAX_10_EXP }
-
-    #[inline]
-    fn min_pos_value(_: Option<f64>) -> f64 { MIN_POS_VALUE }
-
+impl FloatMath for f64 {
     /// Constructs a floating point number by multiplying `x` by 2 raised to the
     /// power of `exp`
     #[inline]
@@ -174,21 +97,6 @@ fn frexp(self) -> (f64, int) {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u64 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0xfffffffffffff) << 1
-        } else {
-            (bits & 0xfffffffffffff) | 0x10000000000000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 1023 + 52;
-        (mantissa, exponent, sign)
-    }
-
     /// Returns the next representable floating-point value in the direction of
     /// `other`.
     #[inline]
@@ -196,39 +104,6 @@ fn next_after(self, other: f64) -> f64 {
         unsafe { cmath::nextafter(self, other) }
     }
 
-    /// Round half-way cases toward `NEG_INFINITY`
-    #[inline]
-    fn floor(self) -> f64 {
-        unsafe { intrinsics::floorf64(self) }
-    }
-
-    /// Round half-way cases toward `INFINITY`
-    #[inline]
-    fn ceil(self) -> f64 {
-        unsafe { intrinsics::ceilf64(self) }
-    }
-
-    /// Round half-way cases away from `0.0`
-    #[inline]
-    fn round(self) -> f64 {
-        unsafe { intrinsics::roundf64(self) }
-    }
-
-    /// The integer part of the number (rounds towards `0.0`)
-    #[inline]
-    fn trunc(self) -> f64 {
-        unsafe { intrinsics::truncf64(self) }
-    }
-
-    /// The fractional part of the number, satisfying:
-    ///
-    /// ```rust
-    /// let x = 1.65f64;
-    /// assert!(x == x.trunc() + x.fract())
-    /// ```
-    #[inline]
-    fn fract(self) -> f64 { self - self.trunc() }
-
     #[inline]
     fn max(self, other: f64) -> f64 {
         unsafe { cmath::fmax(self, other) }
@@ -239,44 +114,6 @@ fn min(self, other: f64) -> f64 {
         unsafe { cmath::fmin(self, other) }
     }
 
-    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
-    #[inline]
-    fn mul_add(self, a: f64, b: f64) -> f64 {
-        unsafe { intrinsics::fmaf64(self, a, b) }
-    }
-
-    /// The reciprocal (multiplicative inverse) of the number
-    #[inline]
-    fn recip(self) -> f64 { 1.0 / self }
-
-    #[inline]
-    fn powf(self, n: f64) -> f64 {
-        unsafe { intrinsics::powf64(self, n) }
-    }
-
-    #[inline]
-    fn powi(self, n: i32) -> f64 {
-        unsafe { intrinsics::powif64(self, n) }
-    }
-
-    /// sqrt(2.0)
-    #[inline]
-    fn sqrt2() -> f64 { consts::SQRT2 }
-
-    /// 1.0 / sqrt(2.0)
-    #[inline]
-    fn frac_1_sqrt2() -> f64 { consts::FRAC_1_SQRT2 }
-
-    #[inline]
-    fn sqrt(self) -> f64 {
-        unsafe { intrinsics::sqrtf64(self) }
-    }
-
-    #[inline]
-    fn rsqrt(self) -> f64 { self.sqrt().recip() }
-
     #[inline]
     fn cbrt(self) -> f64 {
         unsafe { cmath::cbrt(self) }
@@ -287,46 +124,6 @@ fn hypot(self, other: f64) -> f64 {
         unsafe { cmath::hypot(self, other) }
     }
 
-    /// Archimedes' constant
-    #[inline]
-    fn pi() -> f64 { consts::PI }
-
-    /// 2.0 * pi
-    #[inline]
-    fn two_pi() -> f64 { consts::PI_2 }
-
-    /// pi / 2.0
-    #[inline]
-    fn frac_pi_2() -> f64 { consts::FRAC_PI_2 }
-
-    /// pi / 3.0
-    #[inline]
-    fn frac_pi_3() -> f64 { consts::FRAC_PI_3 }
-
-    /// pi / 4.0
-    #[inline]
-    fn frac_pi_4() -> f64 { consts::FRAC_PI_4 }
-
-    /// pi / 6.0
-    #[inline]
-    fn frac_pi_6() -> f64 { consts::FRAC_PI_6 }
-
-    /// pi / 8.0
-    #[inline]
-    fn frac_pi_8() -> f64 { consts::FRAC_PI_8 }
-
-    /// 1.0 / pi
-    #[inline]
-    fn frac_1_pi() -> f64 { consts::FRAC_1_PI }
-
-    /// 2.0 / pi
-    #[inline]
-    fn frac_2_pi() -> f64 { consts::FRAC_2_PI }
-
-    /// 2.0 / sqrt(pi)
-    #[inline]
-    fn frac_2_sqrtpi() -> f64 { consts::FRAC_2_SQRTPI }
-
     #[inline]
     fn sin(self) -> f64 {
         unsafe { intrinsics::sinf64(self) }
@@ -368,38 +165,6 @@ fn sin_cos(self) -> (f64, f64) {
         (self.sin(), self.cos())
     }
 
-    /// Euler's number
-    #[inline]
-    fn e() -> f64 { consts::E }
-
-    /// log2(e)
-    #[inline]
-    fn log2_e() -> f64 { consts::LOG2_E }
-
-    /// log10(e)
-    #[inline]
-    fn log10_e() -> f64 { consts::LOG10_E }
-
-    /// ln(2.0)
-    #[inline]
-    fn ln_2() -> f64 { consts::LN_2 }
-
-    /// ln(10.0)
-    #[inline]
-    fn ln_10() -> f64 { consts::LN_10 }
-
-    /// Returns the exponential of the number
-    #[inline]
-    fn exp(self) -> f64 {
-        unsafe { intrinsics::expf64(self) }
-    }
-
-    /// Returns 2 raised to the power of the number
-    #[inline]
-    fn exp2(self) -> f64 {
-        unsafe { intrinsics::exp2f64(self) }
-    }
-
     /// Returns the exponential of the number, minus `1`, in a way that is
     /// accurate even if the number is close to zero
     #[inline]
@@ -407,28 +172,6 @@ fn exp_m1(self) -> f64 {
         unsafe { cmath::expm1(self) }
     }
 
-    /// Returns the natural logarithm of the number
-    #[inline]
-    fn ln(self) -> f64 {
-        unsafe { intrinsics::logf64(self) }
-    }
-
-    /// Returns the logarithm of the number with respect to an arbitrary base
-    #[inline]
-    fn log(self, base: f64) -> f64 { self.ln() / base.ln() }
-
-    /// Returns the base 2 logarithm of the number
-    #[inline]
-    fn log2(self) -> f64 {
-        unsafe { intrinsics::log2f64(self) }
-    }
-
-    /// Returns the base 10 logarithm of the number
-    #[inline]
-    fn log10(self) -> f64 {
-        unsafe { intrinsics::log10f64(self) }
-    }
-
     /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more
     /// accurately than if the operations were performed separately
     #[inline]
@@ -495,17 +238,6 @@ fn acosh(self) -> f64 {
     fn atanh(self) -> f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
-
-    /// Converts to degrees, assuming the number is in radians
-    #[inline]
-    fn to_degrees(self) -> f64 { self * (180.0f64 / Float::pi()) }
-
-    /// Converts to radians, assuming the number is in degrees
-    #[inline]
-    fn to_radians(self) -> f64 {
-        let value: f64 = Float::pi();
-        self * (value / 180.0)
-    }
 }
 
 //
@@ -1003,18 +735,18 @@ fn test_ldexp() {
         // are supported in floating-point literals
         let f1: f64 = from_str_hex("1p-123").unwrap();
         let f2: f64 = from_str_hex("1p-111").unwrap();
-        assert_eq!(Float::ldexp(1f64, -123), f1);
-        assert_eq!(Float::ldexp(1f64, -111), f2);
+        assert_eq!(FloatMath::ldexp(1f64, -123), f1);
+        assert_eq!(FloatMath::ldexp(1f64, -111), f2);
 
-        assert_eq!(Float::ldexp(0f64, -123), 0f64);
-        assert_eq!(Float::ldexp(-0f64, -123), -0f64);
+        assert_eq!(FloatMath::ldexp(0f64, -123), 0f64);
+        assert_eq!(FloatMath::ldexp(-0f64, -123), -0f64);
 
         let inf: f64 = Float::infinity();
         let neg_inf: f64 = Float::neg_infinity();
         let nan: f64 = Float::nan();
-        assert_eq!(Float::ldexp(inf, -123), inf);
-        assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
-        assert!(Float::ldexp(nan, -123).is_nan());
+        assert_eq!(FloatMath::ldexp(inf, -123), inf);
+        assert_eq!(FloatMath::ldexp(neg_inf, -123), neg_inf);
+        assert!(FloatMath::ldexp(nan, -123).is_nan());
     }
 
     #[test]
@@ -1027,8 +759,8 @@ fn test_frexp() {
         let (x2, exp2) = f2.frexp();
         assert_eq!((x1, exp1), (0.5f64, -122));
         assert_eq!((x2, exp2), (0.5f64, -110));
-        assert_eq!(Float::ldexp(x1, exp1), f1);
-        assert_eq!(Float::ldexp(x2, exp2), f2);
+        assert_eq!(FloatMath::ldexp(x1, exp1), f1);
+        assert_eq!(FloatMath::ldexp(x2, exp2), f2);
 
         assert_eq!(0f64.frexp(), (0f64, 0));
         assert_eq!((-0f64).frexp(), (-0f64, 0));
index d8f1c108b742d48dd8040b50dba5b578319d7450..396037d0dbace10cb6d897ee0e80252462441f22 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::i16::{BITS, BYTES, MIN, MAX};
 
index 9cc8981fc13f422c10d231fd413362088f54723d..5640e82d077dc3a95eb465d39aebb5d15300bb61 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::i32::{BITS, BYTES, MIN, MAX};
 
index 4f7fe32cc7088c9b7d3f171f258840d9e4bad851..40245691e3456fc118f094e261433dc058572905 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::i64::{BITS, BYTES, MIN, MAX};
 
index bea315d86837392e42a3236b646b7d747abfd36e..7ddddd893e211989cc76ccdb76cba11f28f13402 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::i8::{BITS, BYTES, MIN, MAX};
 
index d6a7fd1660b42800eb61a8731d6eb86413ba815a..dc4d80601b7db6a0116eab77f409f584347e4946 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::int::{BITS, BYTES, MIN, MAX};
 
index fcdb63f5ad5eb06564fadbc26af502becd07bc3d..ddff42f68dba9fe870fb49fbfb9c89586d692eab 100644 (file)
@@ -62,31 +62,23 @@ fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
 /// ```
 #[inline]
 pub fn to_str_bytes<U>(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U {
+    use io::{Writer, Seek};
     // The radix can be as low as 2, so we need at least 64 characters for a
     // base 2 number, and then we need another for a possible '-' character.
     let mut buf = [0u8, ..65];
-    let mut cur = 0;
-    strconv::int_to_str_bytes_common(n, radix, strconv::SignNeg, |i| {
-        buf[cur] = i;
-        cur += 1;
-    });
-    f(buf.slice(0, cur))
+    let amt = {
+        let mut wr = ::io::BufWriter::new(buf);
+        (write!(&mut wr, "{}", ::fmt::radix(n, radix as u8))).unwrap();
+        wr.tell().unwrap() as uint
+    };
+    f(buf.slice(0, amt))
 }
 
 impl ToStrRadix for $T {
     /// Convert to a string in a given base.
     #[inline]
     fn to_str_radix(&self, radix: uint) -> ~str {
-        use slice::Vector;
-        use str::StrAllocating;
-
-        let mut buf = ::vec::Vec::new();
-        strconv::int_to_str_bytes_common(*self, radix, strconv::SignNeg, |i| {
-            buf.push(i);
-        });
-        // We know we generated valid utf-8, so we don't need to go through that
-        // check.
-        unsafe { str::raw::from_utf8(buf.as_slice()).to_owned() }
+        format!("{}", ::fmt::radix(*self, radix as u8))
     }
 }
 
index 1efd7cad300bfca9b0144c0ba89ee4bfa11a58fe..3178fcbd66fdb8958e423a352f41942b134f2e33 100644 (file)
 pub use core::num::{from_int, from_i8, from_i16, from_i32, from_i64};
 pub use core::num::{from_uint, from_u8, from_u16, from_u32, from_u64};
 pub use core::num::{from_f32, from_f64};
+pub use core::num::{FPCategory, FPNaN, FPInfinite, FPZero, FPSubnormal};
+pub use core::num::{FPNormal, Float};
 
 pub mod strconv;
 
-/// Used for representing the classification of floating point numbers
-#[deriving(Eq, Show)]
-pub enum FPCategory {
-    /// "Not a Number", often obtained by dividing by zero
-    FPNaN,
-    /// Positive or negative infinity
-    FPInfinite ,
-    /// Positive or negative zero
-    FPZero,
-    /// De-normalized floating point representation (less precise than `FPNormal`)
-    FPSubnormal,
-    /// A regular floating point number
-    FPNormal,
-}
-
-/// Operations on primitive floating point numbers.
-// FIXME(#5527): In a future version of Rust, many of these functions will
-//               become constants.
-//
-// FIXME(#8888): Several of these functions have a parameter named
-//               `unused_self`. Removing it requires #8888 to be fixed.
-pub trait Float: Signed + Primitive {
-    /// Returns the NaN value.
-    fn nan() -> Self;
-    /// Returns the infinite value.
-    fn infinity() -> Self;
-    /// Returns the negative infinite value.
-    fn neg_infinity() -> Self;
-    /// Returns -0.0.
-    fn neg_zero() -> Self;
-
-    /// Returns true if this value is NaN and false otherwise.
-    fn is_nan(self) -> bool;
-    /// Returns true if this value is positive infinity or negative infinity and
-    /// false otherwise.
-    fn is_infinite(self) -> bool;
-    /// Returns true if this number is neither infinite nor NaN.
-    fn is_finite(self) -> bool;
-    /// Returns true if this number is neither zero, infinite, denormal, or NaN.
-    fn is_normal(self) -> bool;
-    /// Returns the category that this number falls into.
-    fn classify(self) -> FPCategory;
-
-    // FIXME (#5527): These should be associated constants
-
-    /// Returns the number of binary digits of mantissa that this type supports.
-    fn mantissa_digits(unused_self: Option<Self>) -> uint;
-    /// Returns the number of base-10 digits of precision that this type supports.
-    fn digits(unused_self: Option<Self>) -> uint;
-    /// Returns the difference between 1.0 and the smallest representable number larger than 1.0.
-    fn epsilon() -> Self;
-    /// Returns the minimum binary exponent that this type can represent.
-    fn min_exp(unused_self: Option<Self>) -> int;
-    /// Returns the maximum binary exponent that this type can represent.
-    fn max_exp(unused_self: Option<Self>) -> int;
-    /// Returns the minimum base-10 exponent that this type can represent.
-    fn min_10_exp(unused_self: Option<Self>) -> int;
-    /// Returns the maximum base-10 exponent that this type can represent.
-    fn max_10_exp(unused_self: Option<Self>) -> int;
-    /// Returns the smallest normalized positive number that this type can represent.
-    fn min_pos_value(unused_self: Option<Self>) -> Self;
-
+/// Mathematical operations on primitive floating point numbers.
+pub trait FloatMath: Float {
     /// Constructs a floating point number created by multiplying `x` by 2
     /// raised to the power of `exp`.
     fn ldexp(x: Self, exp: int) -> Self;
@@ -105,82 +47,22 @@ pub trait Float: Signed + Primitive {
     ///
     ///  * `0.5 <= abs(x) < 1.0`
     fn frexp(self) -> (Self, int);
-    /// Returns the mantissa, exponent and sign as integers, respectively.
-    fn integer_decode(self) -> (u64, i16, i8);
 
     /// Returns the next representable floating-point value in the direction of
     /// `other`.
     fn next_after(self, other: Self) -> Self;
 
-    /// Return the largest integer less than or equal to a number.
-    fn floor(self) -> Self;
-    /// Return the smallest integer greater than or equal to a number.
-    fn ceil(self) -> Self;
-    /// Return the nearest integer to a number. Round half-way cases away from
-    /// `0.0`.
-    fn round(self) -> Self;
-    /// Return the integer part of a number.
-    fn trunc(self) -> Self;
-    /// Return the fractional part of a number.
-    fn fract(self) -> Self;
-
     /// Returns the maximum of the two numbers.
     fn max(self, other: Self) -> Self;
     /// Returns the minimum of the two numbers.
     fn min(self, other: Self) -> Self;
 
-    /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
-    /// error. This produces a more accurate result with better performance than
-    /// a separate multiplication operation followed by an add.
-    fn mul_add(self, a: Self, b: Self) -> Self;
-    /// Take the reciprocal (inverse) of a number, `1/x`.
-    fn recip(self) -> Self;
-
-    /// Raise a number to an integer power.
-    ///
-    /// Using this function is generally faster than using `powf`
-    fn powi(self, n: i32) -> Self;
-    /// Raise a number to a floating point power.
-    fn powf(self, n: Self) -> Self;
-
-    /// sqrt(2.0).
-    fn sqrt2() -> Self;
-    /// 1.0 / sqrt(2.0).
-    fn frac_1_sqrt2() -> Self;
-
-    /// Take the square root of a number.
-    fn sqrt(self) -> Self;
-    /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`.
-    fn rsqrt(self) -> Self;
     /// Take the cubic root of a number.
     fn cbrt(self) -> Self;
     /// Calculate the length of the hypotenuse of a right-angle triangle given
     /// legs of length `x` and `y`.
     fn hypot(self, other: Self) -> Self;
 
-    // FIXME (#5527): These should be associated constants
-
-    /// Archimedes' constant.
-    fn pi() -> Self;
-    /// 2.0 * pi.
-    fn two_pi() -> Self;
-    /// pi / 2.0.
-    fn frac_pi_2() -> Self;
-    /// pi / 3.0.
-    fn frac_pi_3() -> Self;
-    /// pi / 4.0.
-    fn frac_pi_4() -> Self;
-    /// pi / 6.0.
-    fn frac_pi_6() -> Self;
-    /// pi / 8.0.
-    fn frac_pi_8() -> Self;
-    /// 1.0 / pi.
-    fn frac_1_pi() -> Self;
-    /// 2.0 / pi.
-    fn frac_2_pi() -> Self;
-    /// 2.0 / sqrt(pi).
-    fn frac_2_sqrtpi() -> Self;
-
     /// Computes the sine of a number (in radians).
     fn sin(self) -> Self;
     /// Computes the cosine of a number (in radians).
@@ -206,32 +88,9 @@ pub trait Float: Signed + Primitive {
     /// `(sin(x), cos(x))`.
     fn sin_cos(self) -> (Self, Self);
 
-    /// Euler's number.
-    fn e() -> Self;
-    /// log2(e).
-    fn log2_e() -> Self;
-    /// log10(e).
-    fn log10_e() -> Self;
-    /// ln(2.0).
-    fn ln_2() -> Self;
-    /// ln(10.0).
-    fn ln_10() -> Self;
-
-    /// Returns `e^(self)`, (the exponential function).
-    fn exp(self) -> Self;
-    /// Returns 2 raised to the power of the number, `2^(self)`.
-    fn exp2(self) -> Self;
     /// Returns the exponential of the number, minus 1, in a way that is
     /// accurate even if the number is close to zero.
     fn exp_m1(self) -> Self;
-    /// Returns the natural logarithm of the number.
-    fn ln(self) -> Self;
-    /// Returns the logarithm of the number with respect to an arbitrary base.
-    fn log(self, base: Self) -> Self;
-    /// Returns the base 2 logarithm of the number.
-    fn log2(self) -> Self;
-    /// Returns the base 10 logarithm of the number.
-    fn log10(self) -> Self;
     /// Returns the natural logarithm of the number plus 1 (`ln(1+n)`) more
     /// accurately than if the operations were performed separately.
     fn ln_1p(self) -> Self;
@@ -248,11 +107,6 @@ pub trait Float: Signed + Primitive {
     fn acosh(self) -> Self;
     /// Inverse hyperbolic tangent function.
     fn atanh(self) -> Self;
-
-    /// Convert radians to degrees.
-    fn to_degrees(self) -> Self;
-    /// Convert degrees to radians.
-    fn to_radians(self) -> Self;
 }
 
 /// A generic trait for converting a value to a string with a radix (base)
index 4769b17fb2b84e7d15eb795117fd95311448ef69..e58872b8395a6c388cc974eb83aa007c2bd3de6e 100644 (file)
@@ -169,6 +169,7 @@ impl NumStrConv for $t {
  * # Failure
  * - Fails if `radix` < 2 or `radix` > 36.
  */
+#[deprecated = "format!() and friends should be favored instead"]
 pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f: |u8|) {
     assert!(2 <= radix && radix <= 36);
 
@@ -257,6 +258,7 @@ pub fn int_to_str_bytes_common<T: Int>(num: T, radix: uint, sign: SignFormat, f:
  * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
  *   between digit and exponent sign `'p'`.
  */
+#[allow(deprecated)]
 pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+
                                   Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
         num: T, radix: uint, negative_zero: bool,
@@ -819,7 +821,6 @@ mod uint {
         use super::test::Bencher;
         use rand::{XorShiftRng, Rng};
         use num::ToStrRadix;
-        use realstd::result::ResultUnwrap;
 
         #[bench]
         fn to_str_bin(b: &mut Bencher) {
@@ -856,7 +857,6 @@ mod int {
         use super::test::Bencher;
         use rand::{XorShiftRng, Rng};
         use num::ToStrRadix;
-        use realstd::result::ResultUnwrap;
 
         #[bench]
         fn to_str_bin(b: &mut Bencher) {
@@ -893,7 +893,6 @@ mod f64 {
         use super::test::Bencher;
         use rand::{XorShiftRng, Rng};
         use f64;
-        use realstd::result::ResultUnwrap;
 
         #[bench]
         fn float_to_str(b: &mut Bencher) {
index 5c93ca6c36b79748b8fba3a704eb353d4dd0feaa..65ac46af5aa0c80bdbc780119f221a34f1ef142b 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::u16::{BITS, BYTES, MIN, MAX};
 
index 436eae7cd14d0c839acb9f0a0a617560acaeb478..d549e4d0d636253aee6d7398f4f940344d6b32be 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::u32::{BITS, BYTES, MIN, MAX};
 
index c654d6fbe3133df7e4e6cf36e0d4a58939a36741..3773e56f4d16df1f00d51025911947936fb8b9cf 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::u64::{BITS, BYTES, MIN, MAX};
 
index 7051b9191be8158ba668ec23d3b079068383b5ce..372e38d66521f1173e33e3e8e9e3ebb87db25839 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::u8::{BITS, BYTES, MIN, MAX};
 
index d1c3e96b2c987d7334b82dd6d3dc0b70d88141e1..c419276fa24518024d4494e495f70e34ead2c155 100644 (file)
@@ -15,7 +15,6 @@
 use num::strconv;
 use option::Option;
 use slice::ImmutableVector;
-use str;
 
 pub use core::uint::{BITS, BYTES, MIN, MAX};
 
index 0795238a49cff9578865f34f431f431575219533..7977c647606775f695f4a84480a8dce5dfe9df46 100644 (file)
@@ -63,31 +63,23 @@ fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
 /// ```
 #[inline]
 pub fn to_str_bytes<U>(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U {
+    use io::{Writer, Seek};
     // The radix can be as low as 2, so we need at least 64 characters for a
-    // base 2 number.
-    let mut buf = [0u8, ..64];
-    let mut cur = 0;
-    strconv::int_to_str_bytes_common(n, radix, strconv::SignNone, |i| {
-        buf[cur] = i;
-        cur += 1;
-    });
-    f(buf.slice(0, cur))
+    // base 2 number, and then we need another for a possible '-' character.
+    let mut buf = [0u8, ..65];
+    let amt = {
+        let mut wr = ::io::BufWriter::new(buf);
+        (write!(&mut wr, "{}", ::fmt::radix(n, radix as u8))).unwrap();
+        wr.tell().unwrap() as uint
+    };
+    f(buf.slice(0, amt))
 }
 
 impl ToStrRadix for $T {
     /// Convert to a string in a given base.
     #[inline]
     fn to_str_radix(&self, radix: uint) -> ~str {
-        use slice::Vector;
-        use str::StrAllocating;
-
-        let mut buf = ::vec::Vec::new();
-        strconv::int_to_str_bytes_common(*self, radix, strconv::SignNone, |i| {
-            buf.push(i);
-        });
-        // We know we generated valid utf-8, so we don't need to go through that
-        // check.
-        unsafe { str::raw::from_utf8(buf.as_slice()).to_owned() }
+        format!("{}", ::fmt::radix(*self, radix as u8))
     }
 }
 
index 88081d90b40013d55c8e37acb74e118e65659de7..a4705b78caab7419c9a53e3727c095a9dcfc2340 100644 (file)
@@ -1073,19 +1073,19 @@ fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
             ErrAlreadyExists => "File mapping for specified file already exists",
             ErrZeroLength => "Zero-length mapping not allowed",
             ErrUnknown(code) => {
-                return write!(out.buf, "Unknown error = {}", code)
+                return write!(out, "Unknown error = {}", code)
             },
             ErrVirtualAlloc(code) => {
-                return write!(out.buf, "VirtualAlloc failure = {}", code)
+                return write!(out, "VirtualAlloc failure = {}", code)
             },
             ErrCreateFileMappingW(code) => {
-                return write!(out.buf, "CreateFileMappingW failure = {}", code)
+                return write!(out, "CreateFileMappingW failure = {}", code)
             },
             ErrMapViewOfFile(code) => {
-                return write!(out.buf, "MapViewOfFile failure = {}", code)
+                return write!(out, "MapViewOfFile failure = {}", code)
             }
         };
-        write!(out.buf, "{}", str)
+        write!(out, "{}", str)
     }
 }
 
index 3af12c5154c29d5f08847f5ca209ff53f477781d..bd6684b390572b217e717aff2305146e30288239 100644 (file)
@@ -14,6 +14,7 @@
 use clone::Clone;
 use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering};
 use default::Default;
+use fmt;
 use intrinsics;
 use mem;
 use raw::TraitObject;
@@ -99,3 +100,16 @@ fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
         }
     }
 }
+
+impl<T: fmt::Show> fmt::Show for Box<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+#[cfg(not(stage0))]
+impl fmt::Show for Box<Any> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.pad("Box<Any>")
+    }
+}
index 99a281755e4e0c2f137cd41093484548c7ff5707..4f7132dc6e442238af1107a7abba4a7658239d48 100644 (file)
@@ -79,11 +79,18 @@ fn from_str(s: &str) -> Option<Path> {
     }
 }
 
+// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
+// we cannot usefully take ToCStr arguments by reference (without forcing an
+// additional & around &str). So we are instead temporarily adding an instance
+// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
+// instance should be removed, and arguments bound by ToCStr should be passed by
+// reference.
+
 impl ToCStr for Path {
     #[inline]
     fn to_c_str(&self) -> CString {
         // The Path impl guarantees no internal NUL
-        unsafe { self.as_vec().to_c_str_unchecked() }
+        unsafe { self.to_c_str_unchecked() }
     }
 
     #[inline]
@@ -92,6 +99,18 @@ unsafe fn to_c_str_unchecked(&self) -> CString {
     }
 }
 
+impl<'a> ToCStr for &'a Path {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        (*self).to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        (*self).to_c_str_unchecked()
+    }
+}
+
 impl<S: Writer> ::hash::Hash<S> for Path {
     #[inline]
     fn hash(&self, state: &mut S) {
index dfe7241d7af035b9c82f4d7201443a98f376bda4..176788edcc46650720f705a303e5d5c7f19ec44b 100644 (file)
@@ -103,11 +103,18 @@ fn from_str(s: &str) -> Option<Path> {
     }
 }
 
+// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so
+// we cannot usefully take ToCStr arguments by reference (without forcing an
+// additional & around &str). So we are instead temporarily adding an instance
+// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path
+// instance should be removed, and arguments bound by ToCStr should be passed by
+// reference.
+
 impl ToCStr for Path {
     #[inline]
     fn to_c_str(&self) -> CString {
-        // The Path impl guarantees no embedded NULs
-        unsafe { self.as_vec().to_c_str_unchecked() }
+        // The Path impl guarantees no internal NUL
+        unsafe { self.to_c_str_unchecked() }
     }
 
     #[inline]
@@ -116,6 +123,18 @@ unsafe fn to_c_str_unchecked(&self) -> CString {
     }
 }
 
+impl<'a> ToCStr for &'a Path {
+    #[inline]
+    fn to_c_str(&self) -> CString {
+        (*self).to_c_str()
+    }
+
+    #[inline]
+    unsafe fn to_c_str_unchecked(&self) -> CString {
+        (*self).to_c_str_unchecked()
+    }
+}
+
 impl<S: Writer> ::hash::Hash<S> for Path {
     #[inline]
     fn hash(&self, state: &mut S) {
index 6cd9e96496fe0ae85fb3557435cd3df7cffe3e91..e39d8d34447a465e4eb54e8aaa91e762fb50e026 100644 (file)
 pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
 pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
 pub use num::{Signed, Unsigned};
-pub use num::{Primitive, Int, Float, ToPrimitive, FromPrimitive};
+pub use num::{Primitive, Int, Float, FloatMath, ToPrimitive, FromPrimitive};
 pub use option::Expect;
 pub use owned::Box;
 pub use path::{GenericPath, Path, PosixPath, WindowsPath};
 pub use ptr::RawPtr;
 pub use io::{Buffer, Writer, Reader, Seek};
-pub use result::{ResultUnwrap, ResultUnwrapErr};
 pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
 pub use str::{StrAllocating};
 pub use to_str::{ToStr, IntoStr};
index 6029f504d10b62a5b426e935f628d852f011282f..35f32d0872802d3e3b8ad11b869d08022c5ba4d2 100644 (file)
@@ -25,7 +25,7 @@
 use ptr::RawPtr;
 use reflect;
 use reflect::{MovePtr, align};
-use result::{Ok, Err, ResultUnwrap};
+use result::{Ok, Err};
 use str::StrSlice;
 use to_str::ToStr;
 use slice::Vector;
diff --git a/src/libstd/result.rs b/src/libstd/result.rs
deleted file mode 100644 (file)
index ecbc164..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2012-2014 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.
-
-//! Error handling with the `Result` type
-//!
-//! `Result<T>` is the type used for returning and propagating
-//! errors. It is an enum with the variants, `Ok(T)`, representing
-//! success and containing a value, and `Err(E)`, representing error
-//! and containing an error value.
-//!
-//! ~~~
-//! enum Result<T, E> {
-//!    Ok(T),
-//!    Err(E)
-//! }
-//! ~~~
-//!
-//! Functions return `Result` whenever errors are expected and
-//! recoverable. In the `std` crate `Result` is most prominently used
-//! for [I/O](../io/index.html).
-//!
-//! A simple function returning `Result` might be
-//! defined and used like so:
-//!
-//! ~~~
-//! #[deriving(Show)]
-//! enum Version { Version1, Version2 }
-//!
-//! fn parse_version(header: &[u8]) -> Result<Version, &'static str> {
-//!     if header.len() < 1 {
-//!         return Err("invalid header length");
-//!     }
-//!     match header[0] {
-//!         1 => Ok(Version1),
-//!         2 => Ok(Version2),
-//!         _ => Err("invalid version")
-//!     }
-//! }
-//!
-//! let version = parse_version(&[1, 2, 3, 4]);
-//! match version {
-//!     Ok(v) => {
-//!         println!("working with version: {}", v);
-//!     }
-//!     Err(e) => {
-//!         println!("error parsing header: {}", e);
-//!     }
-//! }
-//! ~~~
-//!
-//! Pattern matching on `Result`s is clear and straightforward for
-//! simple cases, but `Result` comes with some convenience methods
-//! that make working it more succinct.
-//!
-//! ~~~
-//! let good_result: Result<int, int> = Ok(10);
-//! let bad_result: Result<int, int> = Err(10);
-//!
-//! // The `is_ok` and `is_err` methods do what they say.
-//! assert!(good_result.is_ok() && !good_result.is_err());
-//! assert!(bad_result.is_err() && !bad_result.is_ok());
-//!
-//! // `map` consumes the `Result` and produces another.
-//! let good_result: Result<int, int> = good_result.map(|i| i + 1);
-//! let bad_result: Result<int, int> = bad_result.map(|i| i - 1);
-//!
-//! // Use `and_then` to continue the computation.
-//! let good_result: Result<bool, int> = good_result.and_then(|i| Ok(i == 11));
-//!
-//! // Use `or_else` to handle the error.
-//! let bad_result: Result<int, int> = bad_result.or_else(|i| Ok(11));
-//!
-//! // Consume the result and return the contents with `unwrap`.
-//! let final_awesome_result = good_result.ok().unwrap();
-//! ~~~
-//!
-//! # Results must be used
-//!
-//! A common problem with using return values to indicate errors is
-//! that it is easy to ignore the return value, thus failing to handle
-//! the error. Result is annotated with the #[must_use] attribute,
-//! which will cause the compiler to issue a warning when a Result
-//! value is ignored. This makes `Result` especially useful with
-//! functions that may encounter errors but don't otherwise return a
-//! useful value.
-//!
-//! Consider the `write_line` method defined for I/O types
-//! by the [`Writer`](../io/trait.Writer.html) trait:
-//!
-//! ~~~
-//! use std::io::IoError;
-//!
-//! trait Writer {
-//!     fn write_line(&mut self, s: &str) -> Result<(), IoError>;
-//! }
-//! ~~~
-//!
-//! *Note: The actual definition of `Writer` uses `IoResult`, which
-//! is just a synonym for `Result<T, IoError>`.*
-//!
-//! This method doesn`t produce a value, but the write may
-//! fail. It's crucial to handle the error case, and *not* write
-//! something like this:
-//!
-//! ~~~ignore
-//! use std::io::{File, Open, Write};
-//!
-//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! // If `write_line` errors, then we'll never know, because the return
-//! // value is ignored.
-//! file.write_line("important message");
-//! drop(file);
-//! ~~~
-//!
-//! If you *do* write that in Rust, the compiler will by give you a
-//! warning (by default, controlled by the `unused_must_use` lint).
-//!
-//! You might instead, if you don't want to handle the error, simply
-//! fail, by converting to an `Option` with `ok`, then asserting
-//! success with `expect`. This will fail if the write fails, proving
-//! a marginally useful message indicating why:
-//!
-//! ~~~no_run
-//! use std::io::{File, Open, Write};
-//!
-//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! file.write_line("important message").ok().expect("failed to write message");
-//! drop(file);
-//! ~~~
-//!
-//! You might also simply assert success:
-//!
-//! ~~~no_run
-//! # use std::io::{File, Open, Write};
-//!
-//! # let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! assert!(file.write_line("important message").is_ok());
-//! # drop(file);
-//! ~~~
-//!
-//! Or propagate the error up the call stack with `try!`:
-//!
-//! ~~~
-//! # use std::io::{File, Open, Write, IoError};
-//! fn write_message() -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//!     try!(file.write_line("important message"));
-//!     drop(file);
-//!     return Ok(());
-//! }
-//! ~~~
-//!
-//! # The `try!` macro
-//!
-//! When writing code that calls many functions that return the
-//! `Result` type, the error handling can be tedious.  The `try!`
-//! macro hides some of the boilerplate of propagating errors up the
-//! call stack.
-//!
-//! It replaces this:
-//!
-//! ~~~
-//! use std::io::{File, Open, Write, IoError};
-//!
-//! struct Info { name: ~str, age: int, rating: int }
-//!
-//! fn write_info(info: &Info) -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
-//!     // Early return on error
-//!     match file.write_line(format!("name: {}", info.name)) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
-//!     }
-//!     match file.write_line(format!("age: {}", info.age)) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
-//!     }
-//!     return file.write_line(format!("rating: {}", info.rating));
-//! }
-//! ~~~
-//!
-//! With this:
-//!
-//! ~~~
-//! use std::io::{File, Open, Write, IoError};
-//!
-//! struct Info { name: ~str, age: int, rating: int }
-//!
-//! fn write_info(info: &Info) -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
-//!     // Early return on error
-//!     try!(file.write_line(format!("name: {}", info.name)));
-//!     try!(file.write_line(format!("age: {}", info.age)));
-//!     try!(file.write_line(format!("rating: {}", info.rating)));
-//!     return Ok(());
-//! }
-//! ~~~
-//!
-//! *It's much nicer!*
-//!
-//! Wrapping an expression in `try!` will result in the unwrapped
-//! success (`Ok`) value, unless the result is `Err`, in which case
-//! `Err` is returned early from the enclosing function. Its simple definition
-//! makes it clear:
-//!
-//! ~~~
-//! # #![feature(macro_rules)]
-//! macro_rules! try(
-//!     ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
-//! )
-//! # fn main() { }
-//! ~~~
-//!
-//! `try!` is imported by the prelude, and is available everywhere.
-//!
-//! # `Result` and `Option`
-//!
-//! The `Result` and [`Option`](../option/index.html) types are
-//! similar and complementary: they are often employed to indicate a
-//! lack of a return value; and they are trivially converted between
-//! each other, so `Result`s are often handled by first converting to
-//! `Option` with the [`ok`](../../core/result/enum.Result.html#method.ok) and
-//! [`err`](../../core/result/enum.Result.html#method.ok) methods.
-//!
-//! Whereas `Option` only indicates the lack of a value, `Result` is
-//! specifically for error reporting, and carries with it an error
-//! value.  Sometimes `Option` is used for indicating errors, but this
-//! is only for simple cases and is generally discouraged. Even when
-//! there is no useful error value to return, prefer `Result<T, ()>`.
-//!
-//! Converting to an `Option` with `ok()` to handle an error:
-//!
-//! ~~~
-//! use std::io::Timer;
-//! let mut t = Timer::new().ok().expect("failed to create timer!");
-//! ~~~
-//!
-//! # `Result` vs. `fail!`
-//!
-//! `Result` is for recoverable errors; `fail!` is for unrecoverable
-//! errors. Callers should always be able to avoid failure if they
-//! take the proper precautions, for example, calling `is_some()`
-//! on an `Option` type before calling `unwrap`.
-//!
-//! The suitability of `fail!` as an error handling mechanism is
-//! limited by Rust's lack of any way to "catch" and resume execution
-//! from a thrown exception. Therefore using failure for error
-//! handling requires encapsulating fallable code in a task. Calling
-//! the `fail!` macro, or invoking `fail!` indirectly should be
-//! avoided as an error reporting strategy. Failure is only for
-//! unrecoverable errors and a failing task is typically the sign of
-//! a bug.
-//!
-//! A module that instead returns `Results` is alerting the caller
-//! that failure is possible, and providing precise control over how
-//! it is handled.
-//!
-//! Furthermore, failure may not be recoverable at all, depending on
-//! the context. The caller of `fail!` should assume that execution
-//! will not resume after failure, that failure is catastrophic.
-
-use fmt::Show;
-
-pub use core::result::{Result, Ok, Err, collect, fold, fold_};
-
-// FIXME: These traits should not exist. Once std::fmt is moved to libcore,
-//        these can once again become inherent methods on Result.
-
-/// Temporary trait for unwrapping a result
-pub trait ResultUnwrap<T, E> {
-    /// Unwraps a result, yielding the content of an `Ok`.
-    ///
-    /// Fails if the value is an `Err`.
-    fn unwrap(self) -> T;
-}
-
-/// Temporary trait for unwrapping the error of a result
-pub trait ResultUnwrapErr<T, E> {
-    /// Unwraps a result, yielding the content of an `Err`.
-    ///
-    /// Fails if the value is an `Ok`.
-    fn unwrap_err(self) -> E;
-}
-
-impl<T, E: Show> ResultUnwrap<T, E> for Result<T, E> {
-    #[inline]
-    fn unwrap(self) -> T {
-        match self {
-            Ok(t) => t,
-            Err(e) =>
-                fail!("called `Result::unwrap()` on an `Err` value: {}", e)
-        }
-    }
-}
-
-impl<T: Show, E> ResultUnwrapErr<T, E> for Result<T, E> {
-    #[inline]
-    fn unwrap_err(self) -> E {
-        match self {
-            Ok(t) =>
-                fail!("called `Result::unwrap_err()` on an `Ok` value: {}", t),
-            Err(e) => e
-        }
-    }
-}
index 05d1f1764b59f0d34bb8b1ae69cf0b7fc9e0d95d..9f0ed8044800cbbfec32f75954eb5ba9ae779347 100644 (file)
@@ -53,24 +53,24 @@ unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
 #[cfg(test)]
 mod test {
     use option::{None, Option};
-    use unstable::run_in_bare_thread;
+    use rt::thread::Thread;
     use super::*;
     use owned::Box;
     use rt::task::Task;
 
     #[test]
     fn thread_local_task_smoke_test() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let task = box Task::new();
             Local::put(task);
             let task: Box<Task> = Local::take();
             cleanup_task(task);
-        });
+        }).join();
     }
 
     #[test]
     fn thread_local_task_two_instances() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let task = box Task::new();
             Local::put(task);
             let task: Box<Task> = Local::take();
@@ -79,12 +79,12 @@ fn thread_local_task_two_instances() {
             Local::put(task);
             let task: Box<Task> = Local::take();
             cleanup_task(task);
-        });
+        }).join();
     }
 
     #[test]
     fn borrow_smoke_test() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let task = box Task::new();
             Local::put(task);
 
@@ -93,12 +93,12 @@ fn borrow_smoke_test() {
             }
             let task: Box<Task> = Local::take();
             cleanup_task(task);
-        });
+        }).join();
     }
 
     #[test]
     fn borrow_with_return() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let task = box Task::new();
             Local::put(task);
 
@@ -108,12 +108,12 @@ fn borrow_with_return() {
 
             let task: Box<Task> = Local::take();
             cleanup_task(task);
-        });
+        }).join();
     }
 
     #[test]
     fn try_take() {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let task = box Task::new();
             Local::put(task);
 
@@ -122,7 +122,7 @@ fn try_take() {
             assert!(u.is_none());
 
             cleanup_task(t);
-        });
+        }).join();
     }
 
     fn cleanup_task(mut t: Box<Task>) {
index 90f97e59caadad6a4d0960d95fcc2f9d4b2355ee..a6c60df2642362798c899343eddcfa535c5bc8f2 100644 (file)
@@ -29,7 +29,7 @@
 use io;
 use io::IoResult;
 use io::net::ip::{IpAddr, SocketAddr};
-use io::process::{ProcessConfig, ProcessExit};
+use io::process::{StdioContainer, ProcessExit};
 use io::signal::Signum;
 use io::{FileMode, FileAccess, FileStat, FilePermission};
 use io::{SeekStyle};
@@ -87,6 +87,61 @@ pub enum CloseBehavior {
     CloseAsynchronously,
 }
 
+/// Data needed to spawn a process. Serializes the `std::io::process::Command`
+/// builder.
+pub struct ProcessConfig<'a> {
+    /// Path to the program to run.
+    pub program: &'a CString,
+
+    /// Arguments to pass to the program (doesn't include the program itself).
+    pub args: &'a [CString],
+
+    /// Optional environment to specify for the program. If this is None, then
+    /// it will inherit the current process's environment.
+    pub env: Option<&'a [(CString, CString)]>,
+
+    /// Optional working directory for the new process. If this is None, then
+    /// the current directory of the running process is inherited.
+    pub cwd: Option<&'a CString>,
+
+    /// Configuration for the child process's stdin handle (file descriptor 0).
+    /// This field defaults to `CreatePipe(true, false)` so the input can be
+    /// written to.
+    pub stdin: StdioContainer,
+
+    /// Configuration for the child process's stdout handle (file descriptor 1).
+    /// This field defaults to `CreatePipe(false, true)` so the output can be
+    /// collected.
+    pub stdout: StdioContainer,
+
+    /// Configuration for the child process's stdout handle (file descriptor 2).
+    /// This field defaults to `CreatePipe(false, true)` so the output can be
+    /// collected.
+    pub stderr: StdioContainer,
+
+    /// 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
+    /// 3 and go to the length of this array. The first three file descriptors
+    /// (stdin/stdout/stderr) are configured with the `stdin`, `stdout`, and
+    /// `stderr` fields.
+    pub extra_io: &'a [StdioContainer],
+
+    /// Sets the child process's user id. This translates to a `setuid` call in
+    /// the child process. Setting this value on windows will cause the spawn to
+    /// fail. Failure in the `setuid` call on unix will also cause the spawn to
+    /// fail.
+    pub uid: Option<uint>,
+
+    /// Similar to `uid`, but sets the group id of the child process. This has
+    /// the same semantics as the `uid` field.
+    pub gid: Option<uint>,
+
+    /// If true, the child process is spawned in a detached state. On unix, this
+    /// means that the child is the leader of a new process group.
+    pub detach: bool,
+}
+
 pub struct LocalIo<'a> {
     factory: &'a mut IoFactory,
 }
@@ -189,7 +244,7 @@ fn fs_utime(&mut self, src: &CString, atime: u64, mtime: u64) ->
 
     // misc
     fn timer_init(&mut self) -> IoResult<Box<RtioTimer:Send>>;
-    fn spawn(&mut self, config: ProcessConfig)
+    fn spawn(&mut self, cfg: ProcessConfig)
             -> IoResult<(Box<RtioProcess:Send>,
                          Vec<Option<Box<RtioPipe:Send>>>)>;
     fn kill(&mut self, pid: libc::pid_t, signal: int) -> IoResult<()>;
index 4f0d7d35ce892f4618821719cce83558fa4c36a1..e25fa4734d5cb0e06161e8daae2a6e8607264503 100644 (file)
@@ -273,13 +273,8 @@ pub unsafe fn detach(native: rust_thread) {
         assert_eq!(pthread_detach(native), 0);
     }
 
-    #[cfg(target_os = "macos")]
-    #[cfg(target_os = "android")]
     pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
 
-    #[cfg(not(target_os = "macos"), not(target_os = "android"))]
-    pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); }
-
     // glibc >= 2.15 has a __pthread_get_minstack() function that returns
     // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
     // storage.  We need that information to avoid blowing up when a small stack
@@ -326,12 +321,7 @@ fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
         fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                        state: libc::c_int) -> libc::c_int;
         fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
-
-        #[cfg(target_os = "macos")]
-        #[cfg(target_os = "android")]
         fn sched_yield() -> libc::c_int;
-        #[cfg(not(target_os = "macos"), not(target_os = "android"))]
-        fn pthread_yield() -> libc::c_int;
     }
 }
 
index e10e0716f67f2bea6c58168c7289280deb30f9f8..1cc513825a707e50831692cd7af452d8b70cb442 100644 (file)
@@ -295,24 +295,12 @@ pub extern "C" fn rust_eh_personality_catch(
     }
 }
 
-#[cold]
-#[no_mangle]
-#[cfg(not(test))]
-pub extern fn rust_fail_bounds_check(file: *u8, line: uint,
-                                     index: uint, len: uint) -> ! {
-    use str::raw::c_str_to_static_slice;
-
-    let msg = format!("index out of bounds: the len is {} but the index is {}",
-                      len as uint, index as uint);
-    begin_unwind(msg, unsafe { c_str_to_static_slice(file as *i8) }, line)
-}
-
 // Entry point of failure from the libcore crate
 #[no_mangle]
 #[cfg(not(test))]
-pub extern fn rust_begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
-    use str::StrAllocating;
-    begin_unwind(msg.to_owned(), file, line)
+pub extern fn rust_begin_unwind(msg: &fmt::Arguments,
+                                file: &'static str, line: uint) -> ! {
+    begin_unwind_fmt(msg, file, line)
 }
 
 /// The entry point for unwinding with a formatted message.
@@ -402,9 +390,9 @@ fn begin_unwind_inner(msg: Box<Any:Send>,
                 Some(mut stderr) => {
                     Local::put(task);
                     // FIXME: what to do when the task printing fails?
-                    let _err = format_args!(|args| ::fmt::writeln(stderr, args),
-                                            "task '{}' failed at '{}', {}:{}",
-                                            n, msg_s, file, line);
+                    let _err = write!(stderr,
+                                      "task '{}' failed at '{}', {}:{}\n",
+                                      n, msg_s, file, line);
                     if backtrace::log_enabled() {
                         let _err = backtrace::write(stderr);
                     }
index e8b1acb10241f331d970058695aeeb6810e0e437..5f9ea14a64711467c432ea1474a4d09b7c5e493a 100644 (file)
@@ -110,8 +110,9 @@ fn write(&mut self, data: &[u8]) -> IoResult<()> {
 }
 
 pub fn dumb_println(args: &fmt::Arguments) {
+    use io::Writer;
     let mut w = Stderr;
-    let _ = fmt::writeln(&mut w as &mut io::Writer, args);
+    let _ = writeln!(&mut w, "{}", args);
 }
 
 pub fn abort(msg: &str) -> ! {
index fa4cf8e4427d0473b14e10fc5ebf1f1f8f35f101..617887e8af3ea9e5c61f53364e899b510c96710b 100644 (file)
@@ -87,6 +87,7 @@ fn main() {
 use mem::transmute;
 use mem;
 use option::{None, Option, Some};
+use result::{Result, Ok, Err};
 use slice::Vector;
 use slice::{ImmutableVector, MutableVector, CloneableVector};
 use strbuf::StrBuf;
@@ -105,12 +106,14 @@ fn main() {
 */
 
 /// Consumes a vector of bytes to create a new utf-8 string.
-/// Returns None if the vector contains invalid UTF-8.
-pub fn from_utf8_owned(vv: ~[u8]) -> Option<~str> {
+///
+/// Returns `Err` with the original vector if the vector contains invalid
+/// UTF-8.
+pub fn from_utf8_owned(vv: ~[u8]) -> Result<~str, ~[u8]> {
     if is_utf8(vv) {
-        Some(unsafe { raw::from_utf8_owned(vv) })
+        Ok(unsafe { raw::from_utf8_owned(vv) })
     } else {
-        None
+        Err(vv)
     }
 }
 
@@ -564,6 +567,11 @@ impl<'a> IntoMaybeOwned<'a> for ~str {
     fn into_maybe_owned(self) -> MaybeOwned<'a> { Owned(self) }
 }
 
+impl<'a> IntoMaybeOwned<'a> for StrBuf {
+    #[inline]
+    fn into_maybe_owned(self) -> MaybeOwned<'a> { Owned(self.into_owned()) }
+}
+
 impl<'a> IntoMaybeOwned<'a> for &'a str {
     #[inline]
     fn into_maybe_owned(self) -> MaybeOwned<'a> { Slice(self) }
@@ -2115,13 +2123,13 @@ fn test_str_from_utf8() {
     #[test]
     fn test_str_from_utf8_owned() {
         let xs = bytes!("hello").to_owned();
-        assert_eq!(from_utf8_owned(xs), Some("hello".to_owned()));
+        assert_eq!(from_utf8_owned(xs), Ok("hello".to_owned()));
 
         let xs = bytes!("ศไทย中华Việt Nam").to_owned();
-        assert_eq!(from_utf8_owned(xs), Some("ศไทย中华Việt Nam".to_owned()));
+        assert_eq!(from_utf8_owned(xs), Ok("ศไทย中华Việt Nam".to_owned()));
 
         let xs = bytes!("hello", 0xff).to_owned();
-        assert_eq!(from_utf8_owned(xs), None);
+        assert_eq!(from_utf8_owned(xs), Err(bytes!("hello", 0xff).to_owned()));
     }
 
     #[test]
@@ -2413,4 +2421,78 @@ fn bench_connect(b: &mut Bencher) {
             assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9);
         })
     }
+
+    #[bench]
+    fn bench_contains_short_short(b: &mut Bencher) {
+        let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+        let needle = "sit";
+
+        b.iter(|| {
+            assert!(haystack.contains(needle));
+        })
+    }
+
+    #[bench]
+    fn bench_contains_short_long(b: &mut Bencher) {
+        let haystack = "\
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
+ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
+eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
+sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
+tempus vel, gravida nec quam.
+
+In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \
+sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \
+diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \
+lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \
+eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \
+interdum. Curabitur ut nisi justo.
+
+Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \
+mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \
+lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \
+est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \
+felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \
+ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \
+feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \
+Aliquam sit amet placerat lorem.
+
+Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \
+mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \
+Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \
+lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \
+suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \
+cursus accumsan.
+
+Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \
+feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
+vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
+leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
+malesuada sollicitudin quam eu fermentum.";
+        let needle = "english";
+
+        b.iter(|| {
+            assert!(!haystack.contains(needle));
+        })
+    }
+
+    #[bench]
+    fn bench_contains_bad_naive(b: &mut Bencher) {
+        let haystack = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+        let needle = "aaaaaaaab";
+
+        b.iter(|| {
+            assert!(!haystack.contains(needle));
+        })
+    }
+
+    #[bench]
+    fn bench_contains_equal(b: &mut Bencher) {
+        let haystack = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+        let needle = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+
+        b.iter(|| {
+            assert!(haystack.contains(needle));
+        })
+    }
 }
index 575de89fae2ac121b88c375544649334b54476b9..de480ef1b7fb7ddb4a6d5923bd90c6af8a389aa0 100644 (file)
@@ -20,6 +20,7 @@
 use option::{None, Option, Some};
 use ptr::RawPtr;
 use ptr;
+use result::{Result, Ok, Err};
 use slice::{OwnedVector, Vector, CloneableVector};
 use str::{CharRange, OwnedStr, Str, StrSlice, StrAllocating};
 use str;
@@ -72,14 +73,17 @@ pub fn from_owned_str(string: ~str) -> StrBuf {
         }
     }
 
-    /// Tries to create a new string buffer from the given byte
-    /// vector, validating that the vector is UTF-8 encoded.
+    /// Returns the vector as a string buffer, if possible, taking care not to
+    /// copy it.
+    ///
+    /// Returns `Err` with the original vector if the vector contains invalid
+    /// UTF-8.
     #[inline]
-    pub fn from_utf8(vec: Vec<u8>) -> Option<StrBuf> {
+    pub fn from_utf8(vec: Vec<u8>) -> Result<StrBuf, Vec<u8>> {
         if str::is_utf8(vec.as_slice()) {
-            Some(StrBuf { vec: vec })
+            Ok(StrBuf { vec: vec })
         } else {
-            None
+            Err(vec)
         }
     }
 
index 7fb61c29112dee8b26ecaaa5b587677240c4a5d4..5c875b4a2ad088acd92035d2c85f498c12e982cd 100644 (file)
@@ -49,7 +49,6 @@
 
 #[cfg(test)] use any::AnyRefExt;
 #[cfg(test)] use owned::AnyOwnExt;
-#[cfg(test)] use realstd::result::ResultUnwrap;
 #[cfg(test)] use result;
 #[cfg(test)] use str::StrAllocating;
 
index 87d531cc627e093dbc7723749e800086931d2a43..4a9c534945925f48f4ca591fd6962fe9111cad89 100644 (file)
@@ -16,8 +16,8 @@
 
 */
 
+
 use c_str::ToCStr;
-use iter::Iterator;
 use mem;
 use ops::*;
 use option::*;
@@ -25,7 +25,7 @@
 use path::GenericPath;
 use path;
 use result::*;
-use slice::{Vector,OwnedVector};
+use slice::Vector;
 use str;
 use vec::Vec;
 
@@ -45,12 +45,22 @@ fn drop(&mut self) {
 }
 
 impl DynamicLibrary {
+    // FIXME (#12938): Until DST lands, we cannot decompose &str into
+    // & and str, so we cannot usefully take ToCStr arguments by
+    // reference (without forcing an additional & around &str). So we
+    // are instead temporarily adding an instance for &Path, so that
+    // we can take ToCStr as owned. When DST lands, the &Path instance
+    // should be removed, and arguments bound by ToCStr should be
+    // passed by reference. (Here: in the `open` method.)
+
     /// Lazily open a dynamic library. When passed None it gives a
     /// handle to the calling process
-    pub fn open(filename: Option<&path::Path>) -> Result<DynamicLibrary, ~str> {
+    pub fn open<T: ToCStr>(filename: Option<T>)
+                        -> Result<DynamicLibrary, ~str> {
         unsafe {
+            let mut filename = filename;
             let maybe_library = dl::check_for_errors_in(|| {
-                match filename {
+                match filename.take() {
                     Some(name) => dl::open_external(name),
                     None => dl::open_internal()
                 }
@@ -75,10 +85,12 @@ pub fn add_search_path(path: &path::Path) {
         } else {
             ("LD_LIBRARY_PATH", ':' as u8)
         };
-        let newenv = os::getenv_as_bytes(envvar).unwrap_or(box []);
-        let mut newenv = newenv.move_iter().collect::<Vec<_>>();
-        newenv.push_all(&[sep]);
-        newenv.push_all(path.as_vec());
+        let mut newenv = Vec::from_slice(path.as_vec());
+        newenv.push(sep);
+        match os::getenv_as_bytes(envvar) {
+            Some(bytes) => newenv.push_all(bytes),
+            None => {}
+        }
         os::setenv(envvar, str::from_utf8(newenv.as_slice()).unwrap());
     }
 
@@ -114,7 +126,8 @@ mod test {
     fn test_loading_cosine() {
         // The math library does not need to be loaded since it is already
         // statically linked in
-        let libm = match DynamicLibrary::open(None) {
+        let none: Option<Path> = None; // appease the typechecker
+        let libm = match DynamicLibrary::open(none) {
             Err(error) => fail!("Could not load self as module: {}", error),
             Ok(libm) => libm
         };
@@ -142,7 +155,7 @@ fn test_loading_cosine() {
     fn test_errors_do_not_crash() {
         // Open /dev/null as a library to get an error, and make sure
         // that only causes an error, and not a crash.
-        let path = GenericPath::new("/dev/null");
+        let path = Path::new("/dev/null");
         match DynamicLibrary::open(Some(&path)) {
             Err(_) => {}
             Ok(_) => fail!("Successfully opened the empty library.")
@@ -157,12 +170,11 @@ fn test_errors_do_not_crash() {
 pub mod dl {
     use c_str::ToCStr;
     use libc;
-    use path;
     use ptr;
     use str;
     use result::*;
 
-    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
+    pub unsafe fn open_external<T: ToCStr>(filename: T) -> *u8 {
         filename.with_c_str(|raw_name| {
             dlopen(raw_name, Lazy as libc::c_int) as *u8
         })
@@ -221,13 +233,16 @@ pub enum RTLD {
 pub mod dl {
     use libc;
     use os;
-    use path::GenericPath;
-    use path;
     use ptr;
     use result::{Ok, Err, Result};
+    use str;
+    use c_str::ToCStr;
 
-    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
-        os::win32::as_utf16_p(filename.as_str().unwrap(), |raw_name| {
+    pub unsafe fn open_external<T: ToCStr>(filename: T) -> *u8 {
+        // Windows expects Unicode data
+        let filename_cstr = filename.to_c_str();
+        let filename_str = str::from_utf8(filename_cstr.as_bytes_no_nul()).unwrap();
+        os::win32::as_utf16_p(filename_str, |raw_name| {
             LoadLibraryW(raw_name as *libc::c_void) as *u8
         })
     }
index 8b07850263fe85111e0dc224a9ddfce48d80d84e..f464f70772d9412e6616f21c4f3b9bf70931f9d4 100644 (file)
@@ -11,7 +11,6 @@
 #![doc(hidden)]
 
 use libc::uintptr_t;
-use kinds::Send;
 
 pub use core::finally;
 
 pub mod sync;
 pub mod mutex;
 
-/**
-
-Start a new thread outside of the current runtime context and wait
-for it to terminate.
-
-The executing thread has no access to a task pointer and will be using
-a normal large stack.
-*/
-pub fn run_in_bare_thread(f: proc():Send) {
-    use rt::thread::Thread;
-    Thread::start(f).join()
-}
-
-#[test]
-fn test_run_in_bare_thread() {
-    let i = 100;
-    run_in_bare_thread(proc() {
-        assert_eq!(i, 100);
-    });
-}
-
-#[test]
-fn test_run_in_bare_thread_exchange() {
-    // Does the exchange heap work without the runtime?
-    let i = box 100;
-    run_in_bare_thread(proc() {
-        assert!(i == box 100);
-    });
-}
-
 /// Dynamically inquire about whether we're running under V.
 /// You should usually not use this unless your test definitely
 /// can't run correctly un-altered. Valgrind is there to help
index 528ab72762aab904a695541dba25c27fc79e700b..57f8d78948fa0ac5faab057f25693e42daf2c9c4 100644 (file)
@@ -635,14 +635,14 @@ pub fn append_one(mut self, x: T) -> Vec<T> {
     /// ```
     pub fn truncate(&mut self, len: uint) {
         unsafe {
-            let mut i = len;
             // drop any extra elements
-            while i < self.len {
-                ptr::read(self.as_slice().unsafe_ref(i));
-                i += 1;
+            while len < self.len {
+                // decrement len before the read(), so a failure on Drop doesn't
+                // re-drop the just-failed value.
+                self.len -= 1;
+                ptr::read(self.as_slice().unsafe_ref(self.len));
             }
         }
-        self.len = len;
     }
 
     /// Work with `self` as a mutable slice.
@@ -1862,4 +1862,39 @@ struct Foo {
         assert_eq!(b[0].x, 42);
         assert_eq!(b[1].x, 84);
     }
+
+    #[test]
+    fn test_vec_truncate_drop() {
+        static mut drops: uint = 0;
+        struct Elem(int);
+        impl Drop for Elem {
+            fn drop(&mut self) {
+                unsafe { drops += 1; }
+            }
+        }
+
+        let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
+        assert_eq!(unsafe { drops }, 0);
+        v.truncate(3);
+        assert_eq!(unsafe { drops }, 2);
+        v.truncate(0);
+        assert_eq!(unsafe { drops }, 5);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_vec_truncate_fail() {
+        struct BadElem(int);
+        impl Drop for BadElem {
+            fn drop(&mut self) {
+                let BadElem(ref mut x) = *self;
+                if *x == 0xbadbeef {
+                    fail!("BadElem failure: 0xbadbeef")
+                }
+            }
+        }
+
+        let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)];
+        v.truncate(0);
+    }
 }
index 17251d31351ab303b72be6c41091c02391280fba..bc53d2bec8d6e3ca2b7004af7c940b2fd9f735cf 100644 (file)
@@ -155,7 +155,7 @@ fn bit(&self) -> u32 {
 
 impl fmt::Show for Abi {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "\"{}\"", self.name())
+        write!(f, "\"{}\"", self.name())
     }
 }
 
index e5ef31a95a38b5bc3c79cecdbbf9e314cc77c35d..e7f892d77ceaaef7542d451a01fb3ddeeedd41a9 100644 (file)
@@ -106,7 +106,7 @@ fn encode(&self, s: &mut S) -> Result<(), E> {
 
 impl<D:Decoder<E>, E> Decodable<D, E> for Ident {
     fn decode(d: &mut D) -> Result<Ident, E> {
-        Ok(str_to_ident(try!(d.read_str())))
+        Ok(str_to_ident(try!(d.read_str()).as_slice()))
     }
 }
 
@@ -711,7 +711,7 @@ pub enum IntTy {
 
 impl fmt::Show for IntTy {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}",
+        write!(f, "{}",
                ast_util::int_ty_to_str(*self, None, ast_util::AutoSuffix))
     }
 }
@@ -727,7 +727,7 @@ pub enum UintTy {
 
 impl fmt::Show for UintTy {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}",
+        write!(f, "{}",
                ast_util::uint_ty_to_str(*self, None, ast_util::AutoSuffix))
     }
 }
@@ -741,7 +741,7 @@ pub enum FloatTy {
 
 impl fmt::Show for FloatTy {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", ast_util::float_ty_to_str(*self))
+        write!(f, "{}", ast_util::float_ty_to_str(*self))
     }
 }
 
index 333f876e479b168a839df0f575d243b0f0a3f758..f1561ea31f91bcae60fe5f511e09c5c58a332f91 100644 (file)
@@ -41,7 +41,7 @@ pub fn name(&self) -> Name {
 impl fmt::Show for PathElem {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let slot = token::get_name(self.name());
-        write!(f.buf, "{}", slot)
+        write!(f, "{}", slot)
     }
 }
 
@@ -103,6 +103,7 @@ pub enum Node {
     NodeStmt(@Stmt),
     NodeArg(@Pat),
     NodeLocal(@Pat),
+    NodePat(@Pat),
     NodeBlock(P<Block>),
 
     /// NodeStructCtor represents a tuple struct.
@@ -127,6 +128,7 @@ enum MapEntry {
     EntryStmt(NodeId, @Stmt),
     EntryArg(NodeId, @Pat),
     EntryLocal(NodeId, @Pat),
+    EntryPat(NodeId, @Pat),
     EntryBlock(NodeId, P<Block>),
     EntryStructCtor(NodeId, @StructDef),
     EntryLifetime(NodeId, @Lifetime),
@@ -154,6 +156,7 @@ fn parent(&self) -> Option<NodeId> {
             EntryStmt(id, _) => id,
             EntryArg(id, _) => id,
             EntryLocal(id, _) => id,
+            EntryPat(id, _) => id,
             EntryBlock(id, _) => id,
             EntryStructCtor(id, _) => id,
             EntryLifetime(id, _) => id,
@@ -172,6 +175,7 @@ fn to_node(&self) -> Option<Node> {
             EntryStmt(_, p) => NodeStmt(p),
             EntryArg(_, p) => NodeArg(p),
             EntryLocal(_, p) => NodeLocal(p),
+            EntryPat(_, p) => NodePat(p),
             EntryBlock(_, p) => NodeBlock(p),
             EntryStructCtor(_, p) => NodeStructCtor(p),
             EntryLifetime(_, p) => NodeLifetime(p),
@@ -399,6 +403,7 @@ pub fn span(&self, id: NodeId) -> Span {
             Some(NodeExpr(expr)) => expr.span,
             Some(NodeStmt(stmt)) => stmt.span,
             Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
+            Some(NodePat(pat)) => pat.span,
             Some(NodeBlock(block)) => block.span,
             Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
             _ => fail!("node_span: could not find span for id {}", id),
@@ -513,7 +518,9 @@ fn fold_pat(&mut self, pat: @Pat) -> @Pat {
                 // Note: this is at least *potentially* a pattern...
                 self.insert(pat.id, EntryLocal(self.parent, pat));
             }
-            _ => {}
+            _ => {
+                self.insert(pat.id, EntryPat(self.parent, pat));
+            }
         }
 
         pat
@@ -704,6 +711,9 @@ fn node_id_to_str(map: &Map, id: NodeId) -> StrBuf {
             (format!("local {} (id={})",
                     pprust::pat_to_str(pat), id)).to_strbuf()
         }
+        Some(NodePat(pat)) => {
+            (format!("pat {} (id={})", pprust::pat_to_str(pat), id)).to_strbuf()
+        }
         Some(NodeBlock(block)) => {
             (format!("block {} (id={})",
                     pprust::block_to_str(block), id)).to_strbuf()
index 84ef7941b2ed7546d65a671b5bd7306e3c04fec2..b7700cf396d48dba6d2e3266ea70bcac685d5e53 100644 (file)
@@ -33,16 +33,16 @@ pub struct CrateId {
 
 impl fmt::Show for CrateId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, "{}", self.path));
+        try!(write!(f, "{}", self.path));
         let version = match self.version {
             None => "0.0",
             Some(ref version) => version.as_slice(),
         };
         if self.path == self.name ||
                 self.path.as_slice().ends_with(format!("/{}", self.name)) {
-            write!(f.buf, "\\#{}", version)
+            write!(f, "\\#{}", version)
         } else {
-            write!(f.buf, "\\#{}:{}", self.name, version)
+            write!(f, "\\#{}:{}", self.name, version)
         }
     }
 }
index 73027013090e72202197501c31d43db5dd7bc6b8..1a07393f9fc80f3fce28a0ee88615ed1af4c1e5e 100644 (file)
@@ -49,6 +49,13 @@ fn is_full_span(&self) -> bool {
     }
 }
 
+#[deriving(Clone)]
+pub enum ColorConfig {
+    Auto,
+    Always,
+    Never
+}
+
 pub trait Emitter {
     fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>,
             msg: &str, lvl: Level);
@@ -176,8 +183,8 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
     }
 }
 
-pub fn default_handler() -> Handler {
-    mk_handler(box EmitterWriter::stderr())
+pub fn default_handler(color_config: ColorConfig) -> Handler {
+    mk_handler(box EmitterWriter::stderr(color_config))
 }
 
 pub fn mk_handler(e: Box<Emitter:Send>) -> Handler {
@@ -252,17 +259,24 @@ pub struct EmitterWriter {
 }
 
 enum Destination {
-    Terminal(term::Terminal<io::stdio::StdWriter>),
+    Terminal(Box<term::Terminal<Box<Writer:Send>>:Send>),
     Raw(Box<Writer:Send>),
 }
 
 impl EmitterWriter {
-    pub fn stderr() -> EmitterWriter {
+    pub fn stderr(color_config: ColorConfig) -> EmitterWriter {
         let stderr = io::stderr();
-        if stderr.get_ref().isatty() {
-            let dst = match term::Terminal::new(stderr.unwrap()) {
-                Ok(t) => Terminal(t),
-                Err(..) => Raw(box io::stderr()),
+
+        let use_color = match color_config {
+            Always => true,
+            Never  => false,
+            Auto   => stderr.get_ref().isatty()
+        };
+
+        if use_color {
+            let dst = match term::stderr() {
+                Some(t) => Terminal(t),
+                None    => Raw(box stderr),
             };
             EmitterWriter { dst: dst }
         } else {
index f4330960acacb3e20d113b47916195231d865681..06b56bbe472a250e804a429ff29596d4371884d9 100644 (file)
@@ -281,7 +281,10 @@ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
                                 ext::fmt::expand_syntax_ext));
     syntax_expanders.insert(intern("format_args"),
                             builtin_normal_expander(
-                                ext::format::expand_args));
+                                ext::format::expand_format_args));
+    syntax_expanders.insert(intern("format_args_method"),
+                            builtin_normal_expander(
+                                ext::format::expand_format_args_method));
     syntax_expanders.insert(intern("env"),
                             builtin_normal_expander(
                                     ext::env::expand_env));
index aeaf53a193904b7e1f5330db0b73b5fd47c0d33a..343100d3a8ef6194b0100edca159c0fdb2628dd6 100644 (file)
@@ -120,23 +120,18 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
     // AST construction!
     // we're basically calling
     //
-    // format_arg!(|__args| ::std::fmt::write(fmt.buf, __args), "<format_string>", exprs...)
+    // format_arg_method!(fmt, write_fmt, "<format_string>", exprs...)
     //
     // but doing it directly via ext::format.
     let formatter = substr.nonself_args[0];
-    let buf = cx.expr_field_access(span, formatter, cx.ident_of("buf"));
-
-    let std_write = vec!(cx.ident_of("std"), cx.ident_of("fmt"), cx.ident_of("write"));
-    let args = cx.ident_of("__args");
-    let write_call = cx.expr_call_global(span, std_write, vec!(buf, cx.expr_ident(span, args)));
-    let format_closure = cx.lambda_expr(span, vec!(args), write_call);
 
+    let meth = cx.ident_of("write_fmt");
     let s = token::intern_and_get_ident(format_string.as_slice());
     let format_string = cx.expr_str(span, s);
 
     // phew, not our responsibility any more!
     format::expand_preparsed_format_args(cx, span,
-                                         format_closure,
+                                         format::MethodCall(formatter, meth),
                                          format_string, exprs, Vec::new(),
                                          HashMap::new())
 }
index c03d174365ed5fb94cd301d8bd99e95c577a596b..01124fdfa54df5d1941cae0e6e15c5a0fa40d426 100644 (file)
@@ -59,6 +59,11 @@ struct Context<'a, 'b> {
     next_arg: uint,
 }
 
+pub enum Invocation {
+    Call(@ast::Expr),
+    MethodCall(@ast::Expr, ast::Ident),
+}
+
 /// Parses the arguments from the given list of tokens, returning None
 /// if there's a parse error so we can continue parsing other format!
 /// expressions.
@@ -67,8 +72,9 @@ struct Context<'a, 'b> {
 ///
 ///     Some((fmtstr, unnamed arguments, ordering of named arguments,
 ///           named arguments))
-fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-    -> (@ast::Expr, Option<(@ast::Expr, Vec<@ast::Expr>, Vec<StrBuf>,
+fn parse_args(ecx: &mut ExtCtxt, sp: Span, allow_method: bool,
+              tts: &[ast::TokenTree])
+    -> (Invocation, Option<(@ast::Expr, Vec<@ast::Expr>, Vec<StrBuf>,
                             HashMap<StrBuf, @ast::Expr>)>) {
     let mut args = Vec::new();
     let mut names = HashMap::<StrBuf, @ast::Expr>::new();
@@ -80,22 +86,31 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                                                 .map(|x| (*x).clone())
                                                 .collect());
     // Parse the leading function expression (maybe a block, maybe a path)
-    let extra = p.parse_expr();
+    let invocation = if allow_method {
+        let e = p.parse_expr();
+        if !p.eat(&token::COMMA) {
+            ecx.span_err(sp, "expected token: `,`");
+            return (Call(e), None);
+        }
+        MethodCall(e, p.parse_ident())
+    } else {
+        Call(p.parse_expr())
+    };
     if !p.eat(&token::COMMA) {
         ecx.span_err(sp, "expected token: `,`");
-        return (extra, None);
+        return (invocation, None);
     }
 
     if p.token == token::EOF {
         ecx.span_err(sp, "requires at least a format string argument");
-        return (extra, None);
+        return (invocation, None);
     }
     let fmtstr = p.parse_expr();
     let mut named = false;
     while p.token != token::EOF {
         if !p.eat(&token::COMMA) {
             ecx.span_err(sp, "expected token: `,`");
-            return (extra, None);
+            return (invocation, None);
         }
         if p.token == token::EOF { break } // accept trailing commas
         if named || (token::is_ident(&p.token) &&
@@ -110,13 +125,13 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                     ecx.span_err(p.span,
                                  "expected ident, positional arguments \
                                  cannot follow named arguments");
-                    return (extra, None);
+                    return (invocation, None);
                 }
                 _ => {
                     ecx.span_err(p.span,
                                  format!("expected ident for named argument, but found `{}`",
                                          p.this_token_to_str()));
-                    return (extra, None);
+                    return (invocation, None);
                 }
             };
             let interned_name = token::get_ident(ident);
@@ -137,7 +152,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
             args.push(p.parse_expr());
         }
     }
-    return (extra, Some((fmtstr, args, order, names)));
+    return (invocation, Some((fmtstr, args, order, names)));
 }
 
 impl<'a, 'b> Context<'a, 'b> {
@@ -595,7 +610,7 @@ fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
 
     /// Actually builds the expression which the iformat! block will be expanded
     /// to
-    fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
+    fn to_expr(&self, invocation: Invocation) -> @ast::Expr {
         let mut lets = Vec::new();
         let mut locals = Vec::new();
         let mut names = Vec::from_fn(self.name_positions.len(), |_| None);
@@ -699,8 +714,16 @@ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
         let resname = self.ecx.ident_of("__args");
         lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
         let res = self.ecx.expr_ident(self.fmtsp, resname);
-        let result = self.ecx.expr_call(extra.span, extra, vec!(
-                            self.ecx.expr_addr_of(extra.span, res)));
+        let result = match invocation {
+            Call(e) => {
+                self.ecx.expr_call(e.span, e,
+                                   vec!(self.ecx.expr_addr_of(e.span, res)))
+            }
+            MethodCall(e, m) => {
+                self.ecx.expr_method_call(e.span, e, m,
+                                          vec!(self.ecx.expr_addr_of(e.span, res)))
+            }
+        };
         let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
                                                       Some(result)));
 
@@ -794,13 +817,25 @@ fn format_arg(&self, sp: Span, argno: Position, arg: @ast::Expr)
     }
 }
 
-pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
-                   tts: &[ast::TokenTree]) -> Box<base::MacResult> {
+pub fn expand_format_args(ecx: &mut ExtCtxt, sp: Span,
+                          tts: &[ast::TokenTree]) -> Box<base::MacResult> {
+
+    match parse_args(ecx, sp, false, tts) {
+        (invocation, Some((efmt, args, order, names))) => {
+            MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt,
+                                                      args, order, names))
+        }
+        (_, None) => MacExpr::new(ecx.expr_uint(sp, 2))
+    }
+}
+
+pub fn expand_format_args_method(ecx: &mut ExtCtxt, sp: Span,
+                                 tts: &[ast::TokenTree]) -> Box<base::MacResult> {
 
-    match parse_args(ecx, sp, tts) {
-        (extra, Some((efmt, args, order, names))) => {
-            MacExpr::new(expand_preparsed_format_args(ecx, sp, extra, efmt, args,
-                                                order, names))
+    match parse_args(ecx, sp, true, tts) {
+        (invocation, Some((efmt, args, order, names))) => {
+            MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt,
+                                                      args, order, names))
         }
         (_, None) => MacExpr::new(ecx.expr_uint(sp, 2))
     }
@@ -810,7 +845,7 @@ pub fn expand_args(ecx: &mut ExtCtxt, sp: Span,
 /// name=names...)` and construct the appropriate formatting
 /// expression.
 pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
-                                    extra: @ast::Expr,
+                                    invocation: Invocation,
                                     efmt: @ast::Expr, args: Vec<@ast::Expr>,
                                     name_ordering: Vec<StrBuf>,
                                     names: HashMap<StrBuf, @ast::Expr>) -> @ast::Expr {
@@ -851,7 +886,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
     }
     match parser.errors.shift() {
         Some(error) => {
-            cx.ecx.span_err(efmt.span, "invalid format string: " + error);
+            cx.ecx.span_err(efmt.span,
+                            format_strbuf!("invalid format string: {}",
+                                           error).as_slice());
             return DummyResult::raw_expr(sp);
         }
         None => {}
@@ -869,5 +906,5 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         }
     }
 
-    cx.to_expr(extra)
+    cx.to_expr(invocation)
 }
index 28f235a3da0398fff283040cb16964ec108d0908..d8a9f69e29342fc47895cf0ba16408bbd95fd2ca 100644 (file)
@@ -13,7 +13,7 @@
 
 use ast;
 use codemap::{Span, CodeMap, FileMap};
-use diagnostic::{SpanHandler, mk_span_handler, default_handler};
+use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto};
 use parse::attr::ParserAttr;
 use parse::parser::Parser;
 
@@ -41,7 +41,7 @@ pub struct ParseSess {
 
 pub fn new_parse_sess() -> ParseSess {
     ParseSess {
-        span_diagnostic: mk_span_handler(default_handler(), CodeMap::new()),
+        span_diagnostic: mk_span_handler(default_handler(Auto), CodeMap::new()),
         included_mod_stack: RefCell::new(Vec::new()),
     }
 }
index 68ce8cb2bc123104c9435fa7c103e170d7460c9b..8758f109042f049b57bd885695604427d27bb1af 100644 (file)
@@ -594,7 +594,7 @@ fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
 
 impl fmt::Show for InternedString {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.string.as_slice())
+        write!(f, "{}", self.string.as_slice())
     }
 }
 
@@ -606,7 +606,8 @@ fn equiv(&self, other: & &'a str) -> bool {
 
 impl<D:Decoder<E>, E> Decodable<D, E> for InternedString {
     fn decode(d: &mut D) -> Result<InternedString, E> {
-        Ok(get_name(get_ident_interner().intern(try!(d.read_str()))))
+        Ok(get_name(get_ident_interner().intern(
+                    try!(d.read_str()).as_slice())))
     }
 }
 
index 2d1b938ec3781733a3a84756fe3a2618529f8407..5f094d851fb06076db894b57af9f0de922fe79b8 100644 (file)
@@ -8,7 +8,32 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Simple ANSI color library
+//! Terminal formatting library.
+//!
+//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
+//! Termina][ansi] to provide color printing, among other things. There are two implementations,
+//! the `TerminfoTerminal`, which uses control characters from a
+//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
+//! API][win].
+//!
+//! ## Example
+//!
+//! ```no_run
+//! extern crate term;
+//!
+//! fn main() {
+//!     let mut t = term::stdout().unwrap();
+//!     t.fg(term::color::GREEN).unwrap();
+//!     println!("hello, ");
+//!     t.fg(term::color::RED).unwrap();
+//!     println!("world!");
+//!     t.reset().unwrap();
+//! }
+//! ```
+//!
+//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
+//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
+//! [ti]: https://en.wikipedia.org/wiki/Terminfo
 
 #![crate_id = "term#0.11.0-pre"]
 #![comment = "Simple ANSI color library"]
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://static.rust-lang.org/doc/master")]
 
-#![feature(macro_rules)]
+#![feature(macro_rules, phase)]
 
 #![deny(missing_doc)]
 
+#[phase(syntax, link)] extern crate log;
 extern crate collections;
 
-use std::io;
-use std::os;
-use terminfo::TermInfo;
-use terminfo::searcher::open;
-use terminfo::parser::compiled::{parse, msys_terminfo};
-use terminfo::parm::{expand, Number, Variables};
+pub use terminfo::TerminfoTerminal;
+#[cfg(windows)]
+pub use win::WinConsole;
+
+use std::io::IoResult;
 
 pub mod terminfo;
 
-// FIXME (#2807): Windows support.
+#[cfg(windows)]
+mod win;
+
+#[cfg(not(windows))]
+/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
+/// opened.
+pub fn stdout() -> Option<Box<Terminal<Box<Writer:Send>>:Send>> {
+    let ti: Option<TerminfoTerminal<Box<Writer:Send>>>
+        = Terminal::new(box std::io::stdout() as Box<Writer:Send>);
+    ti.map(|t| box t as Box<Terminal<Box<Writer:Send>:Send>:Send>)
+}
+
+#[cfg(windows)]
+/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
+/// opened.
+pub fn stdout() -> Option<Box<Terminal<Box<Writer:Send>:Send>:Send>> {
+    let ti: Option<TerminfoTerminal<Box<Writer:Send>>>
+        = Terminal::new(box std::io::stdout() as Box<Writer:Send>);
+
+    match ti {
+        Some(t) => Some(box t as Box<Terminal<Box<Writer:Send>:Send>:Send>),
+        None => {
+            let wc: Option<WinConsole<Box<Writer:Send>>>
+                = Terminal::new(box std::io::stdout() as Box<Writer:Send>);
+            wc.map(|w| box w as Box<Terminal<Box<Writer:Send>:Send>:Send>)
+        }
+    }
+}
+
+#[cfg(not(windows))]
+/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
+/// opened.
+pub fn stderr() -> Option<Box<Terminal<Box<Writer:Send>:Send>:Send>:Send> {
+    let ti: Option<TerminfoTerminal<Box<Writer:Send>>>
+        = Terminal::new(box std::io::stderr() as Box<Writer:Send>);
+    ti.map(|t| box t as Box<Terminal<Box<Writer:Send>:Send>:Send>)
+}
+
+#[cfg(windows)]
+/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
+/// opened.
+pub fn stderr() -> Option<Box<Terminal<Box<Writer:Send>:Send>:Send>> {
+    let ti: Option<TerminfoTerminal<Box<Writer:Send>>>
+        = Terminal::new(box std::io::stderr() as Box<Writer:Send>);
+
+    match ti {
+        Some(t) => Some(box t as Box<Terminal<Box<Writer:Send>:Send>:Send>),
+        None => {
+            let wc: Option<WinConsole<Box<Writer:Send>>>
+                = Terminal::new(box std::io::stderr() as Box<Writer:Send>);
+            wc.map(|w| box w as Box<Terminal<Box<Writer:Send>:Send>:Send>)
+        }
+    }
+}
+
 
 /// Terminal color definitions
 pub mod color {
@@ -91,72 +170,13 @@ pub enum Attr {
     }
 }
 
-fn cap_for_attr(attr: attr::Attr) -> &'static str {
-    match attr {
-        attr::Bold               => "bold",
-        attr::Dim                => "dim",
-        attr::Italic(true)       => "sitm",
-        attr::Italic(false)      => "ritm",
-        attr::Underline(true)    => "smul",
-        attr::Underline(false)   => "rmul",
-        attr::Blink              => "blink",
-        attr::Standout(true)     => "smso",
-        attr::Standout(false)    => "rmso",
-        attr::Reverse            => "rev",
-        attr::Secure             => "invis",
-        attr::ForegroundColor(_) => "setaf",
-        attr::BackgroundColor(_) => "setab"
-    }
-}
-
-/// A Terminal that knows how many colors it supports, with a reference to its
-/// parsed TermInfo database record.
-pub struct Terminal<T> {
-    num_colors: u16,
-    out: T,
-    ti: Box<TermInfo>,
-}
-
-impl<T: Writer> Terminal<T> {
-    /// Returns a wrapped output stream (`Terminal<T>`) as a `Result`.
-    ///
-    /// Returns `Err()` if the TERM environment variable is undefined.
-    /// TERM should be set to something like `xterm-color` or `screen-256color`.
-    ///
-    /// Returns `Err()` on failure to open the terminfo database correctly.
-    /// Also, in the event that the individual terminfo database entry can not
-    /// be parsed.
-    pub fn new(out: T) -> Result<Terminal<T>, StrBuf> {
-        let term = match os::getenv("TERM") {
-            Some(t) => t,
-            None => {
-                return Err("TERM environment variable undefined".to_strbuf())
-            }
-        };
-
-        let mut file = match open(term) {
-            Ok(file) => file,
-            Err(err) => {
-                if "cygwin" == term { // msys terminal
-                    return Ok(Terminal {
-                        out: out,
-                        ti: msys_terminfo(),
-                        num_colors: 8
-                    });
-                }
-                return Err(err);
-            }
-        };
+/// A terminal with similar capabilities to an ANSI Terminal
+/// (foreground/background colors etc).
+pub trait Terminal<T: Writer>: Writer {
+    /// Returns `None` whenever the terminal cannot be created for some
+    /// reason.
+    fn new(out: T) -> Option<Self>;
 
-        let inf = try!(parse(&mut file, false));
-
-        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
-                 && inf.strings.find_equiv(&("setab")).is_some() {
-                     inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n)
-                 } else { 0 };
-
-        return Ok(Terminal {out: out, ti: inf, num_colors: nc});
-    }
     /// Sets the foreground color to the given color.
     ///
     /// If the color is a bright color, but the terminal only supports 8 colors,
@@ -164,22 +184,8 @@ pub fn new(out: T) -> Result<Terminal<T>, StrBuf> {
     ///
     /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
     /// if there was an I/O error.
-    pub fn fg(&mut self, color: color::Color) -> io::IoResult<bool> {
-        let color = self.dim_if_necessary(color);
-        if self.num_colors > color {
-            let s = expand(self.ti
-                               .strings
-                               .find_equiv(&("setaf"))
-                               .unwrap()
-                               .as_slice(),
-                           [Number(color as int)], &mut Variables::new());
-            if s.is_ok() {
-                try!(self.out.write(s.unwrap().as_slice()));
-                return Ok(true)
-            }
-        }
-        Ok(false)
-    }
+    fn fg(&mut self, color: color::Color) -> IoResult<bool>;
+
     /// Sets the background color to the given color.
     ///
     /// If the color is a bright color, but the terminal only supports 8 colors,
@@ -187,104 +193,26 @@ pub fn fg(&mut self, color: color::Color) -> io::IoResult<bool> {
     ///
     /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
     /// if there was an I/O error.
-    pub fn bg(&mut self, color: color::Color) -> io::IoResult<bool> {
-        let color = self.dim_if_necessary(color);
-        if self.num_colors > color {
-            let s = expand(self.ti
-                               .strings
-                               .find_equiv(&("setab"))
-                               .unwrap()
-                               .as_slice(),
-                           [Number(color as int)], &mut Variables::new());
-            if s.is_ok() {
-                try!(self.out.write(s.unwrap().as_slice()));
-                return Ok(true)
-            }
-        }
-        Ok(false)
-    }
+    fn bg(&mut self, color: color::Color) -> IoResult<bool>;
 
-    /// Sets the given terminal attribute, if supported.
-    /// Returns `Ok(true)` if the attribute was supported, `Ok(false)` otherwise,
-    /// and `Err(e)` if there was an I/O error.
-    pub fn attr(&mut self, attr: attr::Attr) -> io::IoResult<bool> {
-        match attr {
-            attr::ForegroundColor(c) => self.fg(c),
-            attr::BackgroundColor(c) => self.bg(c),
-            _ => {
-                let cap = cap_for_attr(attr);
-                let parm = self.ti.strings.find_equiv(&cap);
-                if parm.is_some() {
-                    let s = expand(parm.unwrap().as_slice(),
-                                   [],
-                                   &mut Variables::new());
-                    if s.is_ok() {
-                        try!(self.out.write(s.unwrap().as_slice()));
-                        return Ok(true)
-                    }
-                }
-                Ok(false)
-            }
-        }
-    }
+    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
+    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
+    /// there was an I/O error.
+    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool>;
 
     /// Returns whether the given terminal attribute is supported.
-    pub fn supports_attr(&self, attr: attr::Attr) -> bool {
-        match attr {
-            attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
-                self.num_colors > 0
-            }
-            _ => {
-                let cap = cap_for_attr(attr);
-                self.ti.strings.find_equiv(&cap).is_some()
-            }
-        }
-    }
+    fn supports_attr(&self, attr: attr::Attr) -> bool;
 
     /// Resets all terminal attributes and color to the default.
     /// Returns `Ok()`.
-    pub fn reset(&mut self) -> io::IoResult<()> {
-        let mut cap = self.ti.strings.find_equiv(&("sgr0"));
-        if cap.is_none() {
-            // are there any terminals that have color/attrs and not sgr0?
-            // Try falling back to sgr, then op
-            cap = self.ti.strings.find_equiv(&("sgr"));
-            if cap.is_none() {
-                cap = self.ti.strings.find_equiv(&("op"));
-            }
-        }
-        let s = cap.map_or(Err("can't find terminfo capability \
-                                `sgr0`".to_strbuf()), |op| {
-            expand(op.as_slice(), [], &mut Variables::new())
-        });
-        if s.is_ok() {
-            return self.out.write(s.unwrap().as_slice())
-        }
-        Ok(())
-    }
-
-    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
-        if color >= self.num_colors && color >= 8 && color < 16 {
-            color-8
-        } else { color }
-    }
+    fn reset(&mut self) -> IoResult<()>;
 
-    /// Returns the contained stream
-    pub fn unwrap(self) -> T { self.out }
+    /// Returns the contained stream, destroying the `Terminal`
+    fn unwrap(self) -> T;
 
     /// Gets an immutable reference to the stream inside
-    pub fn get_ref<'a>(&'a self) -> &'a T { &self.out }
+    fn get_ref<'a>(&'a self) -> &'a T;
 
     /// Gets a mutable reference to the stream inside
-    pub fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
-}
-
-impl<T: Writer> Writer for Terminal<T> {
-    fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {
-        self.out.write(buf)
-    }
-
-    fn flush(&mut self) -> io::IoResult<()> {
-        self.out.flush()
-    }
+    fn get_mut<'a>(&'a mut self) -> &'a mut T;
 }
index 46dd397853157cb889a45dc097e2fc679713b561..36e5c1cf763a6459567402a26135b4d948a0d360 100644 (file)
 //! Terminfo database interface.
 
 use collections::HashMap;
+use std::io::IoResult;
+use std::os;
+
+use attr;
+use color;
+use Terminal;
+use self::searcher::open;
+use self::parser::compiled::{parse, msys_terminfo};
+use self::parm::{expand, Number, Variables};
+
 
 /// A parsed terminfo database entry.
+#[deriving(Show)]
 pub struct TermInfo {
     /// Names for the terminal
     pub names: Vec<StrBuf> ,
@@ -32,3 +43,179 @@ pub mod parser {
     pub mod compiled;
 }
 pub mod parm;
+
+
+fn cap_for_attr(attr: attr::Attr) -> &'static str {
+    match attr {
+        attr::Bold               => "bold",
+        attr::Dim                => "dim",
+        attr::Italic(true)       => "sitm",
+        attr::Italic(false)      => "ritm",
+        attr::Underline(true)    => "smul",
+        attr::Underline(false)   => "rmul",
+        attr::Blink              => "blink",
+        attr::Standout(true)     => "smso",
+        attr::Standout(false)    => "rmso",
+        attr::Reverse            => "rev",
+        attr::Secure             => "invis",
+        attr::ForegroundColor(_) => "setaf",
+        attr::BackgroundColor(_) => "setab"
+    }
+}
+
+/// A Terminal that knows how many colors it supports, with a reference to its
+/// parsed Terminfo database record.
+pub struct TerminfoTerminal<T> {
+    num_colors: u16,
+    out: T,
+    ti: Box<TermInfo>
+}
+
+impl<T: Writer> Terminal<T> for TerminfoTerminal<T> {
+    fn new(out: T) -> Option<TerminfoTerminal<T>> {
+        let term = match os::getenv("TERM") {
+            Some(t) => t,
+            None => {
+                debug!("TERM environment variable not defined");
+                return None;
+            }
+        };
+
+        let entry = open(term);
+        if entry.is_err() {
+            if os::getenv("MSYSCON").map_or(false, |s| "mintty.exe" == s) {
+                // msys terminal
+                return Some(TerminfoTerminal {out: out, ti: msys_terminfo(), num_colors: 8});
+            }
+            debug!("error finding terminfo entry: {}", entry.err().unwrap());
+            return None;
+        }
+
+        let mut file = entry.unwrap();
+        let ti = parse(&mut file, false);
+        if ti.is_err() {
+            debug!("error parsing terminfo entry: {}", ti.unwrap_err());
+            return None;
+        }
+
+        let inf = ti.unwrap();
+        let nc = if inf.strings.find_equiv(&("setaf")).is_some()
+                 && inf.strings.find_equiv(&("setab")).is_some() {
+                     inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n)
+                 } else { 0 };
+
+        return Some(TerminfoTerminal {out: out, ti: inf, num_colors: nc});
+    }
+
+    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
+        let color = self.dim_if_necessary(color);
+        if self.num_colors > color {
+            let s = expand(self.ti
+                               .strings
+                               .find_equiv(&("setaf"))
+                               .unwrap()
+                               .as_slice(),
+                           [Number(color as int)], &mut Variables::new());
+            if s.is_ok() {
+                try!(self.out.write(s.unwrap().as_slice()));
+                return Ok(true)
+            }
+        }
+        Ok(false)
+    }
+
+    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
+        let color = self.dim_if_necessary(color);
+        if self.num_colors > color {
+            let s = expand(self.ti
+                               .strings
+                               .find_equiv(&("setab"))
+                               .unwrap()
+                               .as_slice(),
+                           [Number(color as int)], &mut Variables::new());
+            if s.is_ok() {
+                try!(self.out.write(s.unwrap().as_slice()));
+                return Ok(true)
+            }
+        }
+        Ok(false)
+    }
+
+    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
+        match attr {
+            attr::ForegroundColor(c) => self.fg(c),
+            attr::BackgroundColor(c) => self.bg(c),
+            _ => {
+                let cap = cap_for_attr(attr);
+                let parm = self.ti.strings.find_equiv(&cap);
+                if parm.is_some() {
+                    let s = expand(parm.unwrap().as_slice(),
+                                   [],
+                                   &mut Variables::new());
+                    if s.is_ok() {
+                        try!(self.out.write(s.unwrap().as_slice()));
+                        return Ok(true)
+                    }
+                }
+                Ok(false)
+            }
+        }
+    }
+
+    fn supports_attr(&self, attr: attr::Attr) -> bool {
+        match attr {
+            attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
+                self.num_colors > 0
+            }
+            _ => {
+                let cap = cap_for_attr(attr);
+                self.ti.strings.find_equiv(&cap).is_some()
+            }
+        }
+    }
+
+    fn reset(&mut self) -> IoResult<()> {
+        let mut cap = self.ti.strings.find_equiv(&("sgr0"));
+        if cap.is_none() {
+            // are there any terminals that have color/attrs and not sgr0?
+            // Try falling back to sgr, then op
+            cap = self.ti.strings.find_equiv(&("sgr"));
+            if cap.is_none() {
+                cap = self.ti.strings.find_equiv(&("op"));
+            }
+        }
+        let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_strbuf()), |op| {
+            expand(op.as_slice(), [], &mut Variables::new())
+        });
+        if s.is_ok() {
+            return self.out.write(s.unwrap().as_slice())
+        }
+        Ok(())
+    }
+
+    fn unwrap(self) -> T { self.out }
+
+    fn get_ref<'a>(&'a self) -> &'a T { &self.out }
+
+    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
+}
+
+impl<T: Writer> TerminfoTerminal<T> {
+    fn dim_if_necessary(&self, color: color::Color) -> color::Color {
+        if color >= self.num_colors && color >= 8 && color < 16 {
+            color-8
+        } else { color }
+    }
+}
+
+
+impl<T: Writer> Writer for TerminfoTerminal<T> {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.out.write(buf)
+    }
+
+    fn flush(&mut self) -> IoResult<()> {
+        self.out.flush()
+    }
+}
+
diff --git a/src/libterm/win.rs b/src/libterm/win.rs
new file mode 100644 (file)
index 0000000..837ddf5
--- /dev/null
@@ -0,0 +1,148 @@
+// Copyright 2013-2014 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.
+
+//! Windows console handling
+
+// FIXME (#13400): this is only a tiny fraction of the win32 console api
+
+extern crate libc;
+
+use std::io::IoResult;
+
+use attr;
+use color;
+use Terminal;
+
+/// A Terminal implementation which uses the Win32 Console API.
+pub struct WinConsole<T> {
+    buf: T,
+    foreground: color::Color,
+    background: color::Color,
+}
+
+#[link(name = "kernel32")]
+extern "system" {
+    fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
+    fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
+}
+
+fn color_to_bits(color: color::Color) -> u16 {
+    // magic numbers from mingw-w64's wincon.h
+
+    let bits = match color % 8 {
+        color::BLACK   => 0,
+        color::BLUE    => 0x1,
+        color::GREEN   => 0x2,
+        color::RED     => 0x4,
+        color::YELLOW  => 0x2 | 0x4,
+        color::MAGENTA => 0x1 | 0x4,
+        color::CYAN    => 0x1 | 0x2,
+        color::WHITE   => 0x1 | 0x2 | 0x4,
+        _ => unreachable!()
+    };
+
+    if color >= 8 {
+        bits | 0x8
+    } else {
+        bits
+    }
+}
+
+impl<T: Writer> WinConsole<T> {
+    fn apply(&mut self) {
+        let _unused = self.buf.flush();
+        let mut accum: libc::WORD = 0;
+        accum |= color_to_bits(self.foreground);
+        accum |= color_to_bits(self.background) << 4;
+
+        unsafe {
+            // Magic -11 means stdout, from
+            // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
+            //
+            // You may be wondering, "but what about stderr?", and the answer
+            // to that is that setting terminal attributes on the stdout
+            // handle also sets them for stderr, since they go to the same
+            // terminal! Admittedly, this is fragile, since stderr could be
+            // redirected to a different console. This is good enough for
+            // rustc though. See #13400.
+            let out = GetStdHandle(-11);
+            SetConsoleTextAttribute(out, accum);
+        }
+    }
+}
+
+impl<T: Writer> Writer for WinConsole<T> {
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.buf.write(buf)
+    }
+
+    fn flush(&mut self) -> IoResult<()> {
+        self.buf.flush()
+    }
+}
+
+impl<T: Writer> Terminal<T> for WinConsole<T> {
+    fn new(out: T) -> Option<WinConsole<T>> {
+        Some(WinConsole { buf: out, foreground: color::WHITE, background: color::BLACK })
+    }
+
+    fn fg(&mut self, color: color::Color) -> IoResult<bool> {
+        self.foreground = color;
+        self.apply();
+
+        Ok(true)
+    }
+
+    fn bg(&mut self, color: color::Color) -> IoResult<bool> {
+        self.background = color;
+        self.apply();
+
+        Ok(true)
+    }
+
+    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
+        match attr {
+            attr::ForegroundColor(f) => {
+                self.foreground = f;
+                self.apply();
+                Ok(true)
+            },
+            attr::BackgroundColor(b) => {
+                self.background = b;
+                self.apply();
+                Ok(true)
+            },
+            _ => Ok(false)
+        }
+    }
+
+    fn supports_attr(&self, attr: attr::Attr) -> bool {
+        // it claims support for underscore and reverse video, but I can't get
+        // it to do anything -cmr
+        match attr {
+            attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
+            _ => false
+        }
+    }
+
+    fn reset(&mut self) -> IoResult<()> {
+        self.foreground = color::WHITE;
+        self.background = color::BLACK;
+        self.apply();
+
+        Ok(())
+    }
+
+    fn unwrap(self) -> T { self.buf }
+
+    fn get_ref<'a>(&'a self) -> &'a T { &self.buf }
+
+    fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
+}
index ba8b8f776d97cbdc8bd35346953523683dc0c4ea..4681c02d78e13ea12b33dba100363fddac56830c 100644 (file)
@@ -37,6 +37,7 @@
 
 extern crate collections;
 extern crate getopts;
+extern crate regex;
 extern crate serialize;
 extern crate term;
 extern crate time;
@@ -45,6 +46,7 @@
 use stats::Stats;
 use time::precise_time_ns;
 use getopts::{OptGroup, optflag, optopt};
+use regex::Regex;
 use serialize::{json, Decodable};
 use serialize::json::{Json, ToJson};
 use term::Terminal;
@@ -53,6 +55,7 @@
 use std::cmp;
 use std::f64;
 use std::fmt;
+use std::fmt::Show;
 use std::from_str::FromStr;
 use std::io::stdio::StdWriter;
 use std::io::{File, ChanReader, ChanWriter};
@@ -85,14 +88,19 @@ pub enum TestName {
     StaticTestName(&'static str),
     DynTestName(StrBuf)
 }
-impl fmt::Show for TestName {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+impl TestName {
+    fn as_slice<'a>(&'a self) -> &'a str {
         match *self {
-            StaticTestName(s) => f.buf.write_str(s),
-            DynTestName(ref s) => f.buf.write_str(s.as_slice()),
+            StaticTestName(s) => s,
+            DynTestName(ref s) => s.as_slice()
         }
     }
 }
+impl Show for TestName {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.as_slice().fmt(f)
+    }
+}
 
 #[deriving(Clone)]
 enum NamePadding { PadNone, PadOnLeft, PadOnRight }
@@ -100,7 +108,7 @@ enum NamePadding { PadNone, PadOnLeft, PadOnRight }
 impl TestDesc {
     fn padded_name(&self, column_count: uint, align: NamePadding) -> StrBuf {
         use std::num::Saturating;
-        let mut name = StrBuf::from_str(self.name.to_str());
+        let mut name = StrBuf::from_str(self.name.as_slice());
         let fill = column_count.saturating_sub(name.len());
         let mut pad = StrBuf::from_owned_str(" ".repeat(fill));
         match align {
@@ -257,7 +265,7 @@ pub fn test_main_static_x(args: &[~str], tests: &[TestDescAndFn]) {
 }
 
 pub struct TestOpts {
-    pub filter: Option<StrBuf>,
+    pub filter: Option<Regex>,
     pub run_ignored: bool,
     pub run_tests: bool,
     pub run_benchmarks: bool,
@@ -312,14 +320,12 @@ fn optgroups() -> Vec<getopts::OptGroup> {
                                          task, allow printing directly"))
 }
 
-fn usage(binary: &str, helpstr: &str) {
+fn usage(binary: &str) {
     let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
-    println!("{}", getopts::usage(message, optgroups().as_slice()));
-    println!("");
-    if helpstr == "help" {
-        println!("{}", "\
-The FILTER is matched against the name of all tests to run, and if any tests
-have a substring match, only those tests are run.
+    println!(r"{usage}
+
+The FILTER regex is tested against the name of all tests to run, and
+only those tests that match are run.
 
 By default, all tests are run in parallel. This can be altered with the
 RUST_TEST_TASKS environment variable when running tests (set it to 1).
@@ -330,48 +336,40 @@ fn usage(binary: &str, helpstr: &str) {
 
 Test Attributes:
 
-    #[test]        - Indicates a function is a test to be run. This function
+    \#[test]        - Indicates a function is a test to be run. This function
                      takes no arguments.
-    #[bench]       - Indicates a function is a benchmark to be run. This
+    \#[bench]       - Indicates a function is a benchmark to be run. This
                      function takes one argument (test::Bencher).
-    #[should_fail] - This function (also labeled with #[test]) will only pass if
+    \#[should_fail] - This function (also labeled with \#[test]) will only pass if
                      the code causes a failure (an assertion failure or fail!)
-    #[ignore]      - When applied to a function which is already attributed as a
+    \#[ignore]      - When applied to a function which is already attributed as a
                      test, then the test runner will ignore these tests during
                      normal test runs. Running with --ignored will run these
-                     tests. This may also be written as #[ignore(cfg(...))] to
-                     ignore the test on certain configurations.");
-    }
+                     tests. This may also be written as \#[ignore(cfg(...))] to
+                     ignore the test on certain configurations.",
+             usage = getopts::usage(message, optgroups().as_slice()));
 }
 
 // Parses command line arguments into test options
 pub fn parse_opts(args: &[StrBuf]) -> Option<OptRes> {
     let args_ = args.tail();
     let matches =
-        match getopts::getopts(args_.iter()
-                                    .map(|x| x.to_owned())
-                                    .collect::<Vec<_>>()
-                                    .as_slice(),
-                               optgroups().as_slice()) {
+        match getopts::getopts(args_.as_slice(), optgroups().as_slice()) {
           Ok(m) => m,
           Err(f) => return Some(Err(f.to_err_msg().to_strbuf()))
         };
 
-    if matches.opt_present("h") {
-        usage(args[0].as_slice(), "h");
-        return None;
-    }
-    if matches.opt_present("help") {
-        usage(args[0].as_slice(), "help");
-        return None;
-    }
+    if matches.opt_present("h") { usage(args[0].as_slice()); return None; }
 
-    let filter =
-        if matches.free.len() > 0 {
-            Some((*matches.free.get(0)).to_strbuf())
-        } else {
-            None
-        };
+    let filter = if matches.free.len() > 0 {
+        let s = matches.free.get(0).as_slice();
+        match Regex::new(s) {
+            Ok(re) => Some(re),
+            Err(e) => return Some(Err(format_strbuf!("could not parse /{}/: {}", s, e)))
+        }
+    } else {
+        None
+    };
 
     let run_ignored = matches.opt_present("ignored");
 
@@ -386,7 +384,8 @@ pub fn parse_opts(args: &[StrBuf]) -> Option<OptRes> {
     let ratchet_metrics = ratchet_metrics.map(|s| Path::new(s));
 
     let ratchet_noise_percent = matches.opt_str("ratchet-noise-percent");
-    let ratchet_noise_percent = ratchet_noise_percent.map(|s| from_str::<f64>(s).unwrap());
+    let ratchet_noise_percent =
+        ratchet_noise_percent.map(|s| from_str::<f64>(s.as_slice()).unwrap());
 
     let save_metrics = matches.opt_str("save-metrics");
     let save_metrics = save_metrics.map(|s| Path::new(s));
@@ -445,7 +444,7 @@ pub enum TestResult {
 }
 
 enum OutputLocation<T> {
-    Pretty(term::Terminal<T>),
+    Pretty(Box<term::Terminal<Box<Writer:Send>>:Send>),
     Raw(T),
 }
 
@@ -470,10 +469,11 @@ pub fn new(opts: &TestOpts,
             Some(ref path) => Some(try!(File::create(path))),
             None => None
         };
-        let out = match term::Terminal::new(io::stdio::stdout_raw()) {
-            Err(_) => Raw(io::stdio::stdout_raw()),
-            Ok(t) => Pretty(t)
+        let out = match term::stdout() {
+            None => Raw(io::stdio::stdout_raw()),
+            Some(t) => Pretty(t)
         };
+
         Ok(ConsoleTestState {
             out: out,
             log_out: log_out,
@@ -590,7 +590,7 @@ pub fn write_log(&mut self, test: &TestDesc,
                         TrIgnored => "ignored".to_strbuf(),
                         TrMetrics(ref mm) => fmt_metrics(mm),
                         TrBench(ref bs) => fmt_bench_samples(bs)
-                    }, test.name.to_str());
+                    }, test.name.as_slice());
                 o.write(s.as_bytes())
             }
         }
@@ -604,7 +604,7 @@ pub fn write_failures(&mut self) -> io::IoResult<()> {
             failures.push(f.name.to_str());
             if stdout.len() > 0 {
                 fail_out.push_str(format!("---- {} stdout ----\n\t",
-                                  f.name.to_str()));
+                                  f.name.as_slice()));
                 let output = str::from_utf8_lossy(stdout.as_slice());
                 fail_out.push_str(output.as_slice().replace("\n", "\n\t"));
                 fail_out.push_str("\n");
@@ -618,7 +618,7 @@ pub fn write_failures(&mut self) -> io::IoResult<()> {
         try!(self.write_plain("\nfailures:\n"));
         failures.as_mut_slice().sort();
         for name in failures.iter() {
-            try!(self.write_plain(format!("    {}\n", name.to_str())));
+            try!(self.write_plain(format!("    {}\n", name.as_slice())));
         }
         Ok(())
     }
@@ -753,7 +753,7 @@ fn callback<T: Writer>(event: &TestEvent,
                     TrOk => st.passed += 1,
                     TrIgnored => st.ignored += 1,
                     TrMetrics(mm) => {
-                        let tname = test.name.to_str();
+                        let tname = test.name.as_slice();
                         let MetricMap(mm) = mm;
                         for (k,v) in mm.iter() {
                             st.metrics
@@ -764,7 +764,7 @@ fn callback<T: Writer>(event: &TestEvent,
                         st.measured += 1
                     }
                     TrBench(bs) => {
-                        st.metrics.insert_metric(test.name.to_str(),
+                        st.metrics.insert_metric(test.name.as_slice(),
                                                  bs.ns_iter_summ.median,
                                                  bs.ns_iter_summ.max - bs.ns_iter_summ.min);
                         st.measured += 1
@@ -782,12 +782,12 @@ fn callback<T: Writer>(event: &TestEvent,
     fn len_if_padded(t: &TestDescAndFn) -> uint {
         match t.testfn.padding() {
             PadNone => 0u,
-            PadOnLeft | PadOnRight => t.desc.name.to_str().len(),
+            PadOnLeft | PadOnRight => t.desc.name.as_slice().len(),
         }
     }
     match tests.iter().max_by(|t|len_if_padded(*t)) {
         Some(t) => {
-            let n = t.desc.name.to_str();
+            let n = t.desc.name.as_slice();
             st.max_name_len = n.len();
         },
         None => {}
@@ -939,26 +939,12 @@ pub fn filter_tests(
     let mut filtered = tests;
 
     // Remove tests that don't match the test filter
-    filtered = if opts.filter.is_none() {
-        filtered
-    } else {
-        let filter_str = match opts.filter {
-          Some(ref f) => (*f).clone(),
-          None => "".to_strbuf()
-        };
-
-        fn filter_fn(test: TestDescAndFn, filter_str: &str) ->
-            Option<TestDescAndFn> {
-            if test.desc.name.to_str().contains(filter_str) {
-                return Some(test);
-            } else {
-                return None;
-            }
+    filtered = match opts.filter {
+        None => filtered,
+        Some(ref re) => {
+            filtered.move_iter()
+                .filter(|test| re.is_match(test.desc.name.as_slice())).collect()
         }
-
-        filtered.move_iter()
-                .filter_map(|x| filter_fn(x, filter_str.as_slice()))
-                .collect()
     };
 
     // Maybe pull out the ignored test and unignore them
@@ -980,7 +966,7 @@ fn filter(test: TestDescAndFn) -> Option<TestDescAndFn> {
     };
 
     // Sort the tests alphabetically
-    filtered.sort_by(|t1, t2| t1.desc.name.to_str().cmp(&t2.desc.name.to_str()));
+    filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(&t2.desc.name.as_slice()));
 
     // Shard the remaining tests, if sharding requested.
     match opts.test_shard {
@@ -1079,8 +1065,8 @@ fn calc_result(desc: &TestDesc, task_succeeded: bool) -> TestResult {
 impl ToJson for Metric {
     fn to_json(&self) -> json::Json {
         let mut map = box TreeMap::new();
-        map.insert("value".to_owned(), json::Number(self.value));
-        map.insert("noise".to_owned(), json::Number(self.noise));
+        map.insert("value".to_strbuf(), json::Number(self.value));
+        map.insert("noise".to_strbuf(), json::Number(self.noise));
         json::Object(map)
     }
 }
@@ -1117,7 +1103,7 @@ pub fn save(&self, p: &Path) -> io::IoResult<()> {
         // FIXME(pcwalton): Yuck.
         let mut new_map = TreeMap::new();
         for (ref key, ref value) in map.iter() {
-            new_map.insert(key.to_owned(), (*value).clone());
+            new_map.insert(key.to_strbuf(), (*value).clone());
         }
 
         new_map.to_json().to_pretty_writer(&mut file)
@@ -1445,12 +1431,12 @@ fn f() { }
 
     #[test]
     fn first_free_arg_should_be_a_filter() {
-        let args = vec!("progname".to_strbuf(), "filter".to_strbuf());
+        let args = vec!("progname".to_strbuf(), "some_regex_filter".to_strbuf());
         let opts = match parse_opts(args.as_slice()) {
             Some(Ok(o)) => o,
             _ => fail!("Malformed arg in first_free_arg_should_be_a_filter")
         };
-        assert!("filter" == opts.filter.clone().unwrap().as_slice());
+        assert!(opts.filter.expect("should've found filter").is_match("some_regex_filter"))
     }
 
     #[test]
@@ -1549,6 +1535,37 @@ fn testfn() { }
         }
     }
 
+    #[test]
+    pub fn filter_tests_regex() {
+        let mut opts = TestOpts::new();
+        opts.filter = Some(::regex::Regex::new("a.*b.+c").unwrap());
+
+        let mut names = ["yes::abXc", "yes::aXXXbXXXXc",
+                         "no::XYZ", "no::abc"];
+        names.sort();
+
+        fn test_fn() {}
+        let tests = names.iter().map(|name| {
+            TestDescAndFn {
+                desc: TestDesc {
+                    name: DynTestName(name.to_strbuf()),
+                    ignore: false,
+                    should_fail: false
+                },
+                testfn: DynTestFn(test_fn)
+            }
+        }).collect();
+        let filtered = filter_tests(&opts, tests);
+
+        let expected: Vec<&str> =
+            names.iter().map(|&s| s).filter(|name| name.starts_with("yes")).collect();
+
+        assert_eq!(filtered.len(), expected.len());
+        for (test, expected_name) in filtered.iter().zip(expected.iter()) {
+            assert_eq!(test.desc.name.as_slice(), *expected_name);
+        }
+    }
+
     #[test]
     pub fn test_metricmap_compare() {
         let mut m1 = MetricMap::new();
index bf40a2d601fcca67d75aaeeead94ffc270b0ef2e..b3c768a519924c05f1cc63a10785374d8c8335c7 100644 (file)
@@ -38,7 +38,7 @@ fn local_sort<T: Float>(v: &mut [T]) {
 }
 
 /// Trait that provides simple descriptive statistics on a univariate set of numeric samples.
-pub trait Stats <T: Float + FromPrimitive>{
+pub trait Stats <T: FloatMath + FromPrimitive>{
 
     /// Sum of the samples.
     ///
@@ -143,7 +143,7 @@ pub struct Summary<T> {
     pub iqr: T,
 }
 
-impl<T: Float + FromPrimitive> Summary<T> {
+impl<T: FloatMath + FromPrimitive> Summary<T> {
 
     /// Construct a new summary of a sample set.
     pub fn new(samples: &[T]) -> Summary<T> {
@@ -164,7 +164,7 @@ pub fn new(samples: &[T]) -> Summary<T> {
     }
 }
 
-impl<'a,T: Float + FromPrimitive> Stats<T> for &'a [T] {
+impl<'a,T: FloatMath + FromPrimitive> Stats<T> for &'a [T] {
 
     // FIXME #11059 handle NaN, inf and overflow
     #[allow(deprecated_owned_vector)]
index 1ffe4d3cbadc456d0c87fd34f5262c359df84cc7..0e67076dc08e3f2e2c2a4dcc66250b05b9ace2f1 100644 (file)
@@ -8,7 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Simple time handling.
+
 #![crate_id = "time#0.11.0-pre"]
+
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 #![license = "MIT/ASL2"]
@@ -21,6 +24,8 @@
 #[cfg(test)] #[phase(syntax, link)] extern crate log;
 extern crate serialize;
 extern crate libc;
+#[cfg(target_os = "macos")]
+extern crate sync;
 
 use std::io::BufReader;
 use std::num;
@@ -156,10 +161,16 @@ fn os_precise_time_ns() -> u64 {
 
     #[cfg(target_os = "macos")]
     fn os_precise_time_ns() -> u64 {
-        let time = unsafe { imp::mach_absolute_time() };
-        let mut info = libc::mach_timebase_info { numer: 0, denom: 0 };
-        unsafe { imp::mach_timebase_info(&mut info); }
-        return time * ((info.numer / info.denom) as u64);
+        static mut TIMEBASE: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0,
+                                                                                   denom: 0 };
+        static mut ONCE: sync::one::Once = sync::one::ONCE_INIT;
+        unsafe {
+            ONCE.doit(|| {
+                imp::mach_timebase_info(&mut TIMEBASE);
+            });
+            let time = imp::mach_absolute_time();
+            time * TIMEBASE.numer as u64 / TIMEBASE.denom as u64
+        }
     }
 
     #[cfg(not(windows), not(target_os = "macos"))]
@@ -189,7 +200,7 @@ pub fn tzset() {
 
 /// Holds a calendar date and time broken down into its components (year, month, day, and so on),
 /// also called a broken-down time value.
-#[deriving(Clone, Eq, Encodable, Decodable, Show)]
+#[deriving(Clone, Eq, Show)]
 pub struct Tm {
     /// Seconds after the minute – [0, 60]
     pub tm_sec: i32,
@@ -1077,11 +1088,13 @@ fn parse_type(ch: char, tm: &Tm) -> StrBuf {
 
 #[cfg(test)]
 mod tests {
+    extern crate test;
     use super::{Timespec, get_time, precise_time_ns, precise_time_s, tzset,
                 at_utc, at, strptime};
 
     use std::f64;
     use std::result::{Err, Ok};
+    use self::test::Bencher;
 
     #[cfg(windows)]
     fn set_time_zone() {
@@ -1517,4 +1530,9 @@ fn run_tests() {
         test_strftime();
         test_timespec_eq_ord();
     }
+
+    #[bench]
+    fn bench_precise_time_ns(b: &mut Bencher) {
+        b.iter(|| precise_time_ns())
+    }
 }
index a2e75e0bf9b1eb0c90a615461bac300c38280f4e..5fc567f06d38d8fbed9fee6d5b4b7275bf6e9d2f 100644 (file)
@@ -427,8 +427,8 @@ fn split_char_first(s: &str, c: char) -> (StrBuf, StrBuf) {
 impl fmt::Show for UserInfo {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.pass {
-            Some(ref pass) => write!(f.buf, "{}:{}@", self.user, *pass),
-            None => write!(f.buf, "{}@", self.user),
+            Some(ref pass) => write!(f, "{}:{}@", self.user, *pass),
+            None => write!(f, "{}@", self.user),
         }
     }
 }
@@ -824,30 +824,30 @@ impl fmt::Show for Url {
      * result in just "http://somehost.com".
      */
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, "{}:", self.scheme));
+        try!(write!(f, "{}:", self.scheme));
 
         if !self.host.is_empty() {
-            try!(write!(f.buf, "//"));
+            try!(write!(f, "//"));
             match self.user {
-                Some(ref user) => try!(write!(f.buf, "{}", *user)),
+                Some(ref user) => try!(write!(f, "{}", *user)),
                 None => {}
             }
             match self.port {
-                Some(ref port) => try!(write!(f.buf, "{}:{}", self.host,
+                Some(ref port) => try!(write!(f, "{}:{}", self.host,
                                                 *port)),
-                None => try!(write!(f.buf, "{}", self.host)),
+                None => try!(write!(f, "{}", self.host)),
             }
         }
 
-        try!(write!(f.buf, "{}", self.path));
+        try!(write!(f, "{}", self.path));
 
         if !self.query.is_empty() {
-            try!(write!(f.buf, "?{}", query_to_str(&self.query)));
+            try!(write!(f, "?{}", query_to_str(&self.query)));
         }
 
         match self.fragment {
             Some(ref fragment) => {
-                write!(f.buf, "\\#{}", encode_component(fragment.as_slice()))
+                write!(f, "\\#{}", encode_component(fragment.as_slice()))
             }
             None => Ok(()),
         }
@@ -856,14 +856,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl fmt::Show for Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(write!(f.buf, "{}", self.path));
+        try!(write!(f, "{}", self.path));
         if !self.query.is_empty() {
-            try!(write!(f.buf, "?{}", self.query))
+            try!(write!(f, "?{}", self.query))
         }
 
         match self.fragment {
             Some(ref fragment) => {
-                write!(f.buf, "\\#{}", encode_component(fragment.as_slice()))
+                write!(f, "\\#{}", encode_component(fragment.as_slice()))
             }
             None => Ok(())
         }
index d75f967a229b1990f43e9e9b1599f0226cf1966c..d2032b9d49281a7436149776718c389cae4e563b 100644 (file)
@@ -154,17 +154,17 @@ impl fmt::Show for ParseError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ErrorInvalidLength(found) =>
-                write!(f.buf, "Invalid length; expecting 32, 36 or 45 chars, \
-                               found {}", found),
+                write!(f, "Invalid length; expecting 32, 36 or 45 chars, \
+                           found {}", found),
             ErrorInvalidCharacter(found, pos) =>
-                write!(f.buf, "Invalid character; found `{}` (0x{:02x}) at \
-                               offset {}", found, found as uint, pos),
+                write!(f, "Invalid character; found `{}` (0x{:02x}) at \
+                           offset {}", found, found as uint, pos),
             ErrorInvalidGroups(found) =>
-                write!(f.buf, "Malformed; wrong number of groups: expected 1 \
-                               or 5, found {}", found),
+                write!(f, "Malformed; wrong number of groups: expected 1 \
+                           or 5, found {}", found),
             ErrorInvalidGroupLength(group, found, expecting) =>
-                write!(f.buf, "Malformed; length of group {} was {}, \
-                               expecting {}", group, found, expecting),
+                write!(f, "Malformed; length of group {} was {}, \
+                           expecting {}", group, found, expecting),
         }
     }
 }
@@ -474,7 +474,7 @@ fn from_str(us: &str) -> Option<Uuid> {
 /// Convert the UUID to a hexadecimal-based string representation
 impl fmt::Show for Uuid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.to_simple_str())
+        write!(f, "{}", self.to_simple_str())
     }
 }
 
@@ -500,7 +500,7 @@ fn encode(&self, e: &mut T) -> Result<(), E> {
 impl<T: Decoder<E>, E> Decodable<T, E> for Uuid {
     /// Decode a UUID from a string
     fn decode(d: &mut T) -> Result<Uuid, E> {
-        Ok(from_str(try!(d.read_str())).unwrap())
+        Ok(from_str(try!(d.read_str()).as_slice()).unwrap())
     }
 }
 
index c2dd8459540d89724a7d8d4084445f51c188b196..5ac45d75156b4442948109c39e366a1d1f76dd81 100644 (file)
@@ -8,6 +8,72 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! A simple function caching system.
+//!
+//! This is a loose clone of the [fbuild build system](https://github.com/felix-lang/fbuild),
+//! made a touch more generic (not wired to special cases on files) and much
+//! less metaprogram-y due to rust's comparative weakness there, relative to
+//! python.
+//!
+//! It's based around _imperative builds_ that happen to have some function
+//! calls cached. That is, it's _just_ a mechanism for describing cached
+//! functions. This makes it much simpler and smaller than a "build system"
+//! that produces an IR and evaluates it. The evaluation order is normal
+//! function calls. Some of them just return really quickly.
+//!
+//! A cached function consumes and produces a set of _works_. A work has a
+//! name, a kind (that determines how the value is to be checked for
+//! freshness) and a value. Works must also be (de)serializable. Some
+//! examples of works:
+//!
+//!    kind   name    value
+//!   ------------------------
+//!    cfg    os      linux
+//!    file   foo.c   <sha1>
+//!    url    foo.com <etag>
+//!
+//! Works are conceptually single units, but we store them most of the time
+//! in maps of the form (type,name) => value. These are WorkMaps.
+//!
+//! A cached function divides the works it's interested in into inputs and
+//! outputs, and subdivides those into declared (input) works and
+//! discovered (input and output) works.
+//!
+//! A _declared_ input or is one that is given to the workcache before
+//! any work actually happens, in the "prep" phase. Even when a function's
+//! work-doing part (the "exec" phase) never gets called, it has declared
+//! inputs, which can be checked for freshness (and potentially
+//! used to determine that the function can be skipped).
+//!
+//! The workcache checks _all_ works for freshness, but uses the set of
+//! discovered outputs from the _previous_ exec (which it will re-discover
+//! and re-record each time the exec phase runs).
+//!
+//! Therefore the discovered works cached in the db might be a
+//! mis-approximation of the current discoverable works, but this is ok for
+//! the following reason: we assume that if an artifact A changed from
+//! depending on B,C,D to depending on B,C,D,E, then A itself changed (as
+//! part of the change-in-dependencies), so we will be ok.
+//!
+//! Each function has a single discriminated output work called its _result_.
+//! This is only different from other works in that it is returned, by value,
+//! from a call to the cacheable function; the other output works are used in
+//! passing to invalidate dependencies elsewhere in the cache, but do not
+//! otherwise escape from a function invocation. Most functions only have one
+//! output work anyways.
+//!
+//! A database (the central store of a workcache) stores a mappings:
+//!
+//! (fn_name,{declared_input}) => ({discovered_input},
+//!                                {discovered_output},result)
+//!
+//! (Note: fbuild, which workcache is based on, has the concept of a declared
+//! output as separate from a discovered output. This distinction exists only
+//! as an artifact of how fbuild works: via annotations on function types
+//! and metaprogramming, with explicit dependency declaration as a fallback.
+//! Workcache is more explicit about dependencies, and as such treats all
+//! outputs the same, as discovered-during-the-last-run.)
+
 #![crate_id = "workcache#0.11.0-pre"]
 #![crate_type = "rlib"]
 #![crate_type = "dylib"]
 use std::io;
 use std::io::{File, MemWriter};
 
-/**
-*
-* This is a loose clone of the [fbuild build system](https://github.com/felix-lang/fbuild),
-* made a touch more generic (not wired to special cases on files) and much
-* less metaprogram-y due to rust's comparative weakness there, relative to
-* python.
-*
-* It's based around _imperative builds_ that happen to have some function
-* calls cached. That is, it's _just_ a mechanism for describing cached
-* functions. This makes it much simpler and smaller than a "build system"
-* that produces an IR and evaluates it. The evaluation order is normal
-* function calls. Some of them just return really quickly.
-*
-* A cached function consumes and produces a set of _works_. A work has a
-* name, a kind (that determines how the value is to be checked for
-* freshness) and a value. Works must also be (de)serializable. Some
-* examples of works:
-*
-*    kind   name    value
-*   ------------------------
-*    cfg    os      linux
-*    file   foo.c   <sha1>
-*    url    foo.com <etag>
-*
-* Works are conceptually single units, but we store them most of the time
-* in maps of the form (type,name) => value. These are WorkMaps.
-*
-* A cached function divides the works it's interested in into inputs and
-* outputs, and subdivides those into declared (input) works and
-* discovered (input and output) works.
-*
-* A _declared_ input or is one that is given to the workcache before
-* any work actually happens, in the "prep" phase. Even when a function's
-* work-doing part (the "exec" phase) never gets called, it has declared
-* inputs, which can be checked for freshness (and potentially
-* used to determine that the function can be skipped).
-*
-* The workcache checks _all_ works for freshness, but uses the set of
-* discovered outputs from the _previous_ exec (which it will re-discover
-* and re-record each time the exec phase runs).
-*
-* Therefore the discovered works cached in the db might be a
-* mis-approximation of the current discoverable works, but this is ok for
-* the following reason: we assume that if an artifact A changed from
-* depending on B,C,D to depending on B,C,D,E, then A itself changed (as
-* part of the change-in-dependencies), so we will be ok.
-*
-* Each function has a single discriminated output work called its _result_.
-* This is only different from other works in that it is returned, by value,
-* from a call to the cacheable function; the other output works are used in
-* passing to invalidate dependencies elsewhere in the cache, but do not
-* otherwise escape from a function invocation. Most functions only have one
-* output work anyways.
-*
-* A database (the central store of a workcache) stores a mappings:
-*
-* (fn_name,{declared_input}) => ({discovered_input},
-*                                {discovered_output},result)
-*
-* (Note: fbuild, which workcache is based on, has the concept of a declared
-* output as separate from a discovered output. This distinction exists only
-* as an artifact of how fbuild works: via annotations on function types
-* and metaprogramming, with explicit dependency declaration as a fallback.
-* Workcache is more explicit about dependencies, and as such treats all
-* outputs the same, as discovered-during-the-last-run.)
-*
-*/
-
 #[deriving(Clone, Eq, Encodable, Decodable, Ord, TotalOrd, TotalEq)]
 struct WorkKey {
     kind: StrBuf,
@@ -192,7 +190,7 @@ fn save(&self) -> io::IoResult<()> {
         // FIXME(pcwalton): Yuck.
         let mut new_db_cache = TreeMap::new();
         for (ref k, ref v) in self.db_cache.iter() {
-            new_db_cache.insert((*k).to_owned(), (*v).to_owned());
+            new_db_cache.insert((*k).to_strbuf(), (*v).to_strbuf());
         }
 
         new_db_cache.to_json().to_pretty_writer(&mut f)
@@ -488,7 +486,7 @@ pub fn unwrap(self) -> T {
 #[cfg(not(target_os="android"))] // FIXME(#10455)
 fn test() {
     use std::os;
-    use std::io::{fs, Process};
+    use std::io::{fs, Command};
     use std::str::from_utf8;
 
     // Create a path to a new file 'filename' in the directory in which
@@ -515,23 +513,23 @@ fn make_path(filename: StrBuf) -> Path {
         let pth = pth.clone();
 
         let contents = File::open(&pth).read_to_end().unwrap();
-        let file_content = from_utf8(contents.as_slice()).unwrap().to_owned();
+        let file_content = from_utf8(contents.as_slice()).unwrap()
+                                                         .to_strbuf();
 
         // FIXME (#9639): This needs to handle non-utf8 paths
-        prep.declare_input("file", pth.as_str().unwrap(), file_content);
+        prep.declare_input("file",
+                           pth.as_str().unwrap(),
+                           file_content.as_slice());
         prep.exec(proc(_exe) {
             let out = make_path("foo.o".to_strbuf());
             let compiler = if cfg!(windows) {"gcc"} else {"cc"};
-            // FIXME (#9639): This needs to handle non-utf8 paths
-            Process::status(compiler, [pth.as_str().unwrap().to_owned(),
-                                    "-o".to_owned(),
-                                    out.as_str().unwrap().to_owned()]).unwrap();
+            Command::new(compiler).arg(pth).arg("-o").arg(out.clone()).status().unwrap();
 
             let _proof_of_concept = subcx.prep("subfn");
             // Could run sub-rules inside here.
 
             // FIXME (#9639): This needs to handle non-utf8 paths
-            out.as_str().unwrap().to_owned()
+            out.as_str().unwrap().to_strbuf()
         })
     });
 
index 1031f3c1570e98892444cc2a3d91d637ff565d21..64776421fa1451c122839a93926844d4b8b52087 100644 (file)
@@ -128,17 +128,27 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM,
 // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
 // field of a PassManagerBuilder, we expose our own method of doing so.
 extern "C" void
-LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) {
+LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB,
+                              LLVMModuleRef M,
+                              bool DisableSimplifyLibCalls) {
     Triple TargetTriple(unwrap(M)->getTargetTriple());
-    unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple);
+    TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
+    if (DisableSimplifyLibCalls)
+      TLI->disableAllFunctions();
+    unwrap(PMB)->LibraryInfo = TLI;
 }
 
 // Unfortunately, the LLVM C API doesn't provide a way to create the
 // TargetLibraryInfo pass, so we use this method to do so.
 extern "C" void
-LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) {
+LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB,
+                       LLVMModuleRef M,
+                       bool DisableSimplifyLibCalls) {
     Triple TargetTriple(unwrap(M)->getTargetTriple());
-    unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple));
+    TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
+    if (DisableSimplifyLibCalls)
+      TLI->disableAllFunctions();
+    unwrap(PMB)->add(TLI);
 }
 
 // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
index e88ae02c1c65b62984578a4cfee3d4957a29bfa0..4c62d519d78122c7d0ce83c1f9d79444e84a7387 100644 (file)
@@ -1,3 +1,11 @@
+S 2014-05-15 6a2b3d1
+  freebsd-x86_64 afc98b59cb819025fecdb9d145ca4463f857a477
+  linux-i386 d6f7a404412ea34db3d19814ca21fe6fa662b02f
+  linux-x86_64 3dfb54406a7ea75565a7ea3071daad885cb91775
+  macos-i386 bebb937551d601ad908c9e4eaa196cc7a977c503
+  macos-x86_64 08346ed401ad2891c7d2ba0aac0960f6e77bb78b
+  winnt-i386 ad8e5b8292a00f60f1f7dc2e35bd18abeb5b858d
+
 S 2014-05-11 72fc4a5
   freebsd-x86_64 82db6355b0b7c8023c8845a74e2f224da2831b50
   linux-i386 91901299d5f86f5b67377d940073908a1f0e4e82
index 0abacf9ecdd23f8017a71cf2ef691019dee5e72d..c4c2f407423f5031c04f0bc529e804d8ae9e2e16 100644 (file)
@@ -19,7 +19,7 @@ pub struct cat {
 
     impl fmt::Show for cat {
         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            write!(f.buf, "{}", self.name)
+            write!(f, "{}", self.name)
         }
     }
 
index ab3539ebf6f54773e6f7fd04cbf5e9b75b0dd59b..4ae0b6f14f59d4fcd009a629edf46aa8f0e38b55 100644 (file)
@@ -27,7 +27,8 @@ fn bar() { }
 fn baz() { }
 
 pub fn test() {
-    let lib = DynamicLibrary::open(None).unwrap();
+    let none: Option<Path> = None; // appease the typechecker
+    let lib = DynamicLibrary::open(none).unwrap();
     unsafe {
         assert!(lib.symbol::<int>("foo").is_ok());
         assert!(lib.symbol::<int>("baz").is_err());
index 9db068e56c29af2ff4ee65103e5bec7d807279d2..f0bc0204fd26d17a53262f6581ba2619246396ea 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// no-pretty-expanded
+
 #![feature(phase)]
 #[phase(syntax)] extern crate green;
 
@@ -33,7 +35,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             Yellow => "yellow",
             Blue => "blue",
         };
-        f.buf.write(str.as_bytes())
+        write!(f, "{}", str)
     }
 }
 
@@ -82,7 +84,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         }
 
         for s in out.iter().rev() {
-            try!(f.buf.write(s.as_bytes()));
+            try!(write!(f, "{}", s))
         }
         Ok(())
     }
index e17324ee596491dfb58a87439bd880ce37e70060..debd12874da1ee6e1c485096df7ef1ae3143e7b1 100644 (file)
 // <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.
+#![feature(macro_rules)]
+#![feature(simd)]
+#![allow(experimental)]
 
 // ignore-pretty very bad with line comments
 
 extern crate sync;
 
 use std::io;
+use std::os;
+use std::unstable::simd::f64x2;
 use sync::Future;
+use sync::Arc;
 
 static ITER: int = 50;
 static LIMIT: f64 = 2.0;
+static WORKERS: uint = 16;
+
+#[inline(always)]
+fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
+    assert!(WORKERS % 2 == 0);
+
+    // Ensure w and h are multiples of 8.
+    let w = (w + 7) / 8 * 8;
+    let h = w;
+
+    let chunk_size = h / WORKERS;
+
+    // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
+    let first_chunk_size = if h % WORKERS != 0 {
+        chunk_size + h % WORKERS
+    } else {
+        chunk_size
+    };
+
+    // precalc values
+    let inverse_w_doubled = 2.0 / w as f64;
+    let inverse_h_doubled = 2.0 / h as f64;
+    let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
+    let v_consts = f64x2(1.5, 1.0);
+
+    // A lot of this code assumes this (so do other lang benchmarks)
+    assert!(w == h);
+    let mut precalc_r = Vec::with_capacity(w);
+    let mut precalc_i = Vec::with_capacity(h);
+
+    let precalc_futures = Vec::from_fn(WORKERS, |i| {
+        Future::spawn(proc () {
+            let mut rs = Vec::with_capacity(w / WORKERS);
+            let mut is = Vec::with_capacity(w / WORKERS);
+
+            let start = i * chunk_size;
+            let end = if i == 0 {
+                first_chunk_size
+            } else {
+                (i + 1) * chunk_size
+            };
+
+            // This assumes w == h
+            for x in range(start, end) {
+                let xf = x as f64;
+                let xy = f64x2(xf, xf);
+
+                let f64x2(r, i) = xy * v_inverses - v_consts;
+                rs.push(r);
+                is.push(i);
+            }
+
+            (rs, is)
+        })
+    });
+
+    for res in precalc_futures.move_iter() {
+        let (rs, is) = res.unwrap();
+        precalc_r.push_all_move(rs);
+        precalc_i.push_all_move(is);
+    }
+
+    assert_eq!(precalc_r.len(), w);
+    assert_eq!(precalc_i.len(), h);
+
+    let arc_init_r = Arc::new(precalc_r);
+    let arc_init_i = Arc::new(precalc_i);
+
+    let data = Vec::from_fn(WORKERS, |i| {
+        let vec_init_r = arc_init_r.clone();
+        let vec_init_i = arc_init_i.clone();
+
+        Future::spawn(proc () {
+            let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
+            let init_r_slice = vec_init_r.as_slice();
+            for &init_i in vec_init_i.slice(i * chunk_size, (i + 1) * chunk_size).iter() {
+                write_line(init_i, init_r_slice, &mut res);
+            }
+
+            res
+        })
+    });
+
+    try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h));
+    for res in data.move_iter() {
+        try!(out.write(res.unwrap().as_slice()));
+    }
+    out.flush()
+}
 
 fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
+    let v_init_i : f64x2 = f64x2(init_i, init_i);
+    let v_2 : f64x2 = f64x2(2.0, 2.0);
+    static LIMIT_SQUARED: f64 = LIMIT * LIMIT;
+
     for chunk_init_r in vec_init_r.chunks(8) {
         let mut cur_byte = 0xff;
-        let mut cur_bitmask = 0x80;
-        for &init_r in chunk_init_r.iter() {
-            let mut cur_r = init_r;
-            let mut cur_i = init_i;
+        let mut i = 0;
+
+        while i < 8 {
+            let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
+            let mut cur_r = v_init_r;
+            let mut cur_i = v_init_i;
+            let mut r_sq = v_init_r * v_init_r;
+            let mut i_sq = v_init_i * v_init_i;
+
+            let mut b = 0;
             for _ in range(0, ITER) {
                 let r = cur_r;
                 let i = cur_i;
-                cur_r = r * r - i * i + init_r;
-                cur_i = 2.0 * r * i + init_i;
 
-                if r * r + i * i > LIMIT * LIMIT {
-                    cur_byte &= !cur_bitmask;
-                    break;
+                cur_i = v_2 * r * i + v_init_i;
+                cur_r = r_sq - i_sq + v_init_r;
+
+                let f64x2(bit1, bit2) = r_sq + i_sq;
+
+                if bit1 > LIMIT_SQUARED {
+                    b |= 2;
+                    if b == 3 { break; }
+                }
+
+                if bit2 > LIMIT_SQUARED {
+                    b |= 1;
+                    if b == 3 { break; }
                 }
+
+                r_sq = cur_r * cur_r;
+                i_sq = cur_i * cur_i;
             }
-            cur_bitmask >>= 1;
-        }
-        res.push(cur_byte);
-    }
-}
 
-fn mandelbrot<W: io::Writer>(w: uint, mut out: W) -> io::IoResult<()> {
-    // Ensure w and h are multiples of 8.
-    let w = (w + 7) / 8 * 8;
-    let h = w;
-    let chunk_size = h / 8;
-
-    let data: Vec<Future<Vec<u8>>> = range(0u, 8).map(|i| Future::spawn(proc () {
-        let vec_init_r = Vec::from_fn(w, |x| 2.0 * (x as f64) / (w as f64) - 1.5);
-        let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
-        for y in range(i * chunk_size, (i + 1) * chunk_size) {
-            let init_i = 2.0 * (y as f64) / (h as f64) - 1.0;
-            write_line(init_i, vec_init_r.as_slice(), &mut res);
+            cur_byte = (cur_byte << 2) + b;
+            i += 2;
         }
-        res
-    })).collect();
 
-    try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h));
-    for res in data.move_iter() {
-        try!(out.write(res.unwrap().as_slice()));
+        res.push(cur_byte^-1);
     }
-    out.flush()
 }
 
 fn main() {
-    let args = std::os::args();
+    let args = os::args();
     let args = args.as_slice();
     let res = if args.len() < 2 {
         println!("Test mode: do not dump the image because it's not utf8, \
                   which interferes with the test runner.");
-        mandelbrot(1000, std::io::util::NullWriter)
+        mandelbrot(1000, io::util::NullWriter)
     } else {
-        mandelbrot(from_str(args[1]).unwrap(), std::io::stdout())
+        mandelbrot(from_str(args[1]).unwrap(), io::stdout())
     };
     res.unwrap();
 }
index a6e579689ed4258bf7cdc444dd49af9303e4ede5..313671448f8e9c71a91a82032871f9d9e2d69eaa 100644 (file)
@@ -55,7 +55,7 @@ struct Config {
 fn parse_opts(argv: Vec<StrBuf> ) -> Config {
     let opts = vec!(getopts::optflag("", "stress", ""));
 
-    let argv = argv.iter().map(|x| x.to_str()).collect::<Vec<_>>();
+    let argv = argv.iter().map(|x| x.to_strbuf()).collect::<Vec<_>>();
     let opt_args = argv.slice(1, argv.len());
 
     match getopts::getopts(opt_args, opts.as_slice()) {
diff --git a/src/test/compile-fail-fulldeps/gated-phase.rs b/src/test/compile-fail-fulldeps/gated-phase.rs
new file mode 100644 (file)
index 0000000..c876389
--- /dev/null
@@ -0,0 +1,18 @@
+// 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:macro_crate_test.rs
+// ignore-stage1
+
+#[phase(syntax)]
+//~^ ERROR compile time crate loading is experimental and possibly buggy
+extern crate macro_crate_test;
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs b/src/test/compile-fail-fulldeps/macro-crate-unexported-macro.rs
new file mode 100644 (file)
index 0000000..f8eb986
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 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:macro_crate_test.rs
+// ignore-stage1
+// ignore-android
+
+#![feature(phase)]
+
+#[phase(syntax)]
+extern crate macro_crate_test;
+
+fn main() {
+    assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro'
+}
diff --git a/src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs b/src/test/compile-fail-fulldeps/macro-crate-unknown-crate.rs
new file mode 100644 (file)
index 0000000..84c915f
--- /dev/null
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(phase)]
+
+#[phase(syntax)]
+extern crate doesnt_exist; //~ ERROR can't find crate
+
+fn main() {}
diff --git a/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs
new file mode 100644 (file)
index 0000000..2053f81
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2013-2014 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:macro_crate_test.rs
+// ignore-stage1
+// ignore-android
+
+#![feature(phase)]
+
+#[phase(syntax)]
+extern crate macro_crate_test;
+
+fn main() {
+    macro_crate_test::foo();
+    //~^ ERROR unresolved name
+    //~^^ ERROR use of undeclared module `macro_crate_test`
+    //~^^^ ERROR unresolved name `macro_crate_test::foo`.
+}
diff --git a/src/test/compile-fail/gated-phase.rs b/src/test/compile-fail/gated-phase.rs
deleted file mode 100644 (file)
index c876389..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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:macro_crate_test.rs
-// ignore-stage1
-
-#[phase(syntax)]
-//~^ ERROR compile time crate loading is experimental and possibly buggy
-extern crate macro_crate_test;
-
-fn main() {}
index 830b041bbc7156c365629386042e245a24815346..897717971bc1735e1e863d854b6e5ae0fa5c9438 100644 (file)
@@ -10,5 +10,5 @@
 
 fn main() {
     format!("{:d}", "3");
-    //~^ ERROR: failed to find an implementation of trait std::fmt::Signed
+    //~^ ERROR: failed to find an implementation of trait core::fmt::Signed
 }
diff --git a/src/test/compile-fail/macro-crate-unexported-macro.rs b/src/test/compile-fail/macro-crate-unexported-macro.rs
deleted file mode 100644 (file)
index f8eb986..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2014 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:macro_crate_test.rs
-// ignore-stage1
-// ignore-android
-
-#![feature(phase)]
-
-#[phase(syntax)]
-extern crate macro_crate_test;
-
-fn main() {
-    assert_eq!(3, unexported_macro!()); //~ ERROR macro undefined: 'unexported_macro'
-}
diff --git a/src/test/compile-fail/macro-crate-unknown-crate.rs b/src/test/compile-fail/macro-crate-unknown-crate.rs
deleted file mode 100644 (file)
index 84c915f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-#![feature(phase)]
-
-#[phase(syntax)]
-extern crate doesnt_exist; //~ ERROR can't find crate
-
-fn main() {}
diff --git a/src/test/compile-fail/phase-syntax-doesnt-resolve.rs b/src/test/compile-fail/phase-syntax-doesnt-resolve.rs
deleted file mode 100644 (file)
index 2053f81..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013-2014 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:macro_crate_test.rs
-// ignore-stage1
-// ignore-android
-
-#![feature(phase)]
-
-#[phase(syntax)]
-extern crate macro_crate_test;
-
-fn main() {
-    macro_crate_test::foo();
-    //~^ ERROR unresolved name
-    //~^^ ERROR use of undeclared module `macro_crate_test`
-    //~^^^ ERROR unresolved name `macro_crate_test::foo`.
-}
index e95ab71e5aaeae895c28ebaf5eb7b7a628b430b5..753c91d1dc9580ffde569ad6e219f1294ca0ea94 100644 (file)
@@ -18,7 +18,7 @@ struct Number {
 
 impl fmt::Show for Number {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.n)
+        write!(f, "{}", self.n)
     }
 }
 
diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile
new file mode 100644 (file)
index 0000000..fedcc89
--- /dev/null
@@ -0,0 +1,37 @@
+-include ../tools.mk
+
+FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \
+      f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \
+      f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs
+
+
+# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES))
+all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES))
+
+
+RUSTC_LIB=$(RUSTC) --crate-type=lib
+
+define FIND_LAST_BLOCK
+LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) --pretty=expanded,identified $(1) \
+                        | grep block
+                        | tail -1
+                        | sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@')
+endef
+
+ifeq ($(findstring rustc,$(RUSTC)),)
+$(error Must set RUSTC)
+endif
+
+$(TMPDIR)/%.pp: %.rs
+       $(RUSTC_LIB) --pretty=expanded,identified $< -o $@
+
+$(TMPDIR)/%.dot: %.rs
+       $(eval $(call FIND_LAST_BLOCK,$<))
+       $(RUSTC_LIB) --pretty flowgraph=$(LASTBLOCKNUM_$<) $< -o $@.tmp
+       cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \
+                         -e 's@\[label=""\]@@' \
+                         -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \
+                     > $@
+
+$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot
+       diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<)
diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot
new file mode 100644 (file)
index 0000000..f699771
--- /dev/null
@@ -0,0 +1,7 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="block { }"];
+    N0 -> N2;
+    N2 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f00.rs b/src/test/run-make/graphviz-flowgraph/f00.rs
new file mode 100644 (file)
index 0000000..4e7fc7e
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn empty_0() {
+
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot
new file mode 100644 (file)
index 0000000..9d8411c
--- /dev/null
@@ -0,0 +1,9 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 1"];
+    N3[label="block { 1; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f01.rs b/src/test/run-make/graphviz-flowgraph/f01.rs
new file mode 100644 (file)
index 0000000..231aab6
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn lit_1() {
+    1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot
new file mode 100644 (file)
index 0000000..ada3f09
--- /dev/null
@@ -0,0 +1,9 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="local _x"];
+    N3[label="block { let _x: int; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f02.rs b/src/test/run-make/graphviz-flowgraph/f02.rs
new file mode 100644 (file)
index 0000000..3cdd73a
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn decl_x_2() {
+    let _x : int;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot
new file mode 100644 (file)
index 0000000..aff4304
--- /dev/null
@@ -0,0 +1,13 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 3"];
+    N3[label="expr 33"];
+    N4[label="expr 3 + 33"];
+    N5[label="block { 3 + 33; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f03.rs b/src/test/run-make/graphviz-flowgraph/f03.rs
new file mode 100644 (file)
index 0000000..8b172c0
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_add_3() {
+    3 + 33;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot
new file mode 100644 (file)
index 0000000..adcc582
--- /dev/null
@@ -0,0 +1,11 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 4"];
+    N3[label="local _x"];
+    N4[label="block { let _x = 4; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f04.rs b/src/test/run-make/graphviz-flowgraph/f04.rs
new file mode 100644 (file)
index 0000000..2a0ac8a
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn pat_id_4() {
+    let _x = 4;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot
new file mode 100644 (file)
index 0000000..2d52c14
--- /dev/null
@@ -0,0 +1,19 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 5"];
+    N3[label="expr 55"];
+    N4[label="expr (5, 55)"];
+    N5[label="local _x"];
+    N6[label="local _y"];
+    N7[label="pat (_x, _y)"];
+    N8[label="block { let (_x, _y) = (5, 55); }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f05.rs b/src/test/run-make/graphviz-flowgraph/f05.rs
new file mode 100644 (file)
index 0000000..616d822
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn pat_tup_5() {
+    let (_x, _y) = (5, 55);
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot
new file mode 100644 (file)
index 0000000..61b40d6
--- /dev/null
@@ -0,0 +1,15 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 6"];
+    N3[label="expr S6{val: 6,}"];
+    N4[label="local _x"];
+    N5[label="pat S6{val: _x}"];
+    N6[label="block { let S6{val: _x} = S6{val: 6,}; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f06.rs b/src/test/run-make/graphviz-flowgraph/f06.rs
new file mode 100644 (file)
index 0000000..c914409
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 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.
+
+struct S6 { val: int }
+pub fn pat_struct_6() {
+    let S6 { val: _x } = S6{ val: 6 };
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot
new file mode 100644 (file)
index 0000000..c99af17
--- /dev/null
@@ -0,0 +1,33 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 7"];
+    N3[label="expr 77"];
+    N4[label="expr 777"];
+    N5[label="expr 7777"];
+    N6[label="expr [7, 77, 777, 7777]"];
+    N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y }"];
+    N8[label="local x"];
+    N9[label="local y"];
+    N10[label="pat .."];
+    N11[label="pat [x, y, ..]"];
+    N12[label="expr x"];
+    N13[label="expr y"];
+    N14[label="expr x + y"];
+    N15[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y }; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N8;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N14;
+    N14 -> N7;
+    N7 -> N15;
+    N15 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f07.rs b/src/test/run-make/graphviz-flowgraph/f07.rs
new file mode 100644 (file)
index 0000000..39f71d3
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn pat_vec_7() {
+    match [7, 77, 777, 7777] {
+        [x, y, ..] => x + y
+    };
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot
new file mode 100644 (file)
index 0000000..61a708c
--- /dev/null
@@ -0,0 +1,30 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 8"];
+    N3[label="local x"];
+    N4[label="local _y"];
+    N5[label="expr x"];
+    N6[label="expr 88"];
+    N7[label="expr x > 88"];
+    N8[label="expr 888"];
+    N9[label="expr _y"];
+    N10[label="expr _y = 888"];
+    N11[label="block { _y = 888; }"];
+    N12[label="expr if x > 88 { _y = 888; }"];
+    N13[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N7 -> N12;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f08.rs b/src/test/run-make/graphviz-flowgraph/f08.rs
new file mode 100644 (file)
index 0000000..6ba7b03
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_if_onearm_8() {
+    let x = 8; let _y;
+    if x > 88 {
+        _y = 888;
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot
new file mode 100644 (file)
index 0000000..892b9fc
--- /dev/null
@@ -0,0 +1,44 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 91"];
+    N3[label="local x"];
+    N4[label="local _y"];
+    N5[label="expr x"];
+    N6[label="expr 92"];
+    N7[label="expr x > 92"];
+    N8[label="expr 93"];
+    N9[label="expr _y"];
+    N10[label="expr _y = 93"];
+    N11[label="block { _y = 93; }"];
+    N12[label="expr 94"];
+    N13[label="expr 95"];
+    N14[label="expr 94 + 95"];
+    N15[label="expr _y"];
+    N16[label="expr _y = 94 + 95"];
+    N17[label="block { _y = 94 + 95; }"];
+    N18[label="expr { _y = 94 + 95; }"];
+    N19[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"];
+    N20[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N7 -> N12;
+    N12 -> N13;
+    N13 -> N14;
+    N14 -> N15;
+    N15 -> N16;
+    N16 -> N17;
+    N17 -> N18;
+    N11 -> N19;
+    N18 -> N19;
+    N19 -> N20;
+    N20 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f09.rs b/src/test/run-make/graphviz-flowgraph/f09.rs
new file mode 100644 (file)
index 0000000..a78ccb8
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_if_twoarm_9() {
+    let x = 91; let _y;
+    if x > 92 {
+        _y = 93;
+    } else {
+        _y = 94+95;
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot
new file mode 100644 (file)
index 0000000..2cef122
--- /dev/null
@@ -0,0 +1,30 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 10"];
+    N3[label="local mut x"];
+    N4[label="(dummy_node)"];
+    N5[label="expr x"];
+    N6[label="expr 0"];
+    N7[label="expr x > 0"];
+    N8[label="expr while x > 0 { x -= 1; }"];
+    N9[label="expr 1"];
+    N10[label="expr x"];
+    N11[label="expr x -= 1"];
+    N12[label="block { x -= 1; }"];
+    N13[label="block { let mut x = 10; while x > 0 { x -= 1; } }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N7 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N4;
+    N8 -> N13;
+    N13 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f10.rs b/src/test/run-make/graphviz-flowgraph/f10.rs
new file mode 100644 (file)
index 0000000..0ca7cc5
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_while_10() {
+    let mut x = 10;
+    while x > 0 {
+        x -= 1;
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot
new file mode 100644 (file)
index 0000000..59d65e5
--- /dev/null
@@ -0,0 +1,25 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 11"];
+    N3[label="local mut _x"];
+    N4[label="(dummy_node)"];
+    N5[label="expr loop  { _x -= 1; }"];
+    N6[label="expr 1"];
+    N7[label="expr _x"];
+    N8[label="expr _x -= 1"];
+    N9[label="block { _x -= 1; }"];
+    N10[label="expr \"unreachable\""];
+    N11[label="block { let mut _x = 11; loop  { _x -= 1; } \"unreachable\"; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N4;
+    N5 -> N10;
+    N10 -> N11;
+    N11 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f11.rs b/src/test/run-make/graphviz-flowgraph/f11.rs
new file mode 100644 (file)
index 0000000..d0f3452
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_loop_11() {
+    let mut _x = 11;
+    loop {
+        _x -= 1;
+    }
+    "unreachable";
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot
new file mode 100644 (file)
index 0000000..9c0f25d
--- /dev/null
@@ -0,0 +1,40 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 12"];
+    N3[label="local mut x"];
+    N4[label="(dummy_node)"];
+    N5[label="expr loop  { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
+    N6[label="expr 1"];
+    N7[label="expr x"];
+    N8[label="expr x -= 1"];
+    N9[label="expr x"];
+    N10[label="expr 2"];
+    N11[label="expr x == 2"];
+    N12[label="expr break"];
+    N13[label="(dummy_node)"];
+    N14[label="expr \"unreachable\""];
+    N15[label="block { break ; \"unreachable\"; }"];
+    N16[label="expr if x == 2 { break ; \"unreachable\"; }"];
+    N17[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
+    N18[label="block { let mut x = 12; loop  { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N5[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2 { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
+    N13 -> N14;
+    N14 -> N15;
+    N11 -> N16;
+    N15 -> N16;
+    N16 -> N17;
+    N17 -> N4;
+    N5 -> N18;
+    N18 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f12.rs b/src/test/run-make/graphviz-flowgraph/f12.rs
new file mode 100644 (file)
index 0000000..90b1463
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_loop_12() {
+    let mut x = 12;
+    loop {
+        x -= 1;
+        if x == 2 { break; "unreachable"; }
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot
new file mode 100644 (file)
index 0000000..2be43dc
--- /dev/null
@@ -0,0 +1,44 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr E13b"];
+    N3[label="expr 13"];
+    N4[label="expr E13b(13)"];
+    N5[label="local x"];
+    N6[label="local _y"];
+    N7[label="expr x"];
+    N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1 }"];
+    N9[label="local E13a"];
+    N10[label="expr 1"];
+    N11[label="expr _y"];
+    N12[label="expr _y = 1"];
+    N13[label="local v"];
+    N14[label="pat E13b(v)"];
+    N15[label="expr v"];
+    N16[label="expr 1"];
+    N17[label="expr v + 1"];
+    N18[label="expr _y"];
+    N19[label="expr _y = v + 1"];
+    N20[label="block {\l    let x = E13b(13);\l    let _y;\l    match x { E13a => _y = 1, E13b(v) => _y = v + 1 }\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N9;
+    N9 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N8;
+    N7 -> N13;
+    N13 -> N14;
+    N14 -> N15;
+    N15 -> N16;
+    N16 -> N17;
+    N17 -> N18;
+    N18 -> N19;
+    N19 -> N8;
+    N8 -> N20;
+    N20 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f13.rs b/src/test/run-make/graphviz-flowgraph/f13.rs
new file mode 100644 (file)
index 0000000..0817a32
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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.
+
+enum E13 { E13a, E13b(int) }
+pub fn expr_match_13() {
+    let x = E13b(13); let _y;
+    match x {
+        E13a => _y = 1,
+        E13b(v) => _y = v + 1,
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot
new file mode 100644 (file)
index 0000000..0fa4e9b
--- /dev/null
@@ -0,0 +1,28 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 14"];
+    N3[label="local x"];
+    N4[label="expr x"];
+    N5[label="expr 1"];
+    N6[label="expr x > 1"];
+    N7[label="expr return"];
+    N8[label="(dummy_node)"];
+    N9[label="expr \"unreachable\""];
+    N10[label="block { return; \"unreachable\"; }"];
+    N11[label="expr if x > 1 { return; \"unreachable\"; }"];
+    N12[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N1;
+    N8 -> N9;
+    N9 -> N10;
+    N6 -> N11;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f14.rs b/src/test/run-make/graphviz-flowgraph/f14.rs
new file mode 100644 (file)
index 0000000..98ff095
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_ret_14() {
+    let x = 14;
+    if x > 1 {
+        return;
+        "unreachable";
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot
new file mode 100644 (file)
index 0000000..f0278fb
--- /dev/null
@@ -0,0 +1,79 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 15"];
+    N3[label="local mut x"];
+    N4[label="expr 151"];
+    N5[label="local mut y"];
+    N6[label="(dummy_node)"];
+    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { break \'outer ; \"unreachable\" }\l                if y >= 2 { break ; \"unreachable\" }\l                y -= 3;\l            }\l        y -= 4;\l        x -= 5;\l    }\l"];
+    N8[label="(dummy_node)"];
+    N9[label="expr \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\" }\l        if y >= 2 { break ; \"unreachable\" }\l        y -= 3;\l    }\l"];
+    N10[label="expr x"];
+    N11[label="expr 1"];
+    N12[label="expr x == 1"];
+    N13[label="expr break \'outer"];
+    N14[label="(dummy_node)"];
+    N15[label="expr \"unreachable\""];
+    N16[label="block { break \'outer ; \"unreachable\" }"];
+    N17[label="expr if x == 1 { break \'outer ; \"unreachable\" }"];
+    N18[label="expr y"];
+    N19[label="expr 2"];
+    N20[label="expr y >= 2"];
+    N21[label="expr break"];
+    N22[label="(dummy_node)"];
+    N23[label="expr \"unreachable\""];
+    N24[label="block { break ; \"unreachable\" }"];
+    N25[label="expr if y >= 2 { break ; \"unreachable\" }"];
+    N26[label="expr 3"];
+    N27[label="expr y"];
+    N28[label="expr y -= 3"];
+    N29[label="block {\l    if x == 1 { break \'outer ; \"unreachable\" }\l    if y >= 2 { break ; \"unreachable\" }\l    y -= 3;\l}\l"];
+    N30[label="expr 4"];
+    N31[label="expr y"];
+    N32[label="expr y -= 4"];
+    N33[label="expr 5"];
+    N34[label="expr x"];
+    N35[label="expr x -= 5"];
+    N36[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\" }\l            if y >= 2 { break ; \"unreachable\" }\l            y -= 3;\l        }\l    y -= 4;\l    x -= 5;\l}\l"];
+    N37[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\" }\l                    if y >= 2 { break ; \"unreachable\" }\l                    y -= 3;\l                }\l            y -= 4;\l            x -= 5;\l        }\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N8;
+    N8 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1 { break \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1 { break \'outer ; \"unreachable\" },\lexiting scope_5 block {\l    if x == 1 { break \'outer ; \"unreachable\" }\l    if y >= 2 { break ; \"unreachable\" }\l    y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\" }\l        if y >= 2 { break ; \"unreachable\" }\l        y -= 3;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\" }\l        if y >= 2 { break ; \"unreachable\" }\l        y -= 3;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\" }\l            if y >= 2 { break ; \"unreachable\" }\l            y -= 3;\l        }\l    y -= 4;\l    x -= 5;\l}\l"];
+    N14 -> N15;
+    N15 -> N16;
+    N12 -> N17;
+    N16 -> N17;
+    N17 -> N18;
+    N18 -> N19;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 2 { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 2 { break ; \"unreachable\" },\lexiting scope_5 block {\l    if x == 1 { break \'outer ; \"unreachable\" }\l    if y >= 2 { break ; \"unreachable\" }\l    y -= 3;\l}\l"];
+    N22 -> N23;
+    N23 -> N24;
+    N20 -> N25;
+    N24 -> N25;
+    N25 -> N26;
+    N26 -> N27;
+    N27 -> N28;
+    N28 -> N29;
+    N29 -> N8;
+    N9 -> N30;
+    N30 -> N31;
+    N31 -> N32;
+    N32 -> N33;
+    N33 -> N34;
+    N34 -> N35;
+    N35 -> N36;
+    N36 -> N6;
+    N7 -> N37;
+    N37 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs
new file mode 100644 (file)
index 0000000..44c038d
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_break_label_15() {
+    let mut x = 15;
+    let mut y = 151;
+    'outer: loop {
+        'inner: loop {
+            if x == 1 {
+                break 'outer;
+                "unreachable"
+            }
+            if y >= 2 {
+                break;
+                "unreachable"
+            }
+            y -= 3;
+        }
+        y -= 4;
+        x -= 5;
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot
new file mode 100644 (file)
index 0000000..3f999ae
--- /dev/null
@@ -0,0 +1,81 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 16"];
+    N3[label="local mut x"];
+    N4[label="expr 16"];
+    N5[label="local mut y"];
+    N6[label="(dummy_node)"];
+    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { continue \'outer ; \"unreachable\" }\l                if y >= 1 { break ; \"unreachable\" }\l                y -= 1;\l            }\l        y -= 1;\l        x -= 1;\l    }\l"];
+    N8[label="(dummy_node)"];
+    N9[label="expr \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\" }\l        if y >= 1 { break ; \"unreachable\" }\l        y -= 1;\l    }\l"];
+    N10[label="expr x"];
+    N11[label="expr 1"];
+    N12[label="expr x == 1"];
+    N13[label="expr continue \'outer"];
+    N14[label="(dummy_node)"];
+    N15[label="expr \"unreachable\""];
+    N16[label="block { continue \'outer ; \"unreachable\" }"];
+    N17[label="expr if x == 1 { continue \'outer ; \"unreachable\" }"];
+    N18[label="expr y"];
+    N19[label="expr 1"];
+    N20[label="expr y >= 1"];
+    N21[label="expr break"];
+    N22[label="(dummy_node)"];
+    N23[label="expr \"unreachable\""];
+    N24[label="block { break ; \"unreachable\" }"];
+    N25[label="expr if y >= 1 { break ; \"unreachable\" }"];
+    N26[label="expr 1"];
+    N27[label="expr y"];
+    N28[label="expr y -= 1"];
+    N29[label="block {\l    if x == 1 { continue \'outer ; \"unreachable\" }\l    if y >= 1 { break ; \"unreachable\" }\l    y -= 1;\l}\l"];
+    N30[label="expr 1"];
+    N31[label="expr y"];
+    N32[label="expr y -= 1"];
+    N33[label="expr 1"];
+    N34[label="expr x"];
+    N35[label="expr x -= 1"];
+    N36[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { continue \'outer ; \"unreachable\" }\l            if y >= 1 { break ; \"unreachable\" }\l            y -= 1;\l        }\l    y -= 1;\l    x -= 1;\l}\l"];
+    N37[label="expr \"unreachable\""];
+    N38[label="block {\l    let mut x = 16;\l    let mut y = 16;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\" }\l                    if y >= 1 { break ; \"unreachable\" }\l                    y -= 1;\l                }\l            y -= 1;\l            x -= 1;\l        }\l    \"unreachable\";\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N8;
+    N8 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1 { continue \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1 { continue \'outer ; \"unreachable\" },\lexiting scope_5 block {\l    if x == 1 { continue \'outer ; \"unreachable\" }\l    if y >= 1 { break ; \"unreachable\" }\l    y -= 1;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\" }\l        if y >= 1 { break ; \"unreachable\" }\l        y -= 1;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\" }\l        if y >= 1 { break ; \"unreachable\" }\l        y -= 1;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1 { continue \'outer ; \"unreachable\" }\l            if y >= 1 { break ; \"unreachable\" }\l            y -= 1;\l        }\l    y -= 1;\l    x -= 1;\l}\l"];
+    N14 -> N15;
+    N15 -> N16;
+    N12 -> N17;
+    N16 -> N17;
+    N17 -> N18;
+    N18 -> N19;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 1 { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 1 { break ; \"unreachable\" },\lexiting scope_5 block {\l    if x == 1 { continue \'outer ; \"unreachable\" }\l    if y >= 1 { break ; \"unreachable\" }\l    y -= 1;\l}\l"];
+    N22 -> N23;
+    N23 -> N24;
+    N20 -> N25;
+    N24 -> N25;
+    N25 -> N26;
+    N26 -> N27;
+    N27 -> N28;
+    N28 -> N29;
+    N29 -> N8;
+    N9 -> N30;
+    N30 -> N31;
+    N31 -> N32;
+    N32 -> N33;
+    N33 -> N34;
+    N34 -> N35;
+    N35 -> N36;
+    N36 -> N6;
+    N7 -> N37;
+    N37 -> N38;
+    N38 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs
new file mode 100644 (file)
index 0000000..f4f23a6
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_continue_label_16() {
+    let mut x = 16;
+    let mut y = 16;
+    'outer: loop {
+        'inner: loop {
+            if x == 1 {
+                continue 'outer;
+                "unreachable"
+            }
+            if y >= 1 {
+                break;
+                "unreachable"
+            }
+            y -= 1;
+        }
+        y -= 1;
+        x -= 1;
+    }
+    "unreachable";
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot
new file mode 100644 (file)
index 0000000..e9bccda
--- /dev/null
@@ -0,0 +1,17 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 1"];
+    N3[label="expr 7"];
+    N4[label="expr 17"];
+    N5[label="expr [1, 7, 17]"];
+    N6[label="local _v"];
+    N7[label="block { let _v = [1, 7, 17]; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f17.rs b/src/test/run-make/graphviz-flowgraph/f17.rs
new file mode 100644 (file)
index 0000000..23f5bb8
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_vec_17() {
+    let _v = [1, 7, 17];
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
new file mode 100644 (file)
index 0000000..6345b4e
--- /dev/null
@@ -0,0 +1,17 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr inner"];
+    N3[label="expr inner"];
+    N4[label="expr 18"];
+    N5[label="expr inner(18)"];
+    N6[label="expr inner(inner(18))"];
+    N7[label="block {\l    fn inner(x: int) -> int { x + x }\l    inner(inner(18));\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f18.rs b/src/test/run-make/graphviz-flowgraph/f18.rs
new file mode 100644 (file)
index 0000000..0ace542
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_call_18() {
+    fn inner(x:int) -> int { x + x }
+    inner(inner(18));
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
new file mode 100644 (file)
index 0000000..5fad185
--- /dev/null
@@ -0,0 +1,19 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 19"];
+    N3[label="expr S19{x: 19,}"];
+    N4[label="local s"];
+    N5[label="expr s"];
+    N6[label="expr s.inner()"];
+    N7[label="expr s.inner().inner()"];
+    N8[label="block {\l    struct S19 {\l        x: int,\l    }\l    impl S19 {\l        fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f19.rs b/src/test/run-make/graphviz-flowgraph/f19.rs
new file mode 100644 (file)
index 0000000..092f689
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_method_call_19() {
+    struct S19 { x: int }
+    impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } }
+    let s = S19 { x: 19 };
+    s.inner().inner();
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot
new file mode 100644 (file)
index 0000000..593ad6f
--- /dev/null
@@ -0,0 +1,23 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 2"];
+    N3[label="expr 0"];
+    N4[label="expr 20"];
+    N5[label="expr [2, 0, 20]"];
+    N6[label="local v"];
+    N7[label="expr v"];
+    N8[label="expr 20"];
+    N9[label="expr v[20]"];
+    N10[label="block { let v = [2, 0, 20]; v[20]; }"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N7;
+    N7 -> N8;
+    N8 -> N9;
+    N9 -> N10;
+    N10 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f20.rs b/src/test/run-make/graphviz-flowgraph/f20.rs
new file mode 100644 (file)
index 0000000..d734993
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn expr_index_20() {
+    let v = [2, 0, 20];
+    v[20];
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot
new file mode 100644 (file)
index 0000000..0798c4a
--- /dev/null
@@ -0,0 +1,75 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 15"];
+    N3[label="local mut x"];
+    N4[label="expr 151"];
+    N5[label="local mut y"];
+    N6[label="(dummy_node)"];
+    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { break \'outer ; \"unreachable\"; }\l                if y >= 2 { return; \"unreachable\"; }\l                y -= 3;\l                x -= 5;\l            }\l        \"unreachable\";\l    }\l"];
+    N8[label="(dummy_node)"];
+    N9[label="expr \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        y -= 3;\l        x -= 5;\l    }\l"];
+    N10[label="expr x"];
+    N11[label="expr 1"];
+    N12[label="expr x == 1"];
+    N13[label="expr break \'outer"];
+    N14[label="(dummy_node)"];
+    N15[label="expr \"unreachable\""];
+    N16[label="block { break \'outer ; \"unreachable\"; }"];
+    N17[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"];
+    N18[label="expr y"];
+    N19[label="expr 2"];
+    N20[label="expr y >= 2"];
+    N21[label="expr return"];
+    N22[label="(dummy_node)"];
+    N23[label="expr \"unreachable\""];
+    N24[label="block { return; \"unreachable\"; }"];
+    N25[label="expr if y >= 2 { return; \"unreachable\"; }"];
+    N26[label="expr 3"];
+    N27[label="expr y"];
+    N28[label="expr y -= 3"];
+    N29[label="expr 5"];
+    N30[label="expr x"];
+    N31[label="expr x -= 5"];
+    N32[label="block {\l    if x == 1 { break \'outer ; \"unreachable\"; }\l    if y >= 2 { return; \"unreachable\"; }\l    y -= 3;\l    x -= 5;\l}\l"];
+    N33[label="expr \"unreachable\""];
+    N34[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\"; }\l            if y >= 2 { return; \"unreachable\"; }\l            y -= 3;\l            x -= 5;\l        }\l    \"unreachable\";\l}\l"];
+    N35[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { break \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    y -= 3;\l                    x -= 5;\l                }\l            \"unreachable\";\l        }\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N8;
+    N8 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1 { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1 { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1 { break \'outer ; \"unreachable\"; }\l    if y >= 2 { return; \"unreachable\"; }\l    y -= 3;\l    x -= 5;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        y -= 3;\l        x -= 5;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        y -= 3;\l        x -= 5;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1 { break \'outer ; \"unreachable\"; }\l            if y >= 2 { return; \"unreachable\"; }\l            y -= 3;\l            x -= 5;\l        }\l    \"unreachable\";\l}\l"];
+    N14 -> N15;
+    N15 -> N16;
+    N12 -> N17;
+    N16 -> N17;
+    N17 -> N18;
+    N18 -> N19;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1 { break \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        y -= 3;\l        x -= 5;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { break \'outer ; \"unreachable\"; }\l                if y >= 2 { return; \"unreachable\"; }\l                y -= 3;\l                x -= 5;\l            }\l        \"unreachable\";\l    }\l"];
+    N22 -> N23;
+    N23 -> N24;
+    N20 -> N25;
+    N24 -> N25;
+    N25 -> N26;
+    N26 -> N27;
+    N27 -> N28;
+    N28 -> N29;
+    N29 -> N30;
+    N30 -> N31;
+    N31 -> N32;
+    N32 -> N8;
+    N9 -> N33;
+    N33 -> N34;
+    N34 -> N6;
+    N7 -> N35;
+    N35 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f21.rs b/src/test/run-make/graphviz-flowgraph/f21.rs
new file mode 100644 (file)
index 0000000..70083ed
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_break_label_21() {
+    let mut x = 15;
+    let mut y = 151;
+    'outer: loop {
+        'inner: loop {
+            if x == 1 {
+                break 'outer;
+                "unreachable";
+            }
+            if y >= 2 {
+                return;
+                "unreachable";
+            }
+            y -= 3;
+            x -= 5;
+        }
+        "unreachable";
+    }
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot
new file mode 100644 (file)
index 0000000..9ad731b
--- /dev/null
@@ -0,0 +1,77 @@
+digraph block {
+    N0[label="entry"];
+    N1[label="exit"];
+    N2[label="expr 15"];
+    N3[label="local mut x"];
+    N4[label="expr 151"];
+    N5[label="local mut y"];
+    N6[label="(dummy_node)"];
+    N7[label="expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { continue \'outer ; \"unreachable\"; }\l                if y >= 2 { return; \"unreachable\"; }\l                x -= 1;\l                y -= 3;\l            }\l        \"unreachable\";\l    }\l"];
+    N8[label="(dummy_node)"];
+    N9[label="expr \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        x -= 1;\l        y -= 3;\l    }\l"];
+    N10[label="expr x"];
+    N11[label="expr 1"];
+    N12[label="expr x == 1"];
+    N13[label="expr continue \'outer"];
+    N14[label="(dummy_node)"];
+    N15[label="expr \"unreachable\""];
+    N16[label="block { continue \'outer ; \"unreachable\"; }"];
+    N17[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"];
+    N18[label="expr y"];
+    N19[label="expr 2"];
+    N20[label="expr y >= 2"];
+    N21[label="expr return"];
+    N22[label="(dummy_node)"];
+    N23[label="expr \"unreachable\""];
+    N24[label="block { return; \"unreachable\"; }"];
+    N25[label="expr if y >= 2 { return; \"unreachable\"; }"];
+    N26[label="expr 1"];
+    N27[label="expr x"];
+    N28[label="expr x -= 1"];
+    N29[label="expr 3"];
+    N30[label="expr y"];
+    N31[label="expr y -= 3"];
+    N32[label="block {\l    if x == 1 { continue \'outer ; \"unreachable\"; }\l    if y >= 2 { return; \"unreachable\"; }\l    x -= 1;\l    y -= 3;\l}\l"];
+    N33[label="expr \"unreachable\""];
+    N34[label="block {\l    \'inner:\l        loop  {\l            if x == 1 { continue \'outer ; \"unreachable\"; }\l            if y >= 2 { return; \"unreachable\"; }\l            x -= 1;\l            y -= 3;\l        }\l    \"unreachable\";\l}\l"];
+    N35[label="expr \"unreachable\""];
+    N36[label="block {\l    let mut x = 15;\l    let mut y = 151;\l    \'outer:\l        loop  {\l            \'inner:\l                loop  {\l                    if x == 1 { continue \'outer ; \"unreachable\"; }\l                    if y >= 2 { return; \"unreachable\"; }\l                    x -= 1;\l                    y -= 3;\l                }\l            \"unreachable\";\l        }\l    \"unreachable\";\l}\l"];
+    N0 -> N2;
+    N2 -> N3;
+    N3 -> N4;
+    N4 -> N5;
+    N5 -> N6;
+    N6 -> N8;
+    N8 -> N10;
+    N10 -> N11;
+    N11 -> N12;
+    N12 -> N13;
+    N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1 { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1 { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l    if x == 1 { continue \'outer ; \"unreachable\"; }\l    if y >= 2 { return; \"unreachable\"; }\l    x -= 1;\l    y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        x -= 1;\l        y -= 3;\l    }\l,\lexiting scope_7 stmt \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        x -= 1;\l        y -= 3;\l    }\l,\lexiting scope_8 block {\l    \'inner:\l        loop  {\l            if x == 1 { continue \'outer ; \"unreachable\"; }\l            if y >= 2 { return; \"unreachable\"; }\l            x -= 1;\l            y -= 3;\l        }\l    \"unreachable\";\l}\l"];
+    N14 -> N15;
+    N15 -> N16;
+    N12 -> N17;
+    N16 -> N17;
+    N17 -> N18;
+    N18 -> N19;
+    N19 -> N20;
+    N20 -> N21;
+    N21 -> N1[label="exiting scope_0 expr \'inner:\l    loop  {\l        if x == 1 { continue \'outer ; \"unreachable\"; }\l        if y >= 2 { return; \"unreachable\"; }\l        x -= 1;\l        y -= 3;\l    }\l,\lexiting scope_1 expr \'outer:\l    loop  {\l        \'inner:\l            loop  {\l                if x == 1 { continue \'outer ; \"unreachable\"; }\l                if y >= 2 { return; \"unreachable\"; }\l                x -= 1;\l                y -= 3;\l            }\l        \"unreachable\";\l    }\l"];
+    N22 -> N23;
+    N23 -> N24;
+    N20 -> N25;
+    N24 -> N25;
+    N25 -> N26;
+    N26 -> N27;
+    N27 -> N28;
+    N28 -> N29;
+    N29 -> N30;
+    N30 -> N31;
+    N31 -> N32;
+    N32 -> N8;
+    N9 -> N33;
+    N33 -> N34;
+    N34 -> N6;
+    N7 -> N35;
+    N35 -> N36;
+    N36 -> N1;
+}
diff --git a/src/test/run-make/graphviz-flowgraph/f22.rs b/src/test/run-make/graphviz-flowgraph/f22.rs
new file mode 100644 (file)
index 0000000..b35aac9
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2014 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(unreachable_code)]
+pub fn expr_break_label_21() {
+    let mut x = 15;
+    let mut y = 151;
+    'outer: loop {
+        'inner: loop {
+            if x == 1 {
+                continue 'outer;
+                "unreachable";
+            }
+            if y >= 2 {
+                return;
+                "unreachable";
+            }
+            x -= 1;
+            y -= 3;
+        }
+        "unreachable";
+    }
+    "unreachable";
+}
index a08d6bb0bf87fdb45ea3c309e80a0be2305225bd..219eb1a3ebd459da0c14e9a4d93d91cead169934 100644 (file)
@@ -12,7 +12,7 @@
 use rand::{task_rng, Rng};
 
 use std::{char, os, str};
-use std::io::{File, Process};
+use std::io::{File, Command};
 
 // creates unicode_input_multiple_files_{main,chars}.rs, where the
 // former imports the latter. `_chars` just contains an indentifier
@@ -40,7 +40,6 @@ fn main() {
     let tmpdir = Path::new(args.get(2).as_slice());
 
     let main_file = tmpdir.join("unicode_input_multiple_files_main.rs");
-    let main_file_str = main_file.as_str().unwrap();
     {
         let _ = File::create(&main_file).unwrap()
             .write_str("mod unicode_input_multiple_files_chars;");
@@ -57,7 +56,9 @@ fn main() {
 
         // rustc is passed to us with --out-dir and -L etc., so we
         // can't exec it directly
-        let result = Process::output("sh", ["-c".to_owned(), rustc + " " + main_file_str]).unwrap();
+        let result = Command::new("sh")
+                             .arg("-c").arg(rustc + " " + main_file.as_str().unwrap())
+                             .output().unwrap();
         let err = str::from_utf8_lossy(result.error.as_slice());
 
         // positive test so that this test will be updated when the
index d56149752155161821870fe6eba580db3339b333..2bb89d7621320c2634c276c184f5d3bebbb22ed7 100644 (file)
@@ -12,7 +12,7 @@
 use rand::{task_rng, Rng};
 
 use std::{char, os, str};
-use std::io::{File, Process};
+use std::io::{File, Command};
 
 // creates a file with `fn main() { <random ident> }` and checks the
 // compiler emits a span of the appropriate length (for the
@@ -37,9 +37,7 @@ fn main() {
     let args = os::args();
     let rustc = args.get(1).as_slice();
     let tmpdir = Path::new(args.get(2).as_slice());
-
     let main_file = tmpdir.join("span_main.rs");
-    let main_file_str = main_file.as_str().unwrap();
 
     for _ in range(0, 100) {
         let n = task_rng().gen_range(3u, 20);
@@ -53,7 +51,9 @@ fn main() {
 
         // rustc is passed to us with --out-dir and -L etc., so we
         // can't exec it directly
-        let result = Process::output("sh", ["-c".to_owned(), rustc + " " + main_file_str]).unwrap();
+        let result = Command::new("sh")
+                             .arg("-c").arg(rustc + " " + main_file.as_str().unwrap())
+                             .output().unwrap();
 
         let err = str::from_utf8_lossy(result.error.as_slice());
 
index 260ce69f821d768847880cc264f7f3d795347e70..25df896ec15a12caff393dde26a9aedb00a746a0 100644 (file)
@@ -14,7 +14,7 @@
 extern crate native;
 
 use std::os;
-use std::io::process::{Process, ProcessConfig};
+use std::io::process::Command;
 use std::unstable::finally::Finally;
 use std::str;
 
@@ -48,15 +48,7 @@ fn runtest(me: &str) {
     env.push(("RUST_BACKTRACE".to_strbuf(), "1".to_strbuf()));
 
     // Make sure that the stack trace is printed
-    let env = env.iter()
-                 .map(|&(ref k, ref v)| (k.to_owned(), v.to_owned()))
-                 .collect::<Vec<_>>();
-    let mut p = Process::configure(ProcessConfig {
-        program: me,
-        args: ["fail".to_owned()],
-        env: Some(env.as_slice()),
-        .. ProcessConfig::new()
-    }).unwrap();
+    let mut p = Command::new(me).arg("fail").env(env.as_slice()).spawn().unwrap();
     let out = p.wait_with_output().unwrap();
     assert!(!out.status.success());
     let s = str::from_utf8(out.error.as_slice()).unwrap();
@@ -64,11 +56,7 @@ fn runtest(me: &str) {
             "bad output: {}", s);
 
     // Make sure the stack trace is *not* printed
-    let mut p = Process::configure(ProcessConfig {
-        program: me,
-        args: ["fail".to_owned()],
-        .. ProcessConfig::new()
-    }).unwrap();
+    let mut p = Command::new(me).arg("fail").spawn().unwrap();
     let out = p.wait_with_output().unwrap();
     assert!(!out.status.success());
     let s = str::from_utf8(out.error.as_slice()).unwrap();
@@ -76,11 +64,7 @@ fn runtest(me: &str) {
             "bad output2: {}", s);
 
     // Make sure a stack trace is printed
-    let mut p = Process::configure(ProcessConfig {
-        program: me,
-        args: ["double-fail".to_owned()],
-        .. ProcessConfig::new()
-    }).unwrap();
+    let mut p = Command::new(me).arg("double-fail").spawn().unwrap();
     let out = p.wait_with_output().unwrap();
     assert!(!out.status.success());
     let s = str::from_utf8(out.error.as_slice()).unwrap();
@@ -88,12 +72,7 @@ fn runtest(me: &str) {
             "bad output3: {}", s);
 
     // Make sure a stack trace isn't printed too many times
-    let mut p = Process::configure(ProcessConfig {
-        program: me,
-        args: ["double-fail".to_owned()],
-        env: Some(env.as_slice()),
-        .. ProcessConfig::new()
-    }).unwrap();
+    let mut p = Command::new(me).arg("double-fail").env(env.as_slice()).spawn().unwrap();
     let out = p.wait_with_output().unwrap();
     assert!(!out.status.success());
     let s = str::from_utf8(out.error.as_slice()).unwrap();
index e0e60289f9dbf805dfd32a3d89ba37146a954454..bb101140ec39351650e880b8e5b59794499e34d4 100644 (file)
@@ -26,7 +26,7 @@
 impl Logger for MyWriter {
     fn log(&mut self, record: &LogRecord) {
         let MyWriter(ref mut inner) = *self;
-        fmt::writeln(inner as &mut Writer, record.args);
+        write!(inner, "{}", record.args);
     }
 }
 
@@ -45,5 +45,7 @@ fn main() {
         debug!("debug");
         info!("info");
     });
-    assert_eq!(r.read_to_str().unwrap(), "info\n".to_owned());
+    let s = r.read_to_str().unwrap();
+    assert!(s.contains("info"));
+    assert!(!s.contains("debug"));
 }
index 874cf1233b8bb61ad5a74f8327a4f08f9e4d0f9e..fdd44740d0531021b8ec20403ae95130f850064f 100644 (file)
@@ -53,7 +53,7 @@ fn cat(in_x : uint, in_y : int, in_name: StrBuf) -> cat {
 
 impl fmt::Show for cat {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.name)
+        write!(f, "{}", self.name)
     }
 }
 
index 802417da2c2e86495b27099d0cad949760901bca..14c2a5ae6c8b6a153700957d50945f37dbedcca3 100644 (file)
@@ -8,7 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// no-pretty-expanded
+
 #![allow(unused_must_use, dead_code)]
+#![feature(macro_rules)]
 
 use std::io::MemWriter;
 
@@ -21,8 +24,9 @@ fn borrowing_writer_from_struct_and_formatting_struct_field(foo: Foo) {
     write!(foo.writer, "{}", foo.other);
 }
 
-pub fn main() {
+fn main() {
     let mut w = MemWriter::new();
     write!(&mut w as &mut Writer, "");
     write!(&mut w, ""); // should coerce
+    println!("ok");
 }
index 01a71d862b4ff9396a89b363277e5947e18ad85c..a0d4785d8d2be420b79ff024251575dfe953815e 100644 (file)
@@ -22,7 +22,7 @@
 extern crate green;
 extern crate rustuv;
 
-use std::io::Process;
+use std::io::{Process, Command};
 
 macro_rules! succeed( ($e:expr) => (
     match $e { Ok(..) => {}, Err(e) => fail!("failure: {}", e) }
@@ -36,7 +36,7 @@ mod $name {
             use std::io::timer;
             use libc;
             use std::str;
-            use std::io::process::{Process, ProcessOutput};
+            use std::io::process::Command;
             use native;
             use super::*;
 
@@ -68,14 +68,14 @@ fn start(argc: int, argv: **u8) -> int {
 
 #[cfg(unix)]
 pub fn sleeper() -> Process {
-    Process::new("sleep", ["1000".to_owned()]).unwrap()
+    Command::new("sleep").arg("1000").spawn().unwrap()
 }
 #[cfg(windows)]
 pub fn sleeper() -> Process {
     // There's a `timeout` command on windows, but it doesn't like having
     // its output piped, so instead just ping ourselves a few times with
     // gaps inbetweeen so we're sure this process is alive for awhile
-    Process::new("ping", ["127.0.0.1".to_owned(), "-n".to_owned(), "1000".to_owned()]).unwrap()
+    Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
 }
 
 iotest!(fn test_destroy_twice() {
@@ -85,7 +85,7 @@ pub fn sleeper() -> Process {
 })
 
 pub fn test_destroy_actually_kills(force: bool) {
-    use std::io::process::{Process, ProcessOutput, ExitStatus, ExitSignal};
+    use std::io::process::{Command, ProcessOutput, ExitStatus, ExitSignal};
     use std::io::timer;
     use libc;
     use std::str;
@@ -100,7 +100,7 @@ pub fn test_destroy_actually_kills(force: bool) {
     static BLOCK_COMMAND: &'static str = "cmd";
 
     // this process will stay alive indefinitely trying to read from stdin
-    let mut p = Process::new(BLOCK_COMMAND, []).unwrap();
+    let mut p = Command::new(BLOCK_COMMAND).spawn().unwrap();
 
     assert!(p.signal(0).is_ok());
 
index 59ab75ddaaf196d841caae2c25967542c1577cb9..41650b680512977c99f7c45dfaf1608558e67628 100644 (file)
@@ -36,7 +36,7 @@ struct I { a: int, b: int }
 struct Custom;
 impl fmt::Show for Custom {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "yay")
+        write!(f, "yay")
     }
 }
 
index b56847b2da0d61b5b779136f71445640ae19f137..989c09146b7d5c54fae100ea06ae3c80d37413af 100644 (file)
@@ -11,7 +11,7 @@
 extern crate libc;
 
 use std::mem;
-use std::unstable::run_in_bare_thread;
+use std::rt::thread::Thread;
 
 #[link(name = "rustrt")]
 extern {
@@ -21,10 +21,10 @@ fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t),
 
 pub fn main() {
     unsafe {
-        run_in_bare_thread(proc() {
+        Thread::start(proc() {
             let i = &100;
             rust_dbg_call(callback, mem::transmute(i));
-        });
+        }).join();
     }
 }
 
index 56d265233baf1b7bc5c904094e9b27d445e32966..ee142aa8e6dbcdd0240dd60c5ae71c970b1af0d5 100644 (file)
 
 impl fmt::Signed for A {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.buf.write("aloha".as_bytes())
+        f.write("aloha".as_bytes())
     }
 }
 impl fmt::Signed for B {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.buf.write("adios".as_bytes())
+        f.write("adios".as_bytes())
     }
 }
 
@@ -195,9 +195,9 @@ fn test_format_args() {
     let mut buf = MemWriter::new();
     {
         let w = &mut buf as &mut io::Writer;
-        format_args!(|args| { fmt::write(w, args); }, "{}", 1);
-        format_args!(|args| { fmt::write(w, args); }, "test");
-        format_args!(|args| { fmt::write(w, args); }, "{test}", test=3);
+        format_args!(|args| { write!(w, "{}", args); }, "{}", 1);
+        format_args!(|args| { write!(w, "{}", args); }, "test");
+        format_args!(|args| { write!(w, "{}", args); }, "{test}", test=3);
     }
     let s = str::from_utf8(buf.unwrap().as_slice()).unwrap().to_owned();
     t!(s, "1test3");
index 38030eb6c1fdcb72cb0a1c70ffb114795958665f..dd513547212666c51ef9303e325051a4e88b42a7 100644 (file)
@@ -18,7 +18,7 @@
 pub fn main () {
     let args = os::args();
     let args = args.as_slice();
-    if args.len() > 1 && args[1] == "child".to_owned() {
+    if args.len() > 1 && args[1].as_slice() == "child" {
         for _ in range(0, 1000) {
             println!("hello?");
         }
@@ -28,14 +28,7 @@ pub fn main () {
         return;
     }
 
-    let config = process::ProcessConfig {
-        program : args[0].as_slice(),
-        args : &["child".to_owned()],
-        stdout: process::Ignored,
-        stderr: process::Ignored,
-        .. process::ProcessConfig::new()
-    };
-
-    let mut p = process::Process::configure(config).unwrap();
-    println!("{}", p.wait());
+    let mut p = process::Command::new(args[0].as_slice());
+    p.arg("child").stdout(process::Ignored).stderr(process::Ignored);
+    println!("{}", p.spawn().unwrap().wait());
 }
index 36db5a64555b59deb0fc03b25b60cf14220cce69..36fc48432a8217693eab78cc7895d34a84c28d0f 100644 (file)
@@ -50,10 +50,8 @@ fn main() {
 fn parent(flavor: StrBuf) {
     let args = os::args();
     let args = args.as_slice();
-    let mut p = io::Process::new(args[0].as_slice(), [
-        "child".to_owned(),
-        flavor.to_owned()
-    ]).unwrap();
+    let mut p = io::process::Command::new(args[0].as_slice())
+                                     .arg("child").arg(flavor).spawn().unwrap();
     p.stdin.get_mut_ref().write_str("test1\ntest2\ntest3").unwrap();
     let out = p.wait_with_output().unwrap();
     assert!(out.status.success());
index 9405c62a184c6a61163c1d594958de64563b57e9..6aa5f6b09ecdefb9e426df4a73c2a176236de548 100644 (file)
@@ -23,7 +23,7 @@ enum object {
 
 fn lookup(table: Box<json::Object>, key: StrBuf, default: StrBuf) -> StrBuf
 {
-    match table.find(&key.to_owned()) {
+    match table.find(&key.to_strbuf()) {
         option::Some(&json::String(ref s)) => {
             (*s).to_strbuf()
         }
index 4626c0f0c787686424f4daed349740606ed10ff7..2ce3cb931e5d9772b12ab7f6ed13dedc36465bee 100644 (file)
@@ -29,7 +29,7 @@ enum square {
 
 impl fmt::Show for square {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", match *self {
+        write!(f, "{}", match *self {
           bot => { "R".to_owned() }
           wall => { "#".to_owned() }
           rock => { "*".to_owned() }
index ac2ce615fee405a06baae8ce328de30ec113f269..cdc07c026772e3bcff717ea5b00572717010c227 100644 (file)
@@ -106,7 +106,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                               .collect::<Vec<StrBuf>>();
 
         // Concatenate the lines together using a new-line.
-        write!(f.buf, "{}", lines.connect("\n"))
+        write!(f, "{}", lines.connect("\n"))
     }
 }
 
index f87c22bdb57c3d0bf2089514cba17bce176d601e..06151e498f5367f7e0e3819b0bc2486a69dd9096 100644 (file)
@@ -16,7 +16,7 @@
 #[phase(syntax, link)]
 extern crate log;
 
-use std::io::{Process, ProcessConfig};
+use std::io::Command;
 use std::os;
 use std::str;
 
@@ -30,16 +30,11 @@ fn main() {
     }
 
     let env = [("RUST_LOG".to_owned(), "debug".to_owned())];
-    let config = ProcessConfig {
-        program: args[0].as_slice(),
-        args: &["child".to_owned()],
-        env: Some(env.as_slice()),
-        ..ProcessConfig::new()
-    };
-    let p = Process::configure(config).unwrap().wait_with_output().unwrap();
+    let p = Command::new(args[0].as_slice())
+                    .arg("child").env(env.as_slice())
+                    .spawn().unwrap().wait_with_output().unwrap();
     assert!(p.status.success());
     let mut lines = str::from_utf8(p.error.as_slice()).unwrap().lines();
     assert!(lines.next().unwrap().contains("foo"));
     assert!(lines.next().unwrap().contains("bar"));
 }
-
index 30200d4cb1807cf82d60f92d0ab73e14a19a691d..7431340e413a9f78f8fd1bd5d263df722ca18ba0 100644 (file)
@@ -17,7 +17,7 @@ struct Thingy {
 
 impl fmt::Show for Thingy {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "\\{ x: {}, y: {} \\}", self.x, self.y)
+        write!(f, "\\{ x: {}, y: {} \\}", self.x, self.y)
     }
 }
 
@@ -27,7 +27,7 @@ struct PolymorphicThingy<T> {
 
 impl<T:fmt::Show> fmt::Show for PolymorphicThingy<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f.buf, "{}", self.x)
+        write!(f, "{}", self.x)
     }
 }
 
index ac3a9ef2d533089cea13c32ad362136e1f05e3f5..1566b9ed6f19c1d467e67426794bf03966b98521 100644 (file)
@@ -10,7 +10,7 @@
 
 #![feature(asm)]
 
-use std::io::Process;
+use std::io::process::Command;
 use std::os;
 use std::str;
 
@@ -40,12 +40,12 @@ fn main() {
     } else if args.len() > 1 && args[1].as_slice() == "loud" {
         loud_recurse();
     } else {
-        let silent = Process::output(args[0], ["silent".to_owned()]).unwrap();
+        let silent = Command::new(args[0].as_slice()).arg("silent").output().unwrap();
         assert!(!silent.status.success());
         let error = str::from_utf8_lossy(silent.error.as_slice());
         assert!(error.as_slice().contains("has overflowed its stack"));
 
-        let loud = Process::output(args[0], ["loud".to_owned()]).unwrap();
+        let loud = Command::new(args[0].as_slice()).arg("loud").output().unwrap();
         assert!(!loud.status.success());
         let error = str::from_utf8_lossy(silent.error.as_slice());
         assert!(error.as_slice().contains("has overflowed its stack"));
index f41f2619032bc99b60c7d83aaae841b8e0bcafbd..44ff58c151ed6a4c89184b01f1316ab0e978795c 100644 (file)
@@ -24,6 +24,7 @@
 extern crate libc;
 
 use std::io::process;
+use std::io::process::Command;
 use std::io::signal::{Listener, Interrupt};
 
 #[start]
@@ -34,19 +35,12 @@ fn start(argc: int, argv: **u8) -> int {
 fn main() {
     unsafe { libc::setsid(); }
 
-    let config = process::ProcessConfig {
-        program : "/bin/sh",
-        args: &["-c".to_owned(), "read a".to_owned()],
-        detach: true,
-        .. process::ProcessConfig::new()
-    };
-
     // we shouldn't die because of an interrupt
     let mut l = Listener::new();
     l.register(Interrupt).unwrap();
 
     // spawn the child
-    let mut p = process::Process::configure(config).unwrap();
+    let mut p = Command::new("/bin/sh").arg("-c").arg("read a").detached().spawn().unwrap();
 
     // send an interrupt to everyone in our process group
     unsafe { libc::funcs::posix88::signal::kill(0, libc::SIGINT); }
@@ -59,4 +53,3 @@ fn main() {
         process::ExitSignal(..) => fail!()
     }
 }
-
index 45af7d5de3481e6b4be3a24b880e1bf5908a4bed..5e1f9bbaf0cfd1291cc4214ef0435f600b3f762c 100644 (file)
@@ -20,8 +20,7 @@
 
 use std::io;
 use std::io::fs;
-use std::io::process::Process;
-use std::io::process::ProcessConfig;
+use std::io::Command;
 use std::os;
 use std::path::Path;
 
@@ -56,13 +55,11 @@ fn main() {
         assert!(fs::copy(&my_path, &child_path).is_ok());
 
         // run child
-        let p = Process::configure(ProcessConfig {
-            program: child_path.as_str().unwrap(),
-            args: [arg.to_owned()],
-            cwd: Some(&cwd),
-            env: Some(my_env.append_one(env).as_slice()),
-            .. ProcessConfig::new()
-        }).unwrap().wait_with_output().unwrap();
+        let p = Command::new(&child_path)
+                        .arg(arg)
+                        .cwd(&cwd)
+                        .env(my_env.append_one(env).as_slice())
+                        .spawn().unwrap().wait_with_output().unwrap();
 
         // display the output
         assert!(io::stdout().write(p.output.as_slice()).is_ok());
index a0459e6e8c1ada7d6d3f9fea5af9c2101b7543d6..174a441ace57547879e1eb2a9a441cd1b7e5cfbc 100644 (file)
@@ -21,7 +21,7 @@
 // ignore-win32
 
 use std::os;
-use std::io::process::{Process, ExitSignal, ExitStatus};
+use std::io::process::{Command, ExitSignal, ExitStatus};
 
 pub fn main() {
     let args = os::args();
@@ -30,7 +30,7 @@ pub fn main() {
         // Raise a segfault.
         unsafe { *(0 as *mut int) = 0; }
     } else {
-        let status = Process::status(args[0], ["signal".to_owned()]).unwrap();
+        let status = Command::new(args[0].as_slice()).arg("signal").status().unwrap();
         // Windows does not have signal, so we get exit status 0xC0000028 (STATUS_BAD_STACK).
         match status {
             ExitSignal(_) if cfg!(unix) => {},
@@ -39,4 +39,3 @@ pub fn main() {
         }
     }
 }
-
index 2b42e3ada542879fa083edf961c3e66ea55f0820..8e2cfa30066495e00b7241d4022bb0b4ae7da155 100644 (file)
@@ -12,7 +12,8 @@
 // doesn't die in a ball of fire, but rather it's gracefully handled.
 
 use std::os;
-use std::io::{PipeStream, Process};
+use std::io::PipeStream;
+use std::io::Command;
 
 fn test() {
     let os::Pipe { input, out } = os::pipe();
@@ -30,6 +31,7 @@ fn main() {
         return test();
     }
 
-    let mut p = Process::new(args[0], ["test".to_owned()]).unwrap();
+    let mut p = Command::new(args[0].as_slice())
+                        .arg("test").spawn().unwrap();
     assert!(p.wait().unwrap().success());
 }
index 437d6faea3854cea53a480763648168522fc7eee..387a454542adf3cb694dbcd6333b8dbf35f1184f 100644 (file)
@@ -74,6 +74,50 @@ fn test_rm_tempdir() {
     assert!(!path.exists());
 }
 
+fn test_rm_tempdir_close() {
+    let (tx, rx) = channel();
+    let f: proc():Send = proc() {
+        let tmp = TempDir::new("test_rm_tempdir").unwrap();
+        tx.send(tmp.path().clone());
+        tmp.close();
+        fail!("fail to unwind past `tmp`");
+    };
+    task::try(f);
+    let path = rx.recv();
+    assert!(!path.exists());
+
+    let tmp = TempDir::new("test_rm_tempdir").unwrap();
+    let path = tmp.path().clone();
+    let f: proc():Send = proc() {
+        let tmp = tmp;
+        tmp.close();
+        fail!("fail to unwind past `tmp`");
+    };
+    task::try(f);
+    assert!(!path.exists());
+
+    let path;
+    {
+        let f = proc() {
+            TempDir::new("test_rm_tempdir").unwrap()
+        };
+        let tmp = task::try(f).ok().expect("test_rm_tmdir");
+        path = tmp.path().clone();
+        assert!(path.exists());
+        tmp.close();
+    }
+    assert!(!path.exists());
+
+    let path;
+    {
+        let tmp = TempDir::new("test_rm_tempdir").unwrap();
+        path = tmp.unwrap();
+    }
+    assert!(path.exists());
+    fs::rmdir_recursive(&path);
+    assert!(!path.exists());
+}
+
 // Ideally these would be in std::os but then core would need
 // to depend on std
 fn recursive_mkdir_rel() {
@@ -130,6 +174,19 @@ pub fn test_rmdir_recursive_ok() {
     assert!(!root.join("bar").join("blat").exists());
 }
 
+pub fn dont_double_fail() {
+    let r: Result<(), _> = task::try(proc() {
+        let tmpdir = TempDir::new("test").unwrap();
+        // Remove the temporary directory so that TempDir sees
+        // an error on drop
+        fs::rmdir(tmpdir.path());
+        // Trigger failure. If TempDir fails *again* due to the rmdir
+        // error then the process will abort.
+        fail!();
+    });
+    assert!(r.is_err());
+}
+
 fn in_tmpdir(f: ||) {
     let tmpdir = TempDir::new("test").expect("can't make tmpdir");
     assert!(os::change_dir(tmpdir.path()));
@@ -140,8 +197,10 @@ fn in_tmpdir(f: ||) {
 pub fn main() {
     in_tmpdir(test_tempdir);
     in_tmpdir(test_rm_tempdir);
+    in_tmpdir(test_rm_tempdir_close);
     in_tmpdir(recursive_mkdir_rel);
     in_tmpdir(recursive_mkdir_dot);
     in_tmpdir(recursive_mkdir_rel_2);
     in_tmpdir(test_rmdir_recursive_ok);
+    in_tmpdir(dont_double_fail);
 }