summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-12-05 16:46:37 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-12-06 12:13:04 -0800
commit447414f00774d37d934867f5a476cf00e1f95423 (patch)
treed328aa66e62f345cb5d7c7d01c8215e8c9324e79 /src/libstd
parentb513a5a5001b850a153db12d9621d00a70ff929a (diff)
downloadrust-447414f00774d37d934867f5a476cf00e1f95423.tar.gz
rust-447414f00774d37d934867f5a476cf00e1f95423.zip
Establish 'core' library separate from 'std'.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/bitv.rs316
-rw-r--r--src/libstd/bool.rs134
-rw-r--r--src/libstd/box.rs20
-rw-r--r--src/libstd/c_vec.rs99
-rw-r--r--src/libstd/char.rs137
-rw-r--r--src/libstd/cmath.rs71
-rw-r--r--src/libstd/comm.rs184
-rw-r--r--src/libstd/ctypes.rs42
-rw-r--r--src/libstd/dbg.rs71
-rw-r--r--src/libstd/deque.rs129
-rw-r--r--src/libstd/ebml.rs175
-rw-r--r--src/libstd/either.rs89
-rw-r--r--src/libstd/extfmt.rs453
-rw-r--r--src/libstd/float.rs350
-rw-r--r--src/libstd/four.rs229
-rw-r--r--src/libstd/fs.rs391
-rw-r--r--src/libstd/fun_treemap.rs98
-rw-r--r--src/libstd/generic_os.rs99
-rw-r--r--src/libstd/getopts.rs386
-rw-r--r--src/libstd/int.rs189
-rw-r--r--src/libstd/io.rs582
-rw-r--r--src/libstd/json.rs258
-rw-r--r--src/libstd/linux_os.rs145
-rw-r--r--src/libstd/list.rs161
-rw-r--r--src/libstd/macos_os.rs153
-rw-r--r--src/libstd/map.rs336
-rw-r--r--src/libstd/math.rs387
-rw-r--r--src/libstd/math_f32.rs112
-rw-r--r--src/libstd/math_f64.rs112
-rw-r--r--src/libstd/net.rs56
-rw-r--r--src/libstd/option.rs93
-rw-r--r--src/libstd/posix_fs.rs45
-rw-r--r--src/libstd/ptr.rs52
-rw-r--r--src/libstd/rand.rs86
-rw-r--r--src/libstd/result.rs112
-rw-r--r--src/libstd/rope.rs1337
-rw-r--r--src/libstd/run_program.rs304
-rw-r--r--src/libstd/sha1.rs294
-rw-r--r--src/libstd/smallintmap.rs81
-rw-r--r--src/libstd/sort.rs166
-rw-r--r--src/libstd/std.rc138
-rw-r--r--src/libstd/str.rs961
-rw-r--r--src/libstd/sys.rs96
-rw-r--r--src/libstd/task.rs350
-rw-r--r--src/libstd/tempfile.rs23
-rw-r--r--src/libstd/term.rs107
-rw-r--r--src/libstd/test.rs353
-rw-r--r--src/libstd/time.rs30
-rw-r--r--src/libstd/treemap.rs96
-rw-r--r--src/libstd/tri.rs188
-rw-r--r--src/libstd/u32.rs27
-rw-r--r--src/libstd/u64.rs65
-rw-r--r--src/libstd/u8.rs68
-rw-r--r--src/libstd/ufind.rs51
-rw-r--r--src/libstd/uint.rs254
-rw-r--r--src/libstd/unicode.rs166
-rw-r--r--src/libstd/unsafe.rs41
-rw-r--r--src/libstd/util.rs57
-rw-r--r--src/libstd/uv.rs150
-rw-r--r--src/libstd/vec.rs835
-rw-r--r--src/libstd/win32_fs.rs35
-rw-r--r--src/libstd/win32_os.rs133
62 files changed, 12758 insertions, 0 deletions
diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs
new file mode 100644
index 00000000000..4b726703085
--- /dev/null
+++ b/src/libstd/bitv.rs
@@ -0,0 +1,316 @@
+/*
+Module: bitv
+
+Bitvectors.
+*/
+
+export t;
+export create;
+export union;
+export intersect;
+export assign;
+export clone;
+export get;
+export equal;
+export clear;
+export set_all;
+export invert;
+export difference;
+export set;
+export is_true;
+export is_false;
+export to_vec;
+export to_str;
+export eq_vec;
+
+// FIXME: With recursive object types, we could implement binary methods like
+//        union, intersection, and difference. At that point, we could write
+//        an optimizing version of this module that produces a different obj
+//        for the case where nbits <= 32.
+
+/*
+Type: t
+
+The bitvector type.
+*/
+type t = @{storage: [mutable uint], nbits: uint};
+
+
+const uint_bits: uint = 32u + (1u << 32u >> 27u);
+
+/*
+Function: create
+
+Constructs a bitvector.
+
+Parameters:
+nbits - The number of bits in the bitvector
+init - If true then the bits are initialized to 1, otherwise 0
+*/
+fn create(nbits: uint, init: bool) -> t {
+    let elt = if init { !0u } else { 0u };
+    let storage = vec::init_elt_mut::<uint>(elt, nbits / uint_bits + 1u);
+    ret @{storage: storage, nbits: nbits};
+}
+
+fn process(op: block(uint, uint) -> uint, v0: t, v1: t) -> bool {
+    let len = vec::len(v1.storage);
+    assert (vec::len(v0.storage) == len);
+    assert (v0.nbits == v1.nbits);
+    let changed = false;
+    uint::range(0u, len) {|i|
+        let w0 = v0.storage[i];
+        let w1 = v1.storage[i];
+        let w = op(w0, w1);
+        if w0 != w { changed = true; v0.storage[i] = w; }
+    };
+    ret changed;
+}
+
+
+fn lor(w0: uint, w1: uint) -> uint { ret w0 | w1; }
+
+fn union(v0: t, v1: t) -> bool { let sub = lor; ret process(sub, v0, v1); }
+
+fn land(w0: uint, w1: uint) -> uint { ret w0 & w1; }
+
+/*
+Function: intersect
+
+Calculates the intersection of two bitvectors
+
+Sets `v0` to the intersection of `v0` and `v1`
+
+Preconditions:
+
+Both bitvectors must be the same length
+
+Returns:
+
+True if `v0` was changed
+*/
+fn intersect(v0: t, v1: t) -> bool {
+    let sub = land;
+    ret process(sub, v0, v1);
+}
+
+fn right(_w0: uint, w1: uint) -> uint { ret w1; }
+
+/*
+Function: assign
+
+Assigns the value of `v1` to `v0`
+
+Preconditions:
+
+Both bitvectors must be the same length
+
+Returns:
+
+True if `v0` was changed
+*/
+fn assign(v0: t, v1: t) -> bool { let sub = right; ret process(sub, v0, v1); }
+
+/*
+Function: clone
+
+Makes a copy of a bitvector
+*/
+fn clone(v: t) -> t {
+    let storage = vec::init_elt_mut::<uint>(0u, v.nbits / uint_bits + 1u);
+    let len = vec::len(v.storage);
+    uint::range(0u, len) {|i| storage[i] = v.storage[i]; };
+    ret @{storage: storage, nbits: v.nbits};
+}
+
+/*
+Function: get
+
+Retreive the value at index `i`
+*/
+fn get(v: t, i: uint) -> bool {
+    assert (i < v.nbits);
+    let bits = uint_bits;
+    let w = i / bits;
+    let b = i % bits;
+    let x = 1u & v.storage[w] >> b;
+    ret x == 1u;
+}
+
+// FIXME: This doesn't account for the actual size of the vectors,
+// so it could end up comparing garbage bits
+/*
+Function: equal
+
+Compares two bitvectors
+
+Preconditions:
+
+Both bitvectors must be the same length
+
+Returns:
+
+True if both bitvectors contain identical elements
+*/
+fn equal(v0: t, v1: t) -> bool {
+    // FIXME: when we can break or return from inside an iterator loop,
+    //        we can eliminate this painful while-loop
+
+    let len = vec::len(v1.storage);
+    let i = 0u;
+    while i < len {
+        if v0.storage[i] != v1.storage[i] { ret false; }
+        i = i + 1u;
+    }
+    ret true;
+}
+
+/*
+Function: clear
+
+Set all bits to 0
+*/
+fn clear(v: t) {
+    uint::range(0u, vec::len(v.storage)) {|i| v.storage[i] = 0u; };
+}
+
+/*
+Function: set_all
+
+Set all bits to 1
+*/
+fn set_all(v: t) {
+    uint::range(0u, v.nbits) {|i| set(v, i, true); };
+}
+
+/*
+Function: invert
+
+Invert all bits
+*/
+fn invert(v: t) {
+    uint::range(0u, vec::len(v.storage)) {|i|
+        v.storage[i] = !v.storage[i];
+    };
+}
+
+/*
+Function: difference
+
+Calculate the difference between two bitvectors
+
+Sets each element of `v0` to the value of that element minus the element
+of `v1` at the same index.
+
+Preconditions:
+
+Both bitvectors must be the same length
+
+Returns:
+
+True if `v0` was changed
+*/
+fn difference(v0: t, v1: t) -> bool {
+    invert(v1);
+    let b = intersect(v0, v1);
+    invert(v1);
+    ret b;
+}
+
+/*
+Function: set
+
+Set the value of a bit at a given index
+
+Preconditions:
+
+`i` must be less than the length of the bitvector
+*/
+fn set(v: t, i: uint, x: bool) {
+    assert (i < v.nbits);
+    let bits = uint_bits;
+    let w = i / bits;
+    let b = i % bits;
+    let flag = 1u << b;
+    v.storage[w] = if x { v.storage[w] | flag } else { v.storage[w] & !flag };
+}
+
+
+/*
+Function: is_true
+
+Returns true if all bits are 1
+*/
+fn is_true(v: t) -> bool {
+    for i: uint in to_vec(v) { if i != 1u { ret false; } }
+    ret true;
+}
+
+
+/*
+Function: is_false
+
+Returns true if all bits are 0
+*/
+fn is_false(v: t) -> bool {
+    for i: uint in to_vec(v) { if i == 1u { ret false; } }
+    ret true;
+}
+
+fn init_to_vec(v: t, i: uint) -> uint { ret if get(v, i) { 1u } else { 0u }; }
+
+/*
+Function: to_vec
+
+Converts the bitvector to a vector of uint with the same length. Each uint
+in the resulting vector has either value 0u or 1u.
+*/
+fn to_vec(v: t) -> [uint] {
+    let sub = bind init_to_vec(v, _);
+    ret vec::init_fn::<uint>(sub, v.nbits);
+}
+
+/*
+Function: to_str
+
+Converts the bitvector to a string. The resulting string has the same
+length as the bitvector, and each character is either '0' or '1'.
+*/
+fn to_str(v: t) -> str {
+    let rs = "";
+    for i: uint in to_vec(v) { if i == 1u { rs += "1"; } else { rs += "0"; } }
+    ret rs;
+}
+
+/*
+Function: eq_vec
+
+Compare a bitvector to a vector of uint. The uint vector is expected to
+only contain the values 0u and 1u.
+
+Preconditions:
+
+Both the bitvector and vector must have the same length
+*/
+fn eq_vec(v0: t, v1: [uint]) -> bool {
+    assert (v0.nbits == vec::len::<uint>(v1));
+    let len = v0.nbits;
+    let i = 0u;
+    while i < len {
+        let w0 = get(v0, i);
+        let w1 = v1[i];
+        if !w0 && w1 != 0u || w0 && w1 == 0u { ret false; }
+        i = i + 1u;
+    }
+    ret true;
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs
new file mode 100644
index 00000000000..0fc869d1b41
--- /dev/null
+++ b/src/libstd/bool.rs
@@ -0,0 +1,134 @@
+// -*- rust -*-
+
+/*
+Module: bool
+
+Classic Boolean logic reified as ADT
+*/
+
+export t;
+export not, and, or, xor, implies;
+export eq, ne, is_true, is_false;
+export from_str, to_str, all_values, to_bit;
+
+/*
+Type: t
+
+The type of boolean logic values
+*/
+type t = bool;
+
+/* Function: not
+
+Negation/Inverse
+*/
+pure fn not(v: t) -> t { !v }
+
+/* Function: and
+
+Conjunction
+*/
+pure fn and(a: t, b: t) -> t { a && b }
+
+/* Function: or
+
+Disjunction
+*/
+pure fn or(a: t, b: t) -> t { a || b }
+
+/*
+Function: xor
+
+Exclusive or, i.e. `or(and(a, not(b)), and(not(a), b))`
+*/
+pure fn xor(a: t, b: t) -> t { (a && !b) || (!a && b) }
+
+/*
+Function: implies
+
+Implication in the logic, i.e. from `a` follows `b`
+*/
+pure fn implies(a: t, b: t) -> t { !a || b }
+
+/*
+Predicate: eq
+
+Returns:
+
+true if truth values `a` and `b` are indistinguishable in the logic
+*/
+pure fn eq(a: t, b: t) -> bool { a == b }
+
+/*
+Predicate: ne
+
+Returns:
+
+true if truth values `a` and `b` are distinguishable in the logic
+*/
+pure fn ne(a: t, b: t) -> bool { a != b }
+
+/*
+Predicate: is_true
+
+Returns:
+
+true if `v` represents truth in the logic
+*/
+pure fn is_true(v: t) -> bool { v }
+
+/*
+Predicate: is_false
+
+Returns:
+
+true if `v` represents falsehood in the logic
+*/
+pure fn is_false(v: t) -> bool { !v }
+
+/*
+Function: from_str
+
+Parse logic value from `s`
+*/
+pure fn from_str(s: str) -> t {
+    alt s {
+      "true" { true }
+      "false" { false }
+    }
+}
+
+/*
+Function: to_str
+
+Convert `v` into a string
+*/
+pure fn to_str(v: t) -> str { if v { "true" } else { "false" } }
+
+/*
+Function: all_values
+
+Iterates over all truth values by passing them to `blk`
+in an unspecified order
+*/
+fn all_values(blk: block(v: t)) {
+    blk(true);
+    blk(false);
+}
+
+/*
+Function: to_bit
+
+Returns:
+
+An u8 whose first bit is set if `if_true(v)` holds
+*/
+fn to_bit(v: t) -> u8 { if v { 1u8 } else { 0u8 } }
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/box.rs b/src/libstd/box.rs
new file mode 100644
index 00000000000..6682fe17284
--- /dev/null
+++ b/src/libstd/box.rs
@@ -0,0 +1,20 @@
+/*
+Module: box
+*/
+
+
+export ptr_eq;
+
+/*
+Function: ptr_eq
+
+Determine if two shared boxes point to the same object
+*/
+fn ptr_eq<T>(a: @T, b: @T) -> bool {
+    // FIXME: ptr::addr_of
+    unsafe {
+        let a_ptr: uint = unsafe::reinterpret_cast(a);
+        let b_ptr: uint = unsafe::reinterpret_cast(b);
+        ret a_ptr == b_ptr;
+    }
+}
diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs
new file mode 100644
index 00000000000..ff5f636d103
--- /dev/null
+++ b/src/libstd/c_vec.rs
@@ -0,0 +1,99 @@
+/*
+Module: c_vec
+
+Library to interface with chunks of memory allocated in C.
+
+It is often desirable to safely interface with memory allocated from C,
+encapsulating the unsafety into allocation and destruction time.  Indeed,
+allocating memory externally is currently the only way to give Rust shared
+mutable state with C programs that keep their own references; vectors are
+unsuitable because they could be reallocated or moved at any time, and
+importing C memory into a vector takes a one-time snapshot of the memory.
+
+This module simplifies the usage of such external blocks of memory.  Memory
+is encapsulated into an opaque object after creation; the lifecycle of the
+memory can be optionally managed by Rust, if an appropriate destructor
+closure is provided.  Safety is ensured by bounds-checking accesses, which
+are marshalled through get and set functions.
+
+There are three unsafe functions: the two introduction forms, and the
+pointer elimination form.  The introduction forms are unsafe for the obvious
+reason (they act on a pointer that cannot be checked inside the method), but
+the elimination form is somewhat more subtle in its unsafety.  By using a
+pointer taken from a c_vec::t without keeping a reference to the c_vec::t
+itself around, the c_vec could be garbage collected, and the memory within
+could be destroyed.  There are legitimate uses for the pointer elimination
+form -- for instance, to pass memory back into C -- but great care must be
+taken to ensure that a reference to the c_vec::t is still held if needed.
+
+ */
+
+export t;
+export create, create_with_dtor;
+export get, set;
+export size;
+export ptr;
+
+/*
+ Type: t
+
+ The type representing a native chunk of memory.  Wrapped in a tag for
+ opacity; FIXME #818 when it is possible to have truly opaque types, this
+ should be revisited.
+ */
+
+tag t<T> {
+    t({ base: *mutable T, size: uint, rsrc: @dtor_res});
+}
+
+resource dtor_res(dtor: option::t<fn@()>) {
+    alt dtor {
+      option::none. { }
+      option::some(f) { f(); }
+    }
+}
+
+/*
+ Section: Introduction forms
+ */
+
+unsafe fn create<T>(base: *mutable T, size: uint) -> t<T> {
+    ret t({base: base,
+           size: size,
+           rsrc: @dtor_res(option::none)
+          });
+}
+
+unsafe fn create_with_dtor<T>(base: *mutable T, size: uint, dtor: fn@())
+  -> t<T> {
+    ret t({base: base,
+           size: size,
+           rsrc: @dtor_res(option::some(dtor))
+          });
+}
+
+/*
+ Section: Operations
+ */
+
+fn get<copy T>(t: t<T>, ofs: uint) -> T {
+    assert ofs < (*t).size;
+    ret unsafe { *ptr::mut_offset((*t).base, ofs) };
+}
+
+fn set<copy T>(t: t<T>, ofs: uint, v: T) {
+    assert ofs < (*t).size;
+    unsafe { *ptr::mut_offset((*t).base, ofs) = v };
+}
+
+/*
+ Section: Elimination forms
+ */
+
+fn size<T>(t: t<T>) -> uint {
+    ret (*t).size;
+}
+
+unsafe fn ptr<T>(t: t<T>) -> *mutable T {
+    ret (*t).base;
+}
diff --git a/src/libstd/char.rs b/src/libstd/char.rs
new file mode 100644
index 00000000000..bc8e74355c6
--- /dev/null
+++ b/src/libstd/char.rs
@@ -0,0 +1,137 @@
+/*
+Module: char
+
+Utilities for manipulating the char type
+*/
+
+/*
+Function: is_whitespace
+
+Indicates whether a character is whitespace.
+
+Whitespace characters include space (U+0020), tab (U+0009), line feed
+(U+000A), carriage return (U+000D), and a number of less common
+ASCII and unicode characters.
+*/
+pure fn is_whitespace(c: char) -> bool {
+    const ch_space: char = '\u0020';
+    const ch_ogham_space_mark: char = '\u1680';
+    const ch_mongolian_vowel_sep: char = '\u180e';
+    const ch_en_quad: char = '\u2000';
+    const ch_em_quad: char = '\u2001';
+    const ch_en_space: char = '\u2002';
+    const ch_em_space: char = '\u2003';
+    const ch_three_per_em_space: char = '\u2004';
+    const ch_four_per_em_space: char = '\u2005';
+    const ch_six_per_em_space: char = '\u2006';
+    const ch_figure_space: char = '\u2007';
+    const ch_punctuation_space: char = '\u2008';
+    const ch_thin_space: char = '\u2009';
+    const ch_hair_space: char = '\u200a';
+    const ch_narrow_no_break_space: char = '\u202f';
+    const ch_medium_mathematical_space: char = '\u205f';
+    const ch_ideographic_space: char = '\u3000';
+    const ch_line_separator: char = '\u2028';
+    const ch_paragraph_separator: char = '\u2029';
+    const ch_character_tabulation: char = '\u0009';
+    const ch_line_feed: char = '\u000a';
+    const ch_line_tabulation: char = '\u000b';
+    const ch_form_feed: char = '\u000c';
+    const ch_carriage_return: char = '\u000d';
+    const ch_next_line: char = '\u0085';
+    const ch_no_break_space: char = '\u00a0';
+
+    if c == ch_space {
+        true
+    } else if c == ch_ogham_space_mark {
+        true
+    } else if c == ch_mongolian_vowel_sep {
+        true
+    } else if c == ch_en_quad {
+        true
+    } else if c == ch_em_quad {
+        true
+    } else if c == ch_en_space {
+        true
+    } else if c == ch_em_space {
+        true
+    } else if c == ch_three_per_em_space {
+        true
+    } else if c == ch_four_per_em_space {
+        true
+    } else if c == ch_six_per_em_space {
+        true
+    } else if c == ch_figure_space {
+        true
+    } else if c == ch_punctuation_space {
+        true
+    } else if c == ch_thin_space {
+        true
+    } else if c == ch_hair_space {
+        true
+    } else if c == ch_narrow_no_break_space {
+        true
+    } else if c == ch_medium_mathematical_space {
+        true
+    } else if c == ch_ideographic_space {
+        true
+    } else if c == ch_line_tabulation {
+        true
+    } else if c == ch_paragraph_separator {
+        true
+    } else if c == ch_character_tabulation {
+        true
+    } else if c == ch_line_feed {
+        true
+    } else if c == ch_line_tabulation {
+        true
+    } else if c == ch_form_feed {
+        true
+    } else if c == ch_carriage_return {
+        true
+    } else if c == ch_next_line {
+        true
+    } else if c == ch_no_break_space { true } else { false }
+}
+
+/*
+ Function: to_digit
+
+ Convert a char to the corresponding digit.
+
+ Parameters:
+   c - a char, either '0' to '9', 'a' to 'z' or 'A' to 'Z'
+
+ Returns:
+   If `c` is between '0' and '9', the corresponding value between 0 and 9.
+ If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc.
+
+ Safety note:
+   This function fails if `c` is not a valid char
+*/
+pure fn to_digit(c: char) -> u8 {
+    alt c {
+        '0' to '9' { c as u8 - ('0' as u8) }
+        'a' to 'z' { c as u8 + 10u8 - ('a' as u8) }
+        'A' to 'Z' { c as u8 + 10u8 - ('A' as u8) }
+        _ { fail; }
+    }
+}
+
+/*
+ Function: cmp
+
+ Compare two chars.
+
+ Parameters:
+  a - a char
+  b - a char
+
+ Returns:
+  -1 if a<b, 0 if a==b, +1 if a>b
+*/
+fn cmp(a: char, b: char) -> int {
+    ret  if b > a { -1 }
+    else if b < a { 1 }
+    else { 0 }
+}
\ No newline at end of file
diff --git a/src/libstd/cmath.rs b/src/libstd/cmath.rs
new file mode 100644
index 00000000000..69ecbac3e91
--- /dev/null
+++ b/src/libstd/cmath.rs
@@ -0,0 +1,71 @@
+import ctypes::c_int;
+
+#[link_name = "m"]
+#[abi = "cdecl"]
+native mod f64 {
+
+    // Alpabetically sorted by link_name
+
+    pure fn acos(n: f64) -> f64;
+    pure fn asin(n: f64) -> f64;
+    pure fn atan(n: f64) -> f64;
+    pure fn atan2(a: f64, b: f64) -> f64;
+    pure fn ceil(n: f64) -> f64;
+    pure fn cos(n: f64) -> f64;
+    pure fn cosh(n: f64) -> f64;
+    pure fn exp(n: f64) -> f64;
+    #[link_name="fabs"] pure fn abs(n: f64) -> f64;
+    pure fn floor(n: f64) -> f64;
+    pure fn fmod(x: f64, y: f64) -> f64;
+    pure fn frexp(n: f64, &value: c_int) -> f64;
+    pure fn ldexp(x: f64, n: c_int) -> f64;
+    #[link_name="log"] pure fn ln(n: f64) -> f64;
+    #[link_name="log1p"] pure fn ln1p(n: f64) -> f64;
+    pure fn log10(n: f64) -> f64;
+    pure fn log2(n: f64) -> f64;
+    pure fn modf(n: f64, &iptr: f64) -> f64;
+    pure fn pow(n: f64, e: f64) -> f64;
+    pure fn rint(n: f64) -> f64;
+    pure fn round(n: f64) -> f64;
+    pure fn sin(n: f64) -> f64;
+    pure fn sinh(n: f64) -> f64;
+    pure fn sqrt(n: f64) -> f64;
+    pure fn tan(n: f64) -> f64;
+    pure fn tanh(n: f64) -> f64;
+    pure fn trunc(n: f64) -> f64;
+}
+
+#[link_name = "m"]
+#[abi = "cdecl"]
+native mod f32 {
+
+    // Alpabetically sorted by link_name
+
+    #[link_name="acosf"] pure fn acos(n: f32) -> f32;
+    #[link_name="asinf"] pure fn asin(n: f32) -> f32;
+    #[link_name="atanf"] pure fn atan(n: f32) -> f32;
+    #[link_name="atan2f"] pure fn atan2(a: f32, b: f32) -> f32;
+    #[link_name="ceilf"] pure fn ceil(n: f32) -> f32;
+    #[link_name="cosf"] pure fn cos(n: f32) -> f32;
+    #[link_name="coshf"] pure fn cosh(n: f32) -> f32;
+    #[link_name="expf"] pure fn exp(n: f32) -> f32;
+    #[link_name="fabsf"] pure fn abs(n: f32) -> f32;
+    #[link_name="floorf"] pure fn floor(n: f32) -> f32;
+    #[link_name="frexpf"] pure fn frexp(n: f64, &value: c_int) -> f32;
+    #[link_name="fmodf"] pure fn fmod(x: f32, y: f32) -> f32;
+    #[link_name="ldexpf"] pure fn ldexp(x: f32, n: c_int) -> f32;
+    #[link_name="logf"] pure fn ln(n: f32) -> f32;
+    #[link_name="log1p"] pure fn ln1p(n: f64) -> f64;
+    #[link_name="log2f"] pure fn log2(n: f32) -> f32;
+    #[link_name="log10f"] pure fn log10(n: f32) -> f32;
+    #[link_name="modff"] pure fn modf(n: f32, &iptr: f32) -> f32;
+    #[link_name="powf"] pure fn pow(n: f32, e: f32) -> f32;
+    #[link_name="rintf"] pure fn rint(n: f32) -> f32;
+    #[link_name="roundf"] pure fn round(n: f32) -> f32;
+    #[link_name="sinf"] pure fn sin(n: f32) -> f32;
+    #[link_name="sinhf"] pure fn sinh(n: f32) -> f32;
+    #[link_name="sqrtf"] pure fn sqrt(n: f32) -> f32;
+    #[link_name="tanf"] pure fn tan(n: f32) -> f32;
+    #[link_name="tanhf"] pure fn tanh(n: f32) -> f32;
+    #[link_name="truncf"] pure fn trunc(n: f32) -> f32;
+}
diff --git a/src/libstd/comm.rs b/src/libstd/comm.rs
new file mode 100644
index 00000000000..e00205a522b
--- /dev/null
+++ b/src/libstd/comm.rs
@@ -0,0 +1,184 @@
+/*
+Module: comm
+
+Communication between tasks
+
+Communication between tasks is facilitated by ports (in the receiving task),
+and channels (in the sending task). Any number of channels may feed into a
+single port.
+
+Ports and channels may only transmit values of unique types; that is,
+values that are statically guaranteed to be accessed by a single
+'owner' at a time.  Unique types include scalars, vectors, strings,
+and records, tags, tuples and unique boxes (~T) thereof. Most notably,
+shared boxes (@T) may not be transmitted across channels.
+
+Example:
+
+> use std::{task, comm, io};
+>
+> let p = comm::port();
+> task::spawn(comm::chan(p), fn (c: chan<str>) {
+>   comm::send(c, "Hello, World");
+> });
+>
+> io::println(comm::recv(p));
+
+*/
+
+import sys;
+import task;
+
+export send;
+export recv;
+export chan;
+export port;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    type void;
+    type rust_port;
+
+    fn chan_id_send<send T>(t: *sys::type_desc,
+                            target_task: task::task, target_port: port_id,
+                            data: T) -> ctypes::uintptr_t;
+
+    fn new_port(unit_sz: uint) -> *rust_port;
+    fn del_port(po: *rust_port);
+    fn rust_port_detach(po: *rust_port);
+    fn get_port_id(po: *rust_port) -> port_id;
+    fn rust_port_size(po: *rust_port) -> ctypes::size_t;
+    fn port_recv(dptr: *uint, po: *rust_port,
+                 yield: *ctypes::uintptr_t,
+                 killed: *ctypes::uintptr_t);
+}
+
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn call_with_retptr<send T>(&&f: fn@(*uint)) -> T;
+}
+
+type port_id = int;
+
+// It's critical that this only have one variant, so it has a record
+// layout, and will work in the rust_task structure in task.rs.
+/*
+Type: chan
+
+A communication endpoint that can send messages. Channels send
+messages to ports.
+
+Each channel is bound to a port when the channel is constructed, so
+the destination port for a channel must exist before the channel
+itself.
+
+Channels are weak: a channel does not keep the port it is bound to alive.
+If a channel attempts to send data to a dead port that data will be silently
+dropped.
+
+Channels may be duplicated and themselves transmitted over other channels.
+*/
+tag chan<send T> {
+    chan_t(task::task, port_id);
+}
+
+resource port_ptr<send T>(po: *rustrt::rust_port) {
+    // Once the port is detached it's guaranteed not to receive further
+    // messages
+    rustrt::rust_port_detach(po);
+    // Drain the port so that all the still-enqueued items get dropped
+    while rustrt::rust_port_size(po) > 0u {
+        // FIXME: For some reason if we don't assign to something here
+        // we end up with invalid reads in the drop glue.
+        let _t = recv_::<T>(po);
+    }
+    rustrt::del_port(po);
+}
+
+/*
+Type: port
+
+A communication endpoint that can receive messages. Ports receive
+messages from channels.
+
+Each port has a unique per-task identity and may not be replicated or
+transmitted. If a port value is copied, both copies refer to the same port.
+
+Ports may be associated with multiple <chan>s.
+*/
+tag port<send T> { port_t(@port_ptr<T>); }
+
+/*
+Function: send
+
+Sends data over a channel.
+
+The sent data is moved into the channel, whereupon the caller loses access
+to it.
+*/
+fn send<send T>(ch: chan<T>, -data: T) {
+    let chan_t(t, p) = ch;
+    let res = rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data);
+    if res != 0u unsafe {
+        // Data sent successfully
+        unsafe::leak(data);
+    }
+    task::yield();
+}
+
+/*
+Function: port
+
+Constructs a port.
+*/
+fn port<send T>() -> port<T> {
+    port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
+}
+
+/*
+Function: recv
+
+Receive from a port.
+
+If no data is available on the port then the task will block until data
+becomes available.
+*/
+fn recv<send T>(p: port<T>) -> T { recv_(***p) }
+
+// Receive on a raw port pointer
+fn recv_<send T>(p: *rustrt::rust_port) -> T {
+    // FIXME: Due to issue 1185 we can't use a return pointer when
+    // calling C code, and since we can't create our own return
+    // pointer on the stack, we're going to call a little intrinsic
+    // that will grab the value of the return pointer, then call this
+    // function, which we will then use to call the runtime.
+    fn recv(dptr: *uint, port: *rustrt::rust_port,
+            yield: *ctypes::uintptr_t,
+            killed: *ctypes::uintptr_t) unsafe {
+        rustrt::port_recv(dptr, port, yield, killed);
+    }
+    let yield = 0u;
+    let yieldp = ptr::addr_of(yield);
+    let killed = 0u;
+    let killedp = ptr::addr_of(killed);
+    let res = rusti::call_with_retptr(bind recv(_, p, yieldp, killedp));
+    if killed != 0u {
+        fail "killed";
+    }
+    if yield != 0u {
+        // Data isn't available yet, so res has not been initialized.
+        task::yield();
+    }
+    ret res;
+}
+
+/*
+Function: chan
+
+Constructs a channel.
+
+The channel is bound to the port used to construct it.
+*/
+fn chan<send T>(p: port<T>) -> chan<T> {
+    chan_t(task::get_task(), rustrt::get_port_id(***p))
+}
diff --git a/src/libstd/ctypes.rs b/src/libstd/ctypes.rs
new file mode 100644
index 00000000000..82e414a864c
--- /dev/null
+++ b/src/libstd/ctypes.rs
@@ -0,0 +1,42 @@
+/*
+Module: ctypes
+
+Definitions useful for C interop
+*/
+
+type c_int = i32;
+type c_uint = u32;
+
+type void = int; // Not really the same as C
+type long = int;
+type unsigned = u32;
+type ulong = uint;
+
+type intptr_t = uint;
+type uintptr_t = uint;
+type uint32_t = u32;
+
+// machine type equivalents of rust int, uint, float
+
+#[cfg(target_arch="x86")]
+type m_int = i32;
+#[cfg(target_arch="x86_64")]
+type m_int = i64;
+
+#[cfg(target_arch="x86")]
+type m_uint = u32;
+#[cfg(target_arch="x86_64")]
+type m_uint = u64;
+
+// This *must* match with "import m_float = fXX" in std::math per arch
+type m_float = f64;
+
+type size_t = uint;
+type ssize_t = int;
+type off_t = uint;
+
+type fd_t = i32;      // not actually a C type, but should be.
+type pid_t = i32;
+
+// enum is implementation-defined, but is 32-bits in practice
+type enum = u32;
diff --git a/src/libstd/dbg.rs b/src/libstd/dbg.rs
new file mode 100644
index 00000000000..ea98150d76a
--- /dev/null
+++ b/src/libstd/dbg.rs
@@ -0,0 +1,71 @@
+
+
+
+/**
+ * Unsafe debugging functions for inspecting values.
+ *
+ * Your RUST_LOG environment variable must contain "stdlib" for any debug
+ * logging.
+ */
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn debug_tydesc(td: *sys::type_desc);
+    fn debug_opaque<T>(td: *sys::type_desc, x: T);
+    fn debug_box<T>(td: *sys::type_desc, x: @T);
+    fn debug_tag<T>(td: *sys::type_desc, x: T);
+    fn debug_obj<T>(td: *sys::type_desc, x: T, nmethods: uint, nbytes: uint);
+    fn debug_fn<T>(td: *sys::type_desc, x: T);
+    fn debug_ptrcast<T, U>(td: *sys::type_desc, x: @T) -> @U;
+}
+
+fn debug_tydesc<T>() {
+    rustrt::debug_tydesc(sys::get_type_desc::<T>());
+}
+
+fn debug_opaque<T>(x: T) {
+    rustrt::debug_opaque::<T>(sys::get_type_desc::<T>(), x);
+}
+
+fn debug_box<T>(x: @T) {
+    rustrt::debug_box::<T>(sys::get_type_desc::<T>(), x);
+}
+
+fn debug_tag<T>(x: T) {
+    rustrt::debug_tag::<T>(sys::get_type_desc::<T>(), x);
+}
+
+
+/**
+ * `nmethods` is the number of methods we expect the object to have.  The
+ * runtime will print this many words of the obj vtbl).
+ *
+ * `nbytes` is the number of bytes of body data we expect the object to have.
+ * The runtime will print this many bytes of the obj body.  You probably want
+ * this to at least be 4u, since an implicit captured tydesc pointer sits in
+ * the front of any obj's data tuple.x
+ */
+fn debug_obj<T>(x: T, nmethods: uint, nbytes: uint) {
+    rustrt::debug_obj::<T>(sys::get_type_desc::<T>(), x, nmethods, nbytes);
+}
+
+fn debug_fn<T>(x: T) {
+    rustrt::debug_fn::<T>(sys::get_type_desc::<T>(), x);
+}
+
+unsafe fn ptr_cast<T, U>(x: @T) -> @U {
+    ret rustrt::debug_ptrcast::<T, U>(sys::get_type_desc::<T>(), x);
+}
+
+fn refcount<T>(a: @T) -> uint unsafe {
+    let p: *uint = unsafe::reinterpret_cast(a);
+    ret *p;
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs
new file mode 100644
index 00000000000..7c0a13bb5f8
--- /dev/null
+++ b/src/libstd/deque.rs
@@ -0,0 +1,129 @@
+/*
+Module: deque
+
+A deque.  Untested as of yet.  Likely buggy.
+*/
+
+/*
+Object: t
+*/
+type t<T> = obj {
+    // Method: size
+    fn size() -> uint;
+    // Method: add_front
+    fn add_front(T);
+    // Method: add_back
+    fn add_back(T);
+    // Method: pop_front
+    fn pop_front() -> T;
+    // Method: pop_back
+    fn pop_back() -> T;
+    // Method: peek_front
+    fn peek_front() -> T;
+    // Method: peek_back
+    fn peek_back() -> T;
+    // Method: get
+    fn get(int) -> T;
+    };
+
+/*
+Section: Functions
+*/
+
+/*
+Function: create
+*/
+fn create<copy T>() -> t<T> {
+    type cell<T> = option::t<T>;
+
+    let initial_capacity: uint = 32u; // 2^5
+     /**
+      * Grow is only called on full elts, so nelts is also len(elts), unlike
+      * elsewhere.
+      */
+    fn grow<copy T>(nelts: uint, lo: uint, elts: [mutable cell<T>]) ->
+       [mutable cell<T>] {
+        assert (nelts == vec::len(elts));
+        let rv = [mutable];
+
+        let i = 0u;
+        let nalloc = uint::next_power_of_two(nelts + 1u);
+        while i < nalloc {
+            if i < nelts {
+                rv += [mutable elts[(lo + i) % nelts]];
+            } else { rv += [mutable option::none]; }
+            i += 1u;
+        }
+
+        ret rv;
+    }
+    fn get<T>(elts: [mutable cell<T>], i: uint) -> T {
+        ret alt elts[i] { option::some(t) { t } _ { fail } };
+    }
+    obj deque<copy T>(mutable nelts: uint,
+                      mutable lo: uint,
+                      mutable hi: uint,
+                      mutable elts: [mutable cell<T>]) {
+        fn size() -> uint { ret nelts; }
+        fn add_front(t: T) {
+            let oldlo: uint = lo;
+            if lo == 0u {
+                lo = vec::len::<cell<T>>(elts) - 1u;
+            } else { lo -= 1u; }
+            if lo == hi {
+                elts = grow::<T>(nelts, oldlo, elts);
+                lo = vec::len::<cell<T>>(elts) - 1u;
+                hi = nelts;
+            }
+            elts[lo] = option::some::<T>(t);
+            nelts += 1u;
+        }
+        fn add_back(t: T) {
+            if lo == hi && nelts != 0u {
+                elts = grow::<T>(nelts, lo, elts);
+                lo = 0u;
+                hi = nelts;
+            }
+            elts[hi] = option::some::<T>(t);
+            hi = (hi + 1u) % vec::len::<cell<T>>(elts);
+            nelts += 1u;
+        }
+
+        /**
+         * We actually release (turn to none()) the T we're popping so
+         * that we don't keep anyone's refcount up unexpectedly.
+         */
+        fn pop_front() -> T {
+            let t: T = get::<T>(elts, lo);
+            elts[lo] = option::none::<T>;
+            lo = (lo + 1u) % vec::len::<cell<T>>(elts);
+            nelts -= 1u;
+            ret t;
+        }
+        fn pop_back() -> T {
+            if hi == 0u {
+                hi = vec::len::<cell<T>>(elts) - 1u;
+            } else { hi -= 1u; }
+            let t: T = get::<T>(elts, hi);
+            elts[hi] = option::none::<T>;
+            nelts -= 1u;
+            ret t;
+        }
+        fn peek_front() -> T { ret get::<T>(elts, lo); }
+        fn peek_back() -> T { ret get::<T>(elts, hi - 1u); }
+        fn get(i: int) -> T {
+            let idx: uint = (lo + (i as uint)) % vec::len::<cell<T>>(elts);
+            ret get::<T>(elts, idx);
+        }
+    }
+    let v: [mutable cell<T>] =
+        vec::init_elt_mut(option::none, initial_capacity);
+    ret deque::<T>(0u, 0u, 0u, v);
+}
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs
new file mode 100644
index 00000000000..4a49dd473f4
--- /dev/null
+++ b/src/libstd/ebml.rs
@@ -0,0 +1,175 @@
+
+
+// Simple Extensible Binary Markup Language (ebml) reader and writer on a
+// cursor model. See the specification here:
+//     http://www.matroska.org/technical/specs/rfc/index.html
+import option::{some, none};
+
+type ebml_tag = {id: uint, size: uint};
+
+type ebml_state = {ebml_tag: ebml_tag, tag_pos: uint, data_pos: uint};
+
+
+// TODO: When we have module renaming, make "reader" and "writer" separate
+// modules within this file.
+
+// ebml reading
+type doc = {data: @[u8], start: uint, end: uint};
+
+fn vint_at(data: [u8], start: uint) -> {val: uint, next: uint} {
+    let a = data[start];
+    if a & 0x80u8 != 0u8 { ret {val: a & 0x7fu8 as uint, next: start + 1u}; }
+    if a & 0x40u8 != 0u8 {
+        ret {val: (a & 0x3fu8 as uint) << 8u | (data[start + 1u] as uint),
+             next: start + 2u};
+    } else if a & 0x20u8 != 0u8 {
+        ret {val:
+                 (a & 0x1fu8 as uint) << 16u |
+                     (data[start + 1u] as uint) << 8u |
+                     (data[start + 2u] as uint),
+             next: start + 3u};
+    } else if a & 0x10u8 != 0u8 {
+        ret {val:
+                 (a & 0x0fu8 as uint) << 24u |
+                     (data[start + 1u] as uint) << 16u |
+                     (data[start + 2u] as uint) << 8u |
+                     (data[start + 3u] as uint),
+             next: start + 4u};
+    } else { log_err "vint too big"; fail; }
+}
+
+fn new_doc(data: @[u8]) -> doc {
+    ret {data: data, start: 0u, end: vec::len::<u8>(*data)};
+}
+
+fn doc_at(data: @[u8], start: uint) -> doc {
+    let elt_tag = vint_at(*data, start);
+    let elt_size = vint_at(*data, elt_tag.next);
+    let end = elt_size.next + elt_size.val;
+    ret {data: data, start: elt_size.next, end: end};
+}
+
+fn maybe_get_doc(d: doc, tg: uint) -> option::t<doc> {
+    let pos = d.start;
+    while pos < d.end {
+        let elt_tag = vint_at(*d.data, pos);
+        let elt_size = vint_at(*d.data, elt_tag.next);
+        pos = elt_size.next + elt_size.val;
+        if elt_tag.val == tg {
+            ret some::<doc>({data: d.data, start: elt_size.next, end: pos});
+        }
+    }
+    ret none::<doc>;
+}
+
+fn get_doc(d: doc, tg: uint) -> doc {
+    alt maybe_get_doc(d, tg) {
+      some(d) { ret d; }
+      none. {
+        log_err "failed to find block with tag " + uint::to_str(tg, 10u);
+        fail;
+      }
+    }
+}
+
+fn docs(d: doc, it: block(uint, doc)) {
+    let pos = d.start;
+    while pos < d.end {
+        let elt_tag = vint_at(*d.data, pos);
+        let elt_size = vint_at(*d.data, elt_tag.next);
+        pos = elt_size.next + elt_size.val;
+        it(elt_tag.val, {data: d.data, start: elt_size.next, end: pos});
+    }
+}
+
+fn tagged_docs(d: doc, tg: uint, it: block(doc)) {
+    let pos = d.start;
+    while pos < d.end {
+        let elt_tag = vint_at(*d.data, pos);
+        let elt_size = vint_at(*d.data, elt_tag.next);
+        pos = elt_size.next + elt_size.val;
+        if elt_tag.val == tg {
+            it({data: d.data, start: elt_size.next, end: pos});
+        }
+    }
+}
+
+fn doc_data(d: doc) -> [u8] { ret vec::slice::<u8>(*d.data, d.start, d.end); }
+
+fn be_uint_from_bytes(data: @[u8], start: uint, size: uint) -> uint {
+    let sz = size;
+    assert (sz <= 4u);
+    let val = 0u;
+    let pos = start;
+    while sz > 0u {
+        sz -= 1u;
+        val += (data[pos] as uint) << sz * 8u;
+        pos += 1u;
+    }
+    ret val;
+}
+
+fn doc_as_uint(d: doc) -> uint {
+    ret be_uint_from_bytes(d.data, d.start, d.end - d.start);
+}
+
+
+// ebml writing
+type writer = {writer: io::buf_writer, mutable size_positions: [uint]};
+
+fn write_sized_vint(w: io::buf_writer, n: uint, size: uint) {
+    let buf: [u8];
+    alt size {
+      1u { buf = [0x80u8 | (n as u8)]; }
+      2u { buf = [0x40u8 | (n >> 8u as u8), n & 0xffu as u8]; }
+      3u {
+        buf =
+            [0x20u8 | (n >> 16u as u8), n >> 8u & 0xffu as u8,
+             n & 0xffu as u8];
+      }
+      4u {
+        buf =
+            [0x10u8 | (n >> 24u as u8), n >> 16u & 0xffu as u8,
+             n >> 8u & 0xffu as u8, n & 0xffu as u8];
+      }
+      _ { log_err "vint to write too big"; fail; }
+    }
+    w.write(buf);
+}
+
+fn write_vint(w: io::buf_writer, n: uint) {
+    if n < 0x7fu { write_sized_vint(w, n, 1u); ret; }
+    if n < 0x4000u { write_sized_vint(w, n, 2u); ret; }
+    if n < 0x200000u { write_sized_vint(w, n, 3u); ret; }
+    if n < 0x10000000u { write_sized_vint(w, n, 4u); ret; }
+    log_err "vint to write too big";
+    fail;
+}
+
+fn create_writer(w: io::buf_writer) -> writer {
+    let size_positions: [uint] = [];
+    ret {writer: w, mutable size_positions: size_positions};
+}
+
+
+// TODO: Provide a function to write the standard ebml header.
+fn start_tag(w: writer, tag_id: uint) {
+    // Write the tag ID:
+
+    write_vint(w.writer, tag_id);
+    // Write a placeholder four-byte size.
+
+    w.size_positions += [w.writer.tell()];
+    let zeroes: [u8] = [0u8, 0u8, 0u8, 0u8];
+    w.writer.write(zeroes);
+}
+
+fn end_tag(w: writer) {
+    let last_size_pos = vec::pop::<uint>(w.size_positions);
+    let cur_pos = w.writer.tell();
+    w.writer.seek(last_size_pos as int, io::seek_set);
+    write_sized_vint(w.writer, cur_pos - last_size_pos - 4u, 4u);
+    w.writer.seek(cur_pos as int, io::seek_set);
+}
+// TODO: optionally perform "relaxations" on end_tag to more efficiently
+// encode sizes; this is a fixed point iteration
diff --git a/src/libstd/either.rs b/src/libstd/either.rs
new file mode 100644
index 00000000000..89d47b20746
--- /dev/null
+++ b/src/libstd/either.rs
@@ -0,0 +1,89 @@
+/*
+Module: either
+
+A type that represents one of two alternatives
+*/
+
+
+/*
+Tag: t
+
+The either type
+*/
+tag t<T, U> {
+    /* Variant: left */
+    left(T);
+    /* Variant: right */
+    right(U);
+}
+
+/* Section: Operations */
+
+/*
+Function: either
+
+Applies a function based on the given either value
+
+If `value` is left(T) then `f_left` is applied to its contents, if
+`value` is right(U) then `f_right` is applied to its contents, and
+the result is returned.
+*/
+fn either<T, U,
+          V>(f_left: block(T) -> V, f_right: block(U) -> V, value: t<T, U>) ->
+   V {
+    alt value { left(l) { f_left(l) } right(r) { f_right(r) } }
+}
+
+/*
+Function: lefts
+
+Extracts from a vector of either all the left values.
+*/
+fn lefts<copy T, U>(eithers: [t<T, U>]) -> [T] {
+    let result: [T] = [];
+    for elt: t<T, U> in eithers {
+        alt elt { left(l) { result += [l]; } _ {/* fallthrough */ } }
+    }
+    ret result;
+}
+
+/*
+Function: rights
+
+Extracts from a vector of either all the right values
+*/
+fn rights<T, copy U>(eithers: [t<T, U>]) -> [U] {
+    let result: [U] = [];
+    for elt: t<T, U> in eithers {
+        alt elt { right(r) { result += [r]; } _ {/* fallthrough */ } }
+    }
+    ret result;
+}
+
+/*
+Function: partition
+
+Extracts from a vector of either all the left values and right values
+
+Returns a structure containing a vector of left values and a vector of
+right values.
+*/
+fn partition<copy T, copy U>(eithers: [t<T, U>])
+    -> {lefts: [T], rights: [U]} {
+    let lefts: [T] = [];
+    let rights: [U] = [];
+    for elt: t<T, U> in eithers {
+        alt elt { left(l) { lefts += [l]; } right(r) { rights += [r]; } }
+    }
+    ret {lefts: lefts, rights: rights};
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/libstd/extfmt.rs b/src/libstd/extfmt.rs
new file mode 100644
index 00000000000..14a014e891a
--- /dev/null
+++ b/src/libstd/extfmt.rs
@@ -0,0 +1,453 @@
+/*
+Syntax Extension: fmt
+
+Format a string
+
+The 'fmt' extension is modeled on the posix printf system.
+
+A posix conversion ostensibly looks like this
+
+> %[parameter][flags][width][.precision][length]type
+
+Given the different numeric type bestiary we have, we omit the 'length'
+parameter and support slightly different conversions for 'type'
+
+> %[parameter][flags][width][.precision]type
+
+we also only support translating-to-rust a tiny subset of the possible
+combinations at the moment.
+
+Example:
+
+log #fmt("hello, %s!", "world");
+
+*/
+
+import option::{some, none};
+
+
+/*
+ * We have a 'ct' (compile-time) module that parses format strings into a
+ * sequence of conversions. From those conversions AST fragments are built
+ * that call into properly-typed functions in the 'rt' (run-time) module.
+ * Each of those run-time conversion functions accepts another conversion
+ * description that specifies how to format its output.
+ *
+ * The building of the AST is currently done in a module inside the compiler,
+ * but should migrate over here as the plugin interface is defined.
+ */
+
+// Functions used by the fmt extension at compile time
+mod ct {
+    tag signedness { signed; unsigned; }
+    tag caseness { case_upper; case_lower; }
+    tag ty {
+        ty_bool;
+        ty_str;
+        ty_char;
+        ty_int(signedness);
+        ty_bits;
+        ty_hex(caseness);
+        ty_octal;
+        ty_float;
+        // FIXME: More types
+    }
+    tag flag {
+        flag_left_justify;
+        flag_left_zero_pad;
+        flag_space_for_sign;
+        flag_sign_always;
+        flag_alternate;
+    }
+    tag count {
+        count_is(int);
+        count_is_param(int);
+        count_is_next_param;
+        count_implied;
+    }
+
+    // A formatted conversion from an expression to a string
+    type conv =
+        {param: option::t<int>,
+         flags: [flag],
+         width: count,
+         precision: count,
+         ty: ty};
+
+
+    // A fragment of the output sequence
+    tag piece { piece_string(str); piece_conv(conv); }
+    type error_fn = fn@(str) -> ! ;
+
+    fn parse_fmt_string(s: str, error: error_fn) -> [piece] {
+        let pieces: [piece] = [];
+        let lim = str::byte_len(s);
+        let buf = "";
+        fn flush_buf(buf: str, &pieces: [piece]) -> str {
+            if str::byte_len(buf) > 0u {
+                let piece = piece_string(buf);
+                pieces += [piece];
+            }
+            ret "";
+        }
+        let i = 0u;
+        while i < lim {
+            let curr = str::substr(s, i, 1u);
+            if str::eq(curr, "%") {
+                i += 1u;
+                if i >= lim {
+                    error("unterminated conversion at end of string");
+                }
+                let curr2 = str::substr(s, i, 1u);
+                if str::eq(curr2, "%") {
+                    i += 1u;
+                } else {
+                    buf = flush_buf(buf, pieces);
+                    let rs = parse_conversion(s, i, lim, error);
+                    pieces += [rs.piece];
+                    i = rs.next;
+                }
+            } else { buf += curr; i += 1u; }
+        }
+        buf = flush_buf(buf, pieces);
+        ret pieces;
+    }
+    fn peek_num(s: str, i: uint, lim: uint) ->
+       option::t<{num: uint, next: uint}> {
+        if i >= lim { ret none; }
+        let c = s[i];
+        if !('0' as u8 <= c && c <= '9' as u8) { ret option::none; }
+        let n = c - ('0' as u8) as uint;
+        ret alt peek_num(s, i + 1u, lim) {
+              none. { some({num: n, next: i + 1u}) }
+              some(next) {
+                let m = next.num;
+                let j = next.next;
+                some({num: n * 10u + m, next: j})
+              }
+            };
+    }
+    fn parse_conversion(s: str, i: uint, lim: uint, error: error_fn) ->
+       {piece: piece, next: uint} {
+        let parm = parse_parameter(s, i, lim);
+        let flags = parse_flags(s, parm.next, lim);
+        let width = parse_count(s, flags.next, lim);
+        let prec = parse_precision(s, width.next, lim);
+        let ty = parse_type(s, prec.next, lim, error);
+        ret {piece:
+                 piece_conv({param: parm.param,
+                             flags: flags.flags,
+                             width: width.count,
+                             precision: prec.count,
+                             ty: ty.ty}),
+             next: ty.next};
+    }
+    fn parse_parameter(s: str, i: uint, lim: uint) ->
+       {param: option::t<int>, next: uint} {
+        if i >= lim { ret {param: none, next: i}; }
+        let num = peek_num(s, i, lim);
+        ret alt num {
+              none. { {param: none, next: i} }
+              some(t) {
+                let n = t.num;
+                let j = t.next;
+                if j < lim && s[j] == '$' as u8 {
+                    {param: some(n as int), next: j + 1u}
+                } else { {param: none, next: i} }
+              }
+            };
+    }
+    fn parse_flags(s: str, i: uint, lim: uint) ->
+       {flags: [flag], next: uint} {
+        let noflags: [flag] = [];
+        if i >= lim { ret {flags: noflags, next: i}; }
+
+        // FIXME: This recursion generates illegal instructions if the return
+        // value isn't boxed. Only started happening after the ivec conversion
+        fn more_(f: flag, s: str, i: uint, lim: uint) ->
+           @{flags: [flag], next: uint} {
+            let next = parse_flags(s, i + 1u, lim);
+            let rest = next.flags;
+            let j = next.next;
+            let curr: [flag] = [f];
+            ret @{flags: curr + rest, next: j};
+        }
+        let more = bind more_(_, s, i, lim);
+        let f = s[i];
+        ret if f == '-' as u8 {
+                *more(flag_left_justify)
+            } else if f == '0' as u8 {
+                *more(flag_left_zero_pad)
+            } else if f == ' ' as u8 {
+                *more(flag_space_for_sign)
+            } else if f == '+' as u8 {
+                *more(flag_sign_always)
+            } else if f == '#' as u8 {
+                *more(flag_alternate)
+            } else { {flags: noflags, next: i} };
+    }
+    fn parse_count(s: str, i: uint, lim: uint) -> {count: count, next: uint} {
+        ret if i >= lim {
+                {count: count_implied, next: i}
+            } else if s[i] == '*' as u8 {
+                let param = parse_parameter(s, i + 1u, lim);
+                let j = param.next;
+                alt param.param {
+                  none. { {count: count_is_next_param, next: j} }
+                  some(n) { {count: count_is_param(n), next: j} }
+                }
+            } else {
+                let num = peek_num(s, i, lim);
+                alt num {
+                  none. { {count: count_implied, next: i} }
+                  some(num) {
+                    {count: count_is(num.num as int), next: num.next}
+                  }
+                }
+            };
+    }
+    fn parse_precision(s: str, i: uint, lim: uint) ->
+       {count: count, next: uint} {
+        ret if i >= lim {
+                {count: count_implied, next: i}
+            } else if s[i] == '.' as u8 {
+                let count = parse_count(s, i + 1u, lim);
+
+
+                // If there were no digits specified, i.e. the precision
+                // was ".", then the precision is 0
+                alt count.count {
+                  count_implied. { {count: count_is(0), next: count.next} }
+                  _ { count }
+                }
+            } else { {count: count_implied, next: i} };
+    }
+    fn parse_type(s: str, i: uint, lim: uint, error: error_fn) ->
+       {ty: ty, next: uint} {
+        if i >= lim { error("missing type in conversion"); }
+        let tstr = str::substr(s, i, 1u);
+        // TODO: Do we really want two signed types here?
+        // How important is it to be printf compatible?
+        let t =
+            if str::eq(tstr, "b") {
+                ty_bool
+            } else if str::eq(tstr, "s") {
+                ty_str
+            } else if str::eq(tstr, "c") {
+                ty_char
+            } else if str::eq(tstr, "d") || str::eq(tstr, "i") {
+                ty_int(signed)
+            } else if str::eq(tstr, "u") {
+                ty_int(unsigned)
+            } else if str::eq(tstr, "x") {
+                ty_hex(case_lower)
+            } else if str::eq(tstr, "X") {
+                ty_hex(case_upper)
+            } else if str::eq(tstr, "t") {
+                ty_bits
+            } else if str::eq(tstr, "o") {
+                ty_octal
+            } else if str::eq(tstr, "f") {
+                ty_float
+            } else { error("unknown type in conversion: " + tstr) };
+        ret {ty: t, next: i + 1u};
+    }
+}
+
+
+// Functions used by the fmt extension at runtime. For now there are a lot of
+// decisions made a runtime. If it proves worthwhile then some of these
+// conditions can be evaluated at compile-time. For now though it's cleaner to
+// implement it this way, I think.
+mod rt {
+    tag flag {
+        flag_left_justify;
+        flag_left_zero_pad;
+        flag_space_for_sign;
+        flag_sign_always;
+        flag_alternate;
+
+
+        // FIXME: This is a hack to avoid creating 0-length vec exprs,
+        // which have some difficulty typechecking currently. See
+        // comments in front::extfmt::make_flags
+        flag_none;
+    }
+    tag count { count_is(int); count_implied; }
+    tag ty { ty_default; ty_bits; ty_hex_upper; ty_hex_lower; ty_octal; }
+
+    // FIXME: May not want to use a vector here for flags;
+    // instead just use a bool per flag
+    type conv = {flags: [flag], width: count, precision: count, ty: ty};
+
+    fn conv_int(cv: conv, i: int) -> str {
+        let radix = 10u;
+        let prec = get_int_precision(cv);
+        let s = int_to_str_prec(i, radix, prec);
+        if 0 <= i {
+            if have_flag(cv.flags, flag_sign_always) {
+                s = "+" + s;
+            } else if have_flag(cv.flags, flag_space_for_sign) {
+                s = " " + s;
+            }
+        }
+        ret pad(cv, s, pad_signed);
+    }
+    fn conv_uint(cv: conv, u: uint) -> str {
+        let prec = get_int_precision(cv);
+        let rs =
+            alt cv.ty {
+              ty_default. { uint_to_str_prec(u, 10u, prec) }
+              ty_hex_lower. { uint_to_str_prec(u, 16u, prec) }
+              ty_hex_upper. { str::to_upper(uint_to_str_prec(u, 16u, prec)) }
+              ty_bits. { uint_to_str_prec(u, 2u, prec) }
+              ty_octal. { uint_to_str_prec(u, 8u, prec) }
+            };
+        ret pad(cv, rs, pad_unsigned);
+    }
+    fn conv_bool(cv: conv, b: bool) -> str {
+        let s = if b { "true" } else { "false" };
+        // run the boolean conversion through the string conversion logic,
+        // giving it the same rules for precision, etc.
+
+        ret conv_str(cv, s);
+    }
+    fn conv_char(cv: conv, c: char) -> str {
+        ret pad(cv, str::from_char(c), pad_nozero);
+    }
+    fn conv_str(cv: conv, s: str) -> str {
+        // For strings, precision is the maximum characters
+        // displayed
+
+        // FIXME: substr works on bytes, not chars!
+        let unpadded =
+            alt cv.precision {
+              count_implied. { s }
+              count_is(max) {
+                if max as uint < str::char_len(s) {
+                    str::substr(s, 0u, max as uint)
+                } else { s }
+              }
+            };
+        ret pad(cv, unpadded, pad_nozero);
+    }
+    fn conv_float(cv: conv, f: float) -> str {
+        let (to_str, digits) = alt cv.precision {
+              count_is(c) { (float::to_str_exact, c as uint) }
+              count_implied. { (float::to_str, 6u) }
+        };
+        let s = to_str(f, digits);
+        if 0.0 <= f {
+            if have_flag(cv.flags, flag_sign_always) {
+                s = "+" + s;
+            } else if have_flag(cv.flags, flag_space_for_sign) {
+                s = " " + s;
+            }
+        }
+        ret pad(cv, s, pad_signed);
+    }
+
+    // Convert an int to string with minimum number of digits. If precision is
+    // 0 and num is 0 then the result is the empty string.
+    fn int_to_str_prec(num: int, radix: uint, prec: uint) -> str {
+        ret if num < 0 {
+                "-" + uint_to_str_prec(-num as uint, radix, prec)
+            } else { uint_to_str_prec(num as uint, radix, prec) };
+    }
+
+    // Convert a uint to string with a minimum number of digits.  If precision
+    // is 0 and num is 0 then the result is the empty string. Could move this
+    // to uint: but it doesn't seem all that useful.
+    fn uint_to_str_prec(num: uint, radix: uint, prec: uint) -> str {
+        ret if prec == 0u && num == 0u {
+                ""
+            } else {
+                let s = uint::to_str(num, radix);
+                let len = str::char_len(s);
+                if len < prec {
+                    let diff = prec - len;
+                    let pad = str_init_elt('0', diff);
+                    pad + s
+                } else { s }
+            };
+    }
+    fn get_int_precision(cv: conv) -> uint {
+        ret alt cv.precision {
+              count_is(c) { c as uint }
+              count_implied. { 1u }
+            };
+    }
+
+    // FIXME: This might be useful in str: but needs to be utf8 safe first
+    fn str_init_elt(c: char, n_elts: uint) -> str {
+        let svec = vec::init_elt::<u8>(c as u8, n_elts);
+
+        ret str::unsafe_from_bytes(svec);
+    }
+    tag pad_mode { pad_signed; pad_unsigned; pad_nozero; }
+    fn pad(cv: conv, s: str, mode: pad_mode) -> str {
+        let uwidth;
+        alt cv.width {
+          count_implied. { ret s; }
+          count_is(width) {
+            // FIXME: Maybe width should be uint
+
+            uwidth = width as uint;
+          }
+        }
+        let strlen = str::char_len(s);
+        if uwidth <= strlen { ret s; }
+        let padchar = ' ';
+        let diff = uwidth - strlen;
+        if have_flag(cv.flags, flag_left_justify) {
+            let padstr = str_init_elt(padchar, diff);
+            ret s + padstr;
+        }
+        let might_zero_pad = false;
+        let signed = false;
+        alt mode {
+          pad_nozero. {
+            // fallthrough
+
+          }
+          pad_signed. { might_zero_pad = true; signed = true; }
+          pad_unsigned. { might_zero_pad = true; }
+        }
+        fn have_precision(cv: conv) -> bool {
+            ret alt cv.precision { count_implied. { false } _ { true } };
+        }
+        let zero_padding = false;
+        if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
+               !have_precision(cv) {
+            padchar = '0';
+            zero_padding = true;
+        }
+        let padstr = str_init_elt(padchar, diff);
+        // This is completely heinous. If we have a signed value then
+        // potentially rip apart the intermediate result and insert some
+        // zeros. It may make sense to convert zero padding to a precision
+        // instead.
+
+        if signed && zero_padding && str::byte_len(s) > 0u {
+            let head = s[0];
+            if head == '+' as u8 || head == '-' as u8 || head == ' ' as u8 {
+                let headstr = str::unsafe_from_bytes([head]);
+                let bytelen = str::byte_len(s);
+                let numpart = str::substr(s, 1u, bytelen - 1u);
+                ret headstr + padstr + numpart;
+            }
+        }
+        ret padstr + s;
+    }
+    fn have_flag(flags: [flag], f: flag) -> bool {
+        for candidate: flag in flags { if candidate == f { ret true; } }
+        ret false;
+    }
+}
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/float.rs b/src/libstd/float.rs
new file mode 100644
index 00000000000..f916e97bbf8
--- /dev/null
+++ b/src/libstd/float.rs
@@ -0,0 +1,350 @@
+/*
+Module: float
+*/
+
+/**
+ * Section: String Conversions
+ */
+
+/*
+Function: to_str_common
+
+Converts a float to a string
+
+Parameters:
+
+num - The float value
+digits - The number of significant digits
+exact - Whether to enforce the exact number of significant digits
+*/
+fn to_str_common(num: float, digits: uint, exact: bool) -> str {
+    let (num, accum) = num < 0.0 ? (-num, "-") : (num, "");
+    let trunc = num as uint;
+    let frac = num - (trunc as float);
+    accum += uint::str(trunc);
+    if frac == 0.0 || digits == 0u { ret accum; }
+    accum += ".";
+    let i = digits;
+    let epsilon = 1. / pow_uint_to_uint_as_float(10u, i);
+    while i > 0u && (frac >= epsilon || exact) {
+        frac *= 10.0;
+        epsilon *= 10.0;
+        let digit = frac as uint;
+        accum += uint::str(digit);
+        frac -= digit as float;
+        i -= 1u;
+    }
+    ret accum;
+
+}
+
+/*
+Function: to_str
+
+Converts a float to a string with exactly the number of provided significant
+digits
+
+Parameters:
+
+num - The float value
+digits - The number of significant digits
+*/
+fn to_str_exact(num: float, digits: uint) -> str {
+    to_str_common(num, digits, true)
+}
+
+/*
+Function: to_str
+
+Converts a float to a string with a maximum number of significant digits
+
+Parameters:
+
+num - The float value
+digits - The number of significant digits
+*/
+fn to_str(num: float, digits: uint) -> str {
+    to_str_common(num, digits, false)
+}
+
+/*
+Function: from_str
+
+Convert a string to a float
+
+This function accepts strings such as
+* "3.14"
+* "+3.14", equivalent to "3.14"
+* "-3.14"
+* "2.5E10", or equivalently, "2.5e10"
+* "2.5E-10"
+* "", or, equivalently, "." (understood as 0)
+* "5."
+* ".5", or, equivalently,  "0.5"
+
+Leading and trailing whitespace are ignored.
+
+Parameters:
+
+num - A string, possibly empty.
+
+Returns:
+
+<NaN> If the string did not represent a valid number.
+Otherwise, the floating-point number represented [num].
+*/
+fn from_str(num: str) -> float {
+   let num = str::trim(num);
+
+   let pos = 0u;                  //Current byte position in the string.
+                                  //Used to walk the string in O(n).
+   let len = str::byte_len(num);  //Length of the string, in bytes.
+
+   if len == 0u { ret 0.; }
+   let total = 0f;                //Accumulated result
+   let c     = 'z';               //Latest char.
+
+   //The string must start with one of the following characters.
+   alt str::char_at(num, 0u) {
+      '-' | '+' | '0' to '9' | '.' {}
+      _ { ret NaN; }
+   }
+
+   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
+   let neg = false;               //Sign of the result
+   alt str::char_at(num, 0u) {
+      '-' {
+          neg = true;
+          pos = 1u;
+      }
+      '+' {
+          pos = 1u;
+      }
+      _ {}
+   }
+
+   //Examine the following chars until '.', 'e', 'E'
+   while(pos < len) {
+       let char_range = str::char_range_at(num, pos);
+       c   = char_range.ch;
+       pos = char_range.next;
+       alt c {
+         '0' to '9' {
+           total = total * 10f;
+           total += ((c as int) - ('0' as int)) as float;
+         }
+         '.' | 'e' | 'E' {
+           break;
+         }
+         _ {
+           ret NaN;
+         }
+       }
+   }
+
+   if c == '.' {//Examine decimal part
+      let decimal = 1.f;
+      while(pos < len) {
+         let char_range = str::char_range_at(num, pos);
+         c = char_range.ch;
+         pos = char_range.next;
+         alt c {
+            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  {
+                 decimal /= 10.f;
+                 total += (((c as int) - ('0' as int)) as float)*decimal;
+             }
+             'e' | 'E' {
+                 break;
+             }
+             _ {
+                 ret NaN;
+             }
+         }
+      }
+   }
+
+   if (c == 'e') | (c == 'E') {//Examine exponent
+      let exponent = 0u;
+      let neg_exponent = false;
+      if(pos < len) {
+          let char_range = str::char_range_at(num, pos);
+          c   = char_range.ch;
+          alt c  {
+             '+' {
+                pos = char_range.next;
+             }
+             '-' {
+                pos = char_range.next;
+                neg_exponent = true;
+             }
+             _ {}
+          }
+          while(pos < len) {
+             let char_range = str::char_range_at(num, pos);
+             c = char_range.ch;
+             alt c {
+                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
+                     exponent *= 10u;
+                     exponent += ((c as uint) - ('0' as uint));
+                 }
+                 _ {
+                     break;
+                 }
+             }
+             pos = char_range.next;
+          }
+          let multiplier = pow_uint_to_uint_as_float(10u, exponent);
+              //Note: not [int::pow], otherwise, we'll quickly
+              //end up with a nice overflow
+          if neg_exponent {
+             total = total / multiplier;
+          } else {
+             total = total * multiplier;
+          }
+      } else {
+         ret NaN;
+      }
+   }
+
+   if(pos < len) {
+     ret NaN;
+   } else {
+     if(neg) {
+        total *= -1f;
+     }
+     ret total;
+   }
+}
+
+/**
+ * Section: Arithmetics
+ */
+
+/*
+Function: pow_uint_to_uint_as_float
+
+Compute the exponentiation of an integer by another integer as a float.
+
+Parameters:
+x - The base.
+pow - The exponent.
+
+Returns:
+<NaN> of both `x` and `pow` are `0u`, otherwise `x^pow`.
+*/
+fn pow_uint_to_uint_as_float(x: uint, pow: uint) -> float {
+   if x == 0u {
+      if pow == 0u {
+        ret NaN;
+      }
+       ret 0.;
+   }
+   let my_pow     = pow;
+   let total      = 1f;
+   let multiplier = x as float;
+   while (my_pow > 0u) {
+     if my_pow % 2u == 1u {
+       total = total * multiplier;
+     }
+     my_pow     /= 2u;
+     multiplier *= multiplier;
+   }
+   ret total;
+}
+
+
+/**
+ * Section: Constants
+ */
+
+//TODO: Once this is possible, replace the body of these functions
+//by an actual constant.
+
+/* Const: NaN */
+const NaN: float = 0./0.;
+
+/* Predicate: isNaN */
+pure fn isNaN(f: float) -> bool { f != f }
+
+/* Const: infinity */
+const infinity: float = 1./0.;
+
+/* Const: neg_infinity */
+const neg_infinity: float = -1./0.;
+
+/* Function: add */
+pure fn add(x: float, y: float) -> float { ret x + y; }
+
+/* Function: sub */
+pure fn sub(x: float, y: float) -> float { ret x - y; }
+
+/* Function: mul */
+pure fn mul(x: float, y: float) -> float { ret x * y; }
+
+/* Function: div */
+pure fn div(x: float, y: float) -> float { ret x / y; }
+
+/* Function: rem */
+pure fn rem(x: float, y: float) -> float { ret x % y; }
+
+/* Predicate: lt */
+pure fn lt(x: float, y: float) -> bool { ret x < y; }
+
+/* Predicate: le */
+pure fn le(x: float, y: float) -> bool { ret x <= y; }
+
+/* Predicate: eq */
+pure fn eq(x: float, y: float) -> bool { ret x == y; }
+
+/* Predicate: ne */
+pure fn ne(x: float, y: float) -> bool { ret x != y; }
+
+/* Predicate: ge */
+pure fn ge(x: float, y: float) -> bool { ret x >= y; }
+
+/* Predicate: gt */
+pure fn gt(x: float, y: float) -> bool { ret x > y; }
+
+/*
+Predicate: positive
+
+Returns true if `x` is a positive number, including +0.0 and +Infinity.
+ */
+pure fn positive(x: float) -> bool { ret x > 0. || (1./x) == infinity; }
+
+/*
+Predicate: negative
+
+Returns true if `x` is a negative number, including -0.0 and -Infinity.
+ */
+pure fn negative(x: float) -> bool { ret x < 0. || (1./x) == neg_infinity; }
+
+/*
+Predicate: nonpositive
+
+Returns true if `x` is a negative number, including -0.0 and -Infinity.
+(This is the same as `float::negative`.)
+*/
+pure fn nonpositive(x: float) -> bool {
+  ret x < 0. || (1./x) == neg_infinity;
+}
+
+/*
+Predicate: nonnegative
+
+Returns true if `x` is a positive number, including +0.0 and +Infinity.
+(This is the same as `float::positive`.)
+*/
+pure fn nonnegative(x: float) -> bool {
+  ret x > 0. || (1./x) == infinity;
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/libstd/four.rs b/src/libstd/four.rs
new file mode 100644
index 00000000000..11c42fb7018
--- /dev/null
+++ b/src/libstd/four.rs
@@ -0,0 +1,229 @@
+// -*- rust -*-
+
+/*
+Module: four
+
+The fourrternary Belnap relevance logic FOUR represented as ADT
+
+This allows reasoning with four logic values (true, false, none, both).
+
+Implementation: Truth values are represented using a single u8 and
+all operations are done using bit operations which is fast
+on current cpus.
+*/
+
+import tri;
+
+export t, none, true, false, both;
+export not, and, or, xor, implies, implies_materially;
+export eq, ne, is_true, is_false;
+export from_str, to_str, all_values, to_trit, to_bit;
+
+/*
+Type: t
+
+The type of fourrternary logic values
+
+It may be thought of as  tuple `(y, x)` of two bools
+
+*/
+type t = u8;
+
+const b0: u8  = 1u8;
+const b1: u8  = 2u8;
+const b01: u8 = 3u8;
+
+/*
+Constant: none
+
+Logic value `(0, 0)` for bottom (neither true or false)
+*/
+const none: t  = 0u8;
+
+/*
+Constant: true
+
+Logic value `(0, 1)` for truth
+*/
+const true: t  = 1u8;
+
+/*
+Constant: false
+
+Logic value `(1, 0)` for falsehood
+*/
+const false: t = 2u8;
+
+/*
+Constant: both
+
+Logic value `(1, 1)` for top (both true and false)
+*/
+const both: t  = 3u8;
+
+/* Function: not
+
+Negation/Inverse
+
+Returns:
+
+`'(v.y, v.x)`
+*/
+pure fn not(v: t) -> t { ((v << 1u8) | (v >> 1u8)) & b01 }
+
+/* Function: and
+
+Conjunction
+
+Returns:
+
+`(a.x | b.x, a.y & b.y)`
+*/
+pure fn and(a: t, b: t) -> t { ((a & b) & b0) | ((a | b) & b1) }
+
+/* Function: or
+
+Disjunction
+
+Returns:
+
+`(a.x & b.x, a.y | b.y)`
+*/
+pure fn or(a: t, b: t) -> t { ((a | b) & b0) | ((a & b) & b1) }
+
+/* Function: xor
+
+Classic exclusive or
+
+Returns:
+
+`or(and(a, not(b)), and(not(a), b))`
+*/
+pure fn xor(a: t, b: t) -> t { or(and(a, not(b)), and(not(a), b)) }
+
+/*
+Function: implies
+
+Strong implication (from `a` strongly follows `b`)
+
+Returns:
+
+`( x1 & y2, !x1 | x2)`
+*/
+pure fn implies(a: t, b: t) -> t { ((a << 1u8) & b & b1) | (((!a) | b) & b0) }
+
+/*
+Function: implies_materially
+
+Classic (material) implication in the logic
+(from `a` materially follows `b`)
+
+Returns:
+
+`or(not(a), b)`
+*/
+pure fn implies_materially(a: t, b: t) -> t { or(not(a), b) }
+
+/*
+Predicate: eq
+
+Returns:
+
+true if truth values `a` and `b` are indistinguishable in the logic
+*/
+pure fn eq(a: t, b: t) -> bool { a == b }
+
+/*
+Predicate: ne
+
+Returns:
+
+true if truth values `a` and `b` are distinguishable in the logic
+*/
+pure fn ne(a: t, b: t) -> bool { a != b }
+
+/*
+Predicate: is_true
+
+Returns:
+
+true if `v` represents truth in the logic (is `true` or `both`)
+*/
+pure fn is_true(v: t) -> bool { (v & b0) != 0u8 }
+
+/*
+Predicate: is_false
+
+Returns:
+
+true if `v` represents falsehood in the logic (is `false` or `none`)
+*/
+pure fn is_false(v: t) -> bool { (v & b0) == 0u8 }
+
+/*
+Function: from_str
+
+Parse logic value from `s`
+*/
+pure fn from_str(s: str) -> t {
+    alt s {
+      "none" { none }
+      "false" { four::false }
+      "true" { four::true }
+      "both" { both }
+    }
+}
+
+/*
+Function: to_str
+
+Convert `v` into a string
+*/
+pure fn to_str(v: t) -> str {
+    // FIXME replace with consts as soon as that works
+    alt v {
+      0u8 { "none" }
+      1u8 { "true" }
+      2u8 { "false" }
+      3u8 { "both" }
+    }
+}
+
+/*
+Function: all_values
+
+Iterates over all truth values by passing them to `blk`
+in an unspecified order
+*/
+fn all_values(blk: block(v: t)) {
+    blk(both);
+    blk(four::true);
+    blk(four::false);
+    blk(none);
+}
+
+/*
+Function: to_bit
+
+Returns:
+
+An u8 whose first bit is set if `if_true(v)` holds
+*/
+fn to_bit(v: t) -> u8 { v & b0 }
+
+/*
+Function: to_tri
+
+Returns:
+
+A trit of `v` (`both` and `none` are both coalesced into `trit::unknown`)
+*/
+fn to_trit(v: t) -> tri::t { v & (v ^ not(v)) }
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
new file mode 100644
index 00000000000..fcd95040ab0
--- /dev/null
+++ b/src/libstd/fs.rs
@@ -0,0 +1,391 @@
+/*
+Module: fs
+
+File system manipulation
+*/
+
+import os;
+import os::getcwd;
+import os_fs;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_file_is_dir(path: str::sbuf) -> int;
+}
+
+/*
+Function: path_sep
+
+Get the default path separator for the host platform
+*/
+fn path_sep() -> str { ret str::from_char(os_fs::path_sep); }
+
+// FIXME: This type should probably be constrained
+/*
+Type: path
+
+A path or fragment of a filesystem path
+*/
+type path = str;
+
+/*
+Function: dirname
+
+Get the directory portion of a path
+
+Returns all of the path up to, but excluding, the final path separator.
+The dirname of "/usr/share" will be "/usr", but the dirname of
+"/usr/share/" is "/usr/share".
+
+If the path is not prefixed with a directory, then "." is returned.
+*/
+fn dirname(p: path) -> path {
+    let i: int = str::rindex(p, os_fs::path_sep as u8);
+    if i == -1 {
+        i = str::rindex(p, os_fs::alt_path_sep as u8);
+        if i == -1 { ret "."; }
+    }
+    ret str::substr(p, 0u, i as uint);
+}
+
+/*
+Function: basename
+
+Get the file name portion of a path
+
+Returns the portion of the path after the final path separator.
+The basename of "/usr/share" will be "share". If there are no
+path separators in the path then the returned path is identical to
+the provided path. If an empty path is provided or the path ends
+with a path separator then an empty path is returned.
+*/
+fn basename(p: path) -> path {
+    let i: int = str::rindex(p, os_fs::path_sep as u8);
+    if i == -1 {
+        i = str::rindex(p, os_fs::alt_path_sep as u8);
+        if i == -1 { ret p; }
+    }
+    let len = str::byte_len(p);
+    if i + 1 as uint >= len { ret p; }
+    ret str::slice(p, i + 1 as uint, len);
+}
+
+
+// FIXME: Need some typestate to avoid bounds check when len(pre) == 0
+/*
+Function: connect
+
+Connects to path segments
+
+Given paths `pre` and `post` this function will return a path
+that is equal to `post` appended to `pre`, inserting a path separator
+between the two as needed.
+*/
+fn connect(pre: path, post: path) -> path {
+    let len = str::byte_len(pre);
+    ret if pre[len - 1u] == os_fs::path_sep as u8 {
+
+            // Trailing '/'?
+            pre + post
+        } else { pre + path_sep() + post };
+}
+
+/*
+Function: connect_many
+
+Connects a vector of path segments into a single path.
+
+Inserts path separators as needed.
+*/
+fn connect_many(paths: [path]) : vec::is_not_empty(paths) -> path {
+    ret if vec::len(paths) == 1u {
+        paths[0]
+    } else {
+        let rest = vec::slice(paths, 1u, vec::len(paths));
+        check vec::is_not_empty(rest);
+        connect(paths[0], connect_many(rest))
+    }
+}
+
+/*
+Function: file_id_dir
+
+Indicates whether a path represents a directory.
+*/
+fn file_is_dir(p: path) -> bool {
+    ret str::as_buf(p, {|buf| rustrt::rust_file_is_dir(buf) != 0 });
+}
+
+/*
+Function: make_dir
+
+Creates a directory at the specified path.
+*/
+fn make_dir(p: path, mode: ctypes::c_int) -> bool {
+    ret mkdir(p, mode);
+
+    #[cfg(target_os = "win32")]
+    fn mkdir(_p: path, _mode: ctypes::c_int) -> bool unsafe {
+        // FIXME: turn mode into something useful?
+        ret str::as_buf(_p, {|buf|
+            os::kernel32::CreateDirectoryA(
+                buf, unsafe::reinterpret_cast(0))
+        });
+    }
+
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    fn mkdir(_p: path, _mode: ctypes::c_int) -> bool {
+        ret str::as_buf(_p, {|buf| os::libc::mkdir(buf, _mode) == 0i32 });
+    }
+}
+
+/*
+Function: list_dir
+
+Lists the contents of a directory.
+*/
+fn list_dir(p: path) -> [str] {
+    let p = p;
+    let pl = str::byte_len(p);
+    if pl == 0u || p[pl - 1u] as char != os_fs::path_sep { p += path_sep(); }
+    let full_paths: [str] = [];
+    for filename: str in os_fs::list_dir(p) {
+        if !str::eq(filename, ".") {
+            if !str::eq(filename, "..") { full_paths += [p + filename]; }
+        }
+    }
+    ret full_paths;
+}
+
+/*
+Function: remove_dir
+
+Removes a directory at the specified path.
+*/
+fn remove_dir(p: path) -> bool {
+   ret rmdir(p);
+
+    #[cfg(target_os = "win32")]
+    fn rmdir(_p: path) -> bool {
+        ret str::as_buf(_p, {|buf| os::kernel32::RemoveDirectoryA(buf)});
+    }
+
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    fn rmdir(_p: path) -> bool {
+        ret str::as_buf(_p, {|buf| os::libc::rmdir(buf) == 0i32 });
+    }
+}
+
+fn change_dir(p: path) -> bool {
+    ret chdir(p);
+
+    #[cfg(target_os = "win32")]
+    fn chdir(_p: path) -> bool {
+        ret str::as_buf(_p, {|buf| os::kernel32::SetCurrentDirectoryA(buf)});
+    }
+
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    fn chdir(_p: path) -> bool {
+        ret str::as_buf(_p, {|buf| os::libc::chdir(buf) == 0i32 });
+    }
+}
+
+/*
+Function: path_is_absolute
+
+Indicates whether a path is absolute.
+
+A path is considered absolute if it begins at the filesystem root ("/") or,
+on Windows, begins with a drive letter.
+*/
+fn path_is_absolute(p: path) -> bool { ret os_fs::path_is_absolute(p); }
+
+// FIXME: under Windows, we should prepend the current drive letter to paths
+// that start with a slash.
+/*
+Function: make_absolute
+
+Convert a relative path to an absolute path
+
+If the given path is relative, return it prepended with the current working
+directory. If the given path is already an absolute path, return it
+as is.
+*/
+fn make_absolute(p: path) -> path {
+    if path_is_absolute(p) { ret p; } else { ret connect(getcwd(), p); }
+}
+
+/*
+Function: split
+
+Split a path into it's individual components
+
+Splits a given path by path separators and returns a vector containing
+each piece of the path. On Windows, if the path is absolute then
+the first element of the returned vector will be the drive letter
+followed by a colon.
+*/
+fn split(p: path) -> [path] {
+    let split1 = str::split(p, os_fs::path_sep as u8);
+    let split2 = [];
+    for s in split1 {
+        split2 += str::split(s, os_fs::alt_path_sep as u8);
+    }
+    ret split2;
+}
+
+/*
+Function: splitext
+
+Split a path into a pair of strings with the first element being the filename
+without the extension and the second being either empty or the file extension
+including the period. Leading periods in the basename are ignored.  If the
+path includes directory components then they are included in the filename part
+of the result pair.
+*/
+fn splitext(p: path) -> (str, str) {
+    if str::is_empty(p) { ("", "") }
+    else {
+        let parts = str::split(p, '.' as u8);
+        if vec::len(parts) > 1u {
+            let base = str::connect(vec::init(parts), ".");
+            let ext = "." + option::get(vec::last(parts));
+
+            fn is_dotfile(base: str) -> bool {
+                str::is_empty(base)
+                    || str::ends_with(
+                        base, str::from_char(os_fs::path_sep))
+                    || str::ends_with(
+                        base, str::from_char(os_fs::alt_path_sep))
+            }
+
+            fn ext_contains_sep(ext: str) -> bool {
+                vec::len(split(ext)) > 1u
+            }
+
+            fn no_basename(ext: str) -> bool {
+                str::ends_with(
+                    ext, str::from_char(os_fs::path_sep))
+                    || str::ends_with(
+                        ext, str::from_char(os_fs::alt_path_sep))
+            }
+
+            if is_dotfile(base)
+                || ext_contains_sep(ext)
+                || no_basename(ext) {
+                (p, "")
+            } else {
+                (base, ext)
+            }
+        } else {
+            (p, "")
+        }
+    }
+}
+
+/*
+Function: normalize
+
+Removes extra "." and ".." entries from paths.
+
+Does not follow symbolic links.
+*/
+fn normalize(p: path) -> path {
+    let s = split(p);
+    let s = strip_dots(s);
+    let s = rollup_doubledots(s);
+
+    let s = if check vec::is_not_empty(s) {
+        connect_many(s)
+    } else {
+        ""
+    };
+    let s = reabsolute(p, s);
+    let s = reterminate(p, s);
+
+    let s = if str::byte_len(s) == 0u {
+        "."
+    } else {
+        s
+    };
+
+    ret s;
+
+    fn strip_dots(s: [path]) -> [path] {
+        vec::filter_map({ |elem|
+            if elem == "." {
+                option::none
+            } else {
+                option::some(elem)
+            }
+        }, s)
+    }
+
+    fn rollup_doubledots(s: [path]) -> [path] {
+        if vec::is_empty(s) {
+            ret [];
+        }
+
+        let t = [];
+        let i = vec::len(s);
+        let skip = 0;
+        do {
+            i -= 1u;
+            if s[i] == ".." {
+                skip += 1;
+            } else {
+                if skip == 0 {
+                    t += [s[i]];
+                } else {
+                    skip -= 1;
+                }
+            }
+        } while i != 0u;
+        let t = vec::reversed(t);
+        while skip > 0 {
+            t += [".."];
+            skip -= 1;
+        }
+        ret t;
+    }
+
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    fn reabsolute(orig: path, new: path) -> path {
+        if path_is_absolute(orig) {
+            path_sep() + new
+        } else {
+            new
+        }
+    }
+
+    #[cfg(target_os = "win32")]
+    fn reabsolute(orig: path, new: path) -> path {
+       if path_is_absolute(orig) && orig[0] == os_fs::path_sep as u8 {
+           str::from_char(os_fs::path_sep) + new
+       } else {
+           new
+       }
+    }
+
+    fn reterminate(orig: path, new: path) -> path {
+        let last = orig[str::byte_len(orig) - 1u];
+        if last == os_fs::path_sep as u8
+            || last == os_fs::path_sep as u8 {
+            ret new + path_sep();
+        } else {
+            ret new;
+        }
+    }
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/fun_treemap.rs b/src/libstd/fun_treemap.rs
new file mode 100644
index 00000000000..1f4e6b9491a
--- /dev/null
+++ b/src/libstd/fun_treemap.rs
@@ -0,0 +1,98 @@
+/*
+Module: fun_treemap
+
+A functional key,value store that works on anything.
+
+This works using a binary search tree. In the first version, it's a
+very naive algorithm, but it will probably be updated to be a
+red-black tree or something else.
+
+This is copied and modified from treemap right now. It's missing a lot
+of features.
+
+*/
+
+import option::{some, none};
+import option = option::t;
+
+export treemap;
+export init;
+export insert;
+export find;
+export traverse;
+
+/* Section: Types */
+
+/*
+Type: treemap
+*/
+type treemap<K, V> = @tree_node<K, V>;
+
+/*
+Tag: tree_node
+*/
+tag tree_node<K, V> {
+    empty;
+    node(@K, @V, @tree_node<K, V>, @tree_node<K, V>);
+}
+
+/* Section: Operations */
+
+/*
+Function: init
+
+Create a treemap
+*/
+fn init<K, V>() -> treemap<K, V> { @empty }
+
+/*
+Function: insert
+
+Insert a value into the map
+*/
+fn insert<copy K, copy V>(m: treemap<K, V>, k: K, v: V) -> treemap<K, V> {
+    @alt m {
+       @empty. { node(@k, @v, @empty, @empty) }
+       @node(@kk, vv, left, right) {
+         if k < kk {
+             node(@kk, vv, insert(left, k, v), right)
+         } else if k == kk {
+             node(@kk, @v, left, right)
+         } else { node(@kk, vv, left, insert(right, k, v)) }
+       }
+     }
+}
+
+/*
+Function: find
+
+Find a value based on the key
+*/
+fn find<K, copy V>(m: treemap<K, V>, k: K) -> option<V> {
+    alt *m {
+      empty. { none }
+      node(@kk, @v, left, right) {
+        if k == kk {
+            some(v)
+        } else if k < kk { find(left, k) } else { find(right, k) }
+      }
+    }
+}
+
+/*
+Function: traverse
+
+Visit all pairs in the map in order.
+*/
+fn traverse<K, copy V>(m: treemap<K, V>, f: block(K, V)) {
+    alt *m {
+      empty. { }
+      node(@k, @v, _, _) {
+        // copy v to make aliases work out
+        let v1 = v;
+        alt *m { node(_, _, left, _) { traverse(left, f); } }
+        f(k, v1);
+        alt *m { node(_, _, _, right) { traverse(right, f); } }
+      }
+    }
+}
diff --git a/src/libstd/generic_os.rs b/src/libstd/generic_os.rs
new file mode 100644
index 00000000000..bbbd76f8217
--- /dev/null
+++ b/src/libstd/generic_os.rs
@@ -0,0 +1,99 @@
+/*
+Module: generic_os
+
+Some miscellaneous platform functions.
+
+These should be rolled into another module.
+*/
+
+
+// Wow, this is an ugly way to write doc comments
+
+#[cfg(bogus)]
+/*
+Function: getenv
+
+Get the value of an environment variable
+*/
+fn getenv(n: str) -> option::t<str> { }
+
+#[cfg(bogus)]
+/*
+Function: setenv
+
+Set the value of an environment variable
+*/
+fn setenv(n: str, v: str) { }
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "macos")]
+fn getenv(n: str) -> option::t<str> unsafe {
+    let s = str::as_buf(n, {|buf| os::libc::getenv(buf) });
+    ret if unsafe::reinterpret_cast(s) == 0 {
+            option::none::<str>
+        } else {
+            let s = unsafe::reinterpret_cast(s);
+            option::some::<str>(str::str_from_cstr(s))
+        };
+}
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "macos")]
+fn setenv(n: str, v: str) {
+    // FIXME (868)
+    str::as_buf(
+        n,
+        // FIXME (868)
+        {|nbuf|
+            str::as_buf(
+                v,
+                {|vbuf|
+                    os::libc::setenv(nbuf, vbuf, 1i32)})});
+}
+
+#[cfg(target_os = "win32")]
+fn getenv(n: str) -> option::t<str> {
+    let nsize = 256u;
+    while true {
+        let v: [u8] = [];
+        vec::reserve(v, nsize);
+        let res =
+            str::as_buf(n,
+                        {|nbuf|
+                            unsafe {
+                            let vbuf = vec::to_ptr(v);
+                            os::kernel32::GetEnvironmentVariableA(nbuf, vbuf,
+                                                                  nsize)
+                        }
+                        });
+        if res == 0u {
+            ret option::none;
+        } else if res < nsize {
+            unsafe {
+                vec::unsafe::set_len(v, res);
+            }
+            ret option::some(str::unsafe_from_bytes(v));
+        } else { nsize = res; }
+    }
+    fail;
+}
+
+#[cfg(target_os = "win32")]
+fn setenv(n: str, v: str) {
+    // FIXME (868)
+    let _: () =
+        str::as_buf(n, {|nbuf|
+            let _: () =
+                str::as_buf(v, {|vbuf|
+                    os::kernel32::SetEnvironmentVariableA(nbuf, vbuf);
+                });
+        });
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/getopts.rs b/src/libstd/getopts.rs
new file mode 100644
index 00000000000..438bec0a90b
--- /dev/null
+++ b/src/libstd/getopts.rs
@@ -0,0 +1,386 @@
+/*
+Module: getopts
+
+Simple getopt alternative. Construct a vector of options, either by using
+reqopt, optopt, and optflag or by building them from components yourself, and
+pass them to getopts, along with a vector of actual arguments (not including
+argv[0]). You'll either get a failure code back, or a match.  You'll have to
+verify whether the amount of 'free' arguments in the match is what you
+expect. Use opt_* accessors to get argument values out of the match object.
+
+Single-character options are expected to appear on the command line with a
+single preceeding dash; multiple-character options are expected to be
+proceeded by two dashes. Options that expect an argument accept their argument
+following either a space or an equals sign.
+
+Example:
+
+The following example shows simple command line parsing for an application
+that requires an input file to be specified, accepts an optional output file
+name following -o, and accepts both -h and --help as optional flags.
+
+> fn main(args: [str]) {
+>   let opts = [
+>     optopt("o"),
+>     optflag("h"),
+>     optflag("help")
+>   ];
+>   let match = alt getopts(vec::shift(args), opts) {
+>     success(m) { m }
+>     failure(f) { fail fail_str(f) }
+>   };
+>   if opt_present(match, "h") || opt_present(match, "help") {
+>     print_usage();
+>     ret;
+>   }
+>   let output = opt_maybe_str(match, "o");
+>   let input = if !vec::is_empty(match.free) {
+>     match.free[0]
+>   } else {
+>     print_usage();
+>     ret;
+>   }
+>   do_work(input, output);
+> }
+
+*/
+
+import option::{some, none};
+export opt;
+export reqopt;
+export optopt;
+export optflag;
+export optflagopt;
+export optmulti;
+export getopts;
+export result;
+export success;
+export failure;
+export match;
+export fail_;
+export fail_str;
+export opt_present;
+export opt_str;
+export opt_strs;
+export opt_maybe_str;
+export opt_default;
+
+tag name { long(str); short(char); }
+
+tag hasarg { yes; no; maybe; }
+
+tag occur { req; optional; multi; }
+
+/*
+Type: opt
+
+A description of a possible option
+*/
+type opt = {name: name, hasarg: hasarg, occur: occur};
+
+fn mkname(nm: str) -> name {
+    ret if str::char_len(nm) == 1u {
+            short(str::char_at(nm, 0u))
+        } else { long(nm) };
+}
+
+/*
+Function: reqopt
+
+Create an option that is required and takes an argument
+*/
+fn reqopt(name: str) -> opt {
+    ret {name: mkname(name), hasarg: yes, occur: req};
+}
+
+/*
+Function: optopt
+
+Create an option that is optional and takes an argument
+*/
+fn optopt(name: str) -> opt {
+    ret {name: mkname(name), hasarg: yes, occur: optional};
+}
+
+/*
+Function: optflag
+
+Create an option that is optional and does not take an argument
+*/
+fn optflag(name: str) -> opt {
+    ret {name: mkname(name), hasarg: no, occur: optional};
+}
+
+/*
+Function: optflagopt
+
+Create an option that is optional and takes an optional argument
+*/
+fn optflagopt(name: str) -> opt {
+    ret {name: mkname(name), hasarg: maybe, occur: optional};
+}
+
+/*
+Function: optmulti
+
+Create an option that is optional, takes an argument, and may occur
+multiple times
+*/
+fn optmulti(name: str) -> opt {
+    ret {name: mkname(name), hasarg: yes, occur: multi};
+}
+
+tag optval { val(str); given; }
+
+/*
+Type: match
+
+The result of checking command line arguments. Contains a vector
+of matches and a vector of free strings.
+*/
+type match = {opts: [opt], vals: [mutable [optval]], free: [str]};
+
+fn is_arg(arg: str) -> bool {
+    ret str::byte_len(arg) > 1u && arg[0] == '-' as u8;
+}
+
+fn name_str(nm: name) -> str {
+    ret alt nm { short(ch) { str::from_char(ch) } long(s) { s } };
+}
+
+fn find_opt(opts: [opt], nm: name) -> option::t<uint> {
+    let i = 0u;
+    let l = vec::len::<opt>(opts);
+    while i < l { if opts[i].name == nm { ret some::<uint>(i); } i += 1u; }
+    ret none::<uint>;
+}
+
+/*
+Type: fail_
+
+The type returned when the command line does not conform to the
+expected format. Pass this value to <fail_str> to get an error message.
+*/
+tag fail_ {
+    argument_missing(str);
+    unrecognized_option(str);
+    option_missing(str);
+    option_duplicated(str);
+    unexpected_argument(str);
+}
+
+/*
+Function: fail_str
+
+Convert a <fail_> tag into an error string
+*/
+fn fail_str(f: fail_) -> str {
+    ret alt f {
+          argument_missing(nm) { "Argument to option '" + nm + "' missing." }
+          unrecognized_option(nm) { "Unrecognized option: '" + nm + "'." }
+          option_missing(nm) { "Required option '" + nm + "' missing." }
+          option_duplicated(nm) {
+            "Option '" + nm + "' given more than once."
+          }
+          unexpected_argument(nm) {
+            "Option " + nm + " does not take an argument."
+          }
+        };
+}
+
+/*
+Type: result
+
+The result of parsing a command line with a set of options
+
+Variants:
+
+success(match) - Returned from getopts on success
+failure(fail_) - Returned from getopts on failure
+*/
+tag result { success(match); failure(fail_); }
+
+/*
+Function: getopts
+
+Parse command line arguments according to the provided options
+
+Returns:
+
+success(match) - On success. Use functions such as <opt_present>
+                 <opt_str>, etc. to interrogate results.
+failure(fail_) - On failure. Use <fail_str> to get an error message.
+*/
+fn getopts(args: [str], opts: [opt]) -> result {
+    let n_opts = vec::len::<opt>(opts);
+    fn f(_x: uint) -> [optval] { ret []; }
+    let vals = vec::init_fn_mut::<[optval]>(f, n_opts);
+    let free: [str] = [];
+    let l = vec::len(args);
+    let i = 0u;
+    while i < l {
+        let cur = args[i];
+        let curlen = str::byte_len(cur);
+        if !is_arg(cur) {
+            free += [cur];
+        } else if str::eq(cur, "--") {
+            let j = i + 1u;
+            while j < l { free += [args[j]]; j += 1u; }
+            break;
+        } else {
+            let names;
+            let i_arg = option::none::<str>;
+            if cur[1] == '-' as u8 {
+                let tail = str::slice(cur, 2u, curlen);
+                let eq = str::index(tail, '=' as u8);
+                if eq == -1 {
+                    names = [long(tail)];
+                } else {
+                    names = [long(str::slice(tail, 0u, eq as uint))];
+                    i_arg =
+                        option::some::<str>(str::slice(tail,
+                                                       (eq as uint) + 1u,
+                                                       curlen - 2u));
+                }
+            } else {
+                let j = 1u;
+                names = [];
+                while j < curlen {
+                    let range = str::char_range_at(cur, j);
+                    names += [short(range.ch)];
+                    j = range.next;
+                }
+            }
+            let name_pos = 0u;
+            for nm: name in names {
+                name_pos += 1u;
+                let optid;
+                alt find_opt(opts, nm) {
+                  some(id) { optid = id; }
+                  none. { ret failure(unrecognized_option(name_str(nm))); }
+                }
+                alt opts[optid].hasarg {
+                  no. {
+                    if !option::is_none::<str>(i_arg) {
+                        ret failure(unexpected_argument(name_str(nm)));
+                    }
+                    vals[optid] += [given];
+                  }
+                  maybe. {
+                    if !option::is_none::<str>(i_arg) {
+                        vals[optid] += [val(option::get(i_arg))];
+                    } else if name_pos < vec::len::<name>(names) ||
+                                  i + 1u == l || is_arg(args[i + 1u]) {
+                        vals[optid] += [given];
+                    } else { i += 1u; vals[optid] += [val(args[i])]; }
+                  }
+                  yes. {
+                    if !option::is_none::<str>(i_arg) {
+                        vals[optid] += [val(option::get::<str>(i_arg))];
+                    } else if i + 1u == l {
+                        ret failure(argument_missing(name_str(nm)));
+                    } else { i += 1u; vals[optid] += [val(args[i])]; }
+                  }
+                }
+            }
+        }
+        i += 1u;
+    }
+    i = 0u;
+    while i < n_opts {
+        let n = vec::len::<optval>(vals[i]);
+        let occ = opts[i].occur;
+        if occ == req {
+            if n == 0u {
+                ret failure(option_missing(name_str(opts[i].name)));
+            }
+        }
+        if occ != multi {
+            if n > 1u {
+                ret failure(option_duplicated(name_str(opts[i].name)));
+            }
+        }
+        i += 1u;
+    }
+    ret success({opts: opts, vals: vals, free: free});
+}
+
+fn opt_vals(m: match, nm: str) -> [optval] {
+    ret alt find_opt(m.opts, mkname(nm)) {
+          some(id) { m.vals[id] }
+          none. { log_err "No option '" + nm + "' defined."; fail }
+        };
+}
+
+fn opt_val(m: match, nm: str) -> optval { ret opt_vals(m, nm)[0]; }
+
+/*
+Function: opt_present
+
+Returns true if an option was matched
+*/
+fn opt_present(m: match, nm: str) -> bool {
+    ret vec::len::<optval>(opt_vals(m, nm)) > 0u;
+}
+
+/*
+Function: opt_str
+
+Returns the string argument supplied to a matching option
+
+Failure:
+
+- If the option was not matched
+- If the match did not take an argument
+*/
+fn opt_str(m: match, nm: str) -> str {
+    ret alt opt_val(m, nm) { val(s) { s } _ { fail } };
+}
+
+/*
+Function: opt_str
+
+Returns a vector of the arguments provided to all matches of the given option.
+Used when an option accepts multiple values.
+*/
+fn opt_strs(m: match, nm: str) -> [str] {
+    let acc: [str] = [];
+    for v: optval in opt_vals(m, nm) {
+        alt v { val(s) { acc += [s]; } _ { } }
+    }
+    ret acc;
+}
+
+/*
+Function: opt_str
+
+Returns the string argument supplied to a matching option or none
+*/
+fn opt_maybe_str(m: match, nm: str) -> option::t<str> {
+    let vals = opt_vals(m, nm);
+    if vec::len::<optval>(vals) == 0u { ret none::<str>; }
+    ret alt vals[0] { val(s) { some::<str>(s) } _ { none::<str> } };
+}
+
+
+/*
+Function: opt_default
+
+Returns the matching string, a default, or none
+
+Returns none if the option was not present, `def` if the option was
+present but no argument was provided, and the argument if the option was
+present and an argument was provided.
+*/
+fn opt_default(m: match, nm: str, def: str) -> option::t<str> {
+    let vals = opt_vals(m, nm);
+    if vec::len::<optval>(vals) == 0u { ret none::<str>; }
+    ret alt vals[0] { val(s) { some::<str>(s) } _ { some::<str>(def) } }
+}
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/int.rs b/src/libstd/int.rs
new file mode 100644
index 00000000000..2ab299800ad
--- /dev/null
+++ b/src/libstd/int.rs
@@ -0,0 +1,189 @@
+/*
+Module: int
+*/
+
+/*
+Const: max_value
+
+The maximum value of an integer
+*/
+// FIXME: Find another way to access the machine word size in a const expr
+#[cfg(target_arch="x86")]
+const max_value: int = (-1 << 31)-1;
+
+#[cfg(target_arch="x86_64")]
+const max_value: int = (-1 << 63)-1;
+
+/*
+Const: min_value
+
+The minumum value of an integer
+*/
+#[cfg(target_arch="x86")]
+const min_value: int = -1 << 31;
+
+#[cfg(target_arch="x86_64")]
+const min_value: int = -1 << 63;
+
+/* Function: add */
+pure fn add(x: int, y: int) -> int { ret x + y; }
+
+/* Function: sub */
+pure fn sub(x: int, y: int) -> int { ret x - y; }
+
+/* Function: mul */
+pure fn mul(x: int, y: int) -> int { ret x * y; }
+
+/* Function: div */
+pure fn div(x: int, y: int) -> int { ret x / y; }
+
+/* Function: rem */
+pure fn rem(x: int, y: int) -> int { ret x % y; }
+
+/* Predicate: lt */
+pure fn lt(x: int, y: int) -> bool { ret x < y; }
+
+/* Predicate: le */
+pure fn le(x: int, y: int) -> bool { ret x <= y; }
+
+/* Predicate: eq */
+pure fn eq(x: int, y: int) -> bool { ret x == y; }
+
+/* Predicate: ne */
+pure fn ne(x: int, y: int) -> bool { ret x != y; }
+
+/* Predicate: ge */
+pure fn ge(x: int, y: int) -> bool { ret x >= y; }
+
+/* Predicate: gt */
+pure fn gt(x: int, y: int) -> bool { ret x > y; }
+
+/* Predicate: positive */
+pure fn positive(x: int) -> bool { ret x > 0; }
+
+/* Predicate: negative */
+pure fn negative(x: int) -> bool { ret x < 0; }
+
+/* Predicate: nonpositive */
+pure fn nonpositive(x: int) -> bool { ret x <= 0; }
+
+/* Predicate: nonnegative */
+pure fn nonnegative(x: int) -> bool { ret x >= 0; }
+
+
+// FIXME: Make sure this works with negative integers.
+/*
+Function: hash
+
+Produce a uint suitable for use in a hash table
+*/
+fn hash(x: int) -> uint { ret x as uint; }
+
+/*
+Function: range
+
+Iterate over the range [`lo`..`hi`)
+*/
+fn range(lo: int, hi: int, it: block(int)) {
+    let i = lo;
+    while i < hi { it(i); i += 1; }
+}
+
+/*
+Function: parse_buf
+
+Parse a buffer of bytes
+
+Parameters:
+
+buf - A byte buffer
+radix - The base of the number
+
+Failure:
+
+buf must not be empty
+*/
+fn parse_buf(buf: [u8], radix: uint) -> int {
+    if vec::len::<u8>(buf) == 0u {
+        log_err "parse_buf(): buf is empty";
+        fail;
+    }
+    let i = vec::len::<u8>(buf) - 1u;
+    let start = 0u;
+    let power = 1;
+
+    if buf[0] == ('-' as u8) {
+        power = -1;
+        start = 1u;
+    }
+    let n = 0;
+    while true {
+        let digit = char::to_digit(buf[i] as char);
+        if (digit as uint) >= radix {
+            fail;
+        }
+        n += (digit as int) * power;
+        power *= radix as int;
+        if i <= start { ret n; }
+        i -= 1u;
+    }
+    fail;
+}
+
+/*
+Function: from_str
+
+Parse a string to an int
+
+Failure:
+
+s must not be empty
+*/
+fn from_str(s: str) -> int { parse_buf(str::bytes(s), 10u) }
+
+/*
+Function: to_str
+
+Convert to a string in a given base
+*/
+fn to_str(n: int, radix: uint) -> str {
+    assert (0u < radix && radix <= 16u);
+    ret if n < 0 {
+            "-" + uint::to_str(-n as uint, radix)
+        } else { uint::to_str(n as uint, radix) };
+}
+
+/*
+Function: str
+
+Convert to a string
+*/
+fn str(i: int) -> str { ret to_str(i, 10u); }
+
+/*
+Function: pow
+
+Returns `base` raised to the power of `exponent`
+*/
+fn pow(base: int, exponent: uint) -> int {
+    if exponent == 0u { ret 1; } //Not mathemtically true if [base == 0]
+    if base     == 0  { ret 0; }
+    let my_pow  = exponent;
+    let acc     = 1;
+    let multiplier = base;
+    while(my_pow > 0u) {
+      if my_pow % 2u == 1u {
+         acc *= multiplier;
+      }
+      my_pow     /= 2u;
+      multiplier *= multiplier;
+    }
+    ret acc;
+}
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/io.rs b/src/libstd/io.rs
new file mode 100644
index 00000000000..910ec8bb9ea
--- /dev/null
+++ b/src/libstd/io.rs
@@ -0,0 +1,582 @@
+import ctypes::fd_t;
+import ctypes::c_int;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_get_stdin() -> os::libc::FILE;
+    fn rust_get_stdout() -> os::libc::FILE;
+    fn rust_get_stderr() -> os::libc::FILE;
+}
+
+// Reading
+
+// FIXME This is all buffered. We might need an unbuffered variant as well
+tag seek_style { seek_set; seek_end; seek_cur; }
+
+
+// The raw underlying reader class. All readers must implement this.
+type buf_reader =
+    // FIXME: Seekable really should be orthogonal. We will need
+    // inheritance.
+    obj {
+        fn read(uint) -> [u8];
+        fn read_byte() -> int;
+        fn unread_byte(int);
+        fn eof() -> bool;
+        fn seek(int, seek_style);
+        fn tell() -> uint;
+        // Needed on readers in case one needs to flush metadata
+        // changes (atime)
+        fn fsync(level: fsync::level) -> int;
+    };
+
+
+// Convenience methods for reading.
+type reader =
+    // FIXME: This should inherit from buf_reader.
+    // FIXME: eventually u64
+
+    obj {
+        fn get_buf_reader() -> buf_reader;
+        fn read_byte() -> int;
+        fn unread_byte(int);
+        fn read_bytes(uint) -> [u8];
+        fn read_char() -> char;
+        fn eof() -> bool;
+        fn read_line() -> str;
+        fn read_c_str() -> str;
+        fn read_le_uint(uint) -> uint;
+        fn read_le_int(uint) -> int;
+        fn read_be_uint(uint) -> uint;
+        fn read_whole_stream() -> [u8];
+        fn seek(int, seek_style);
+        fn tell() -> uint;
+    };
+
+fn convert_whence(whence: seek_style) -> i32 {
+    ret alt whence {
+      seek_set. { 0i32 }
+      seek_cur. { 1i32 }
+      seek_end. { 2i32 }
+    };
+}
+
+resource FILE_res(f: os::libc::FILE) {
+    os::libc::fclose(f);
+}
+
+obj FILE_buf_reader(f: os::libc::FILE, res: option::t<@FILE_res>) {
+    fn read(len: uint) -> [u8] unsafe {
+        let buf = [];
+        vec::reserve::<u8>(buf, len);
+        let read =
+            os::libc::fread(vec::unsafe::to_ptr::<u8>(buf), 1u, len, f);
+        vec::unsafe::set_len::<u8>(buf, read);
+        ret buf;
+    }
+    fn read_byte() -> int { ret os::libc::fgetc(f) as int; }
+    fn unread_byte(byte: int) { os::libc::ungetc(byte as i32, f); }
+    fn eof() -> bool { ret os::libc::feof(f) != 0i32; }
+    fn seek(offset: int, whence: seek_style) {
+        assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
+    }
+    fn tell() -> uint { ret os::libc::ftell(f) as uint; }
+    fn fsync(level: fsync::level) -> int {
+        ret os::fsync_fd(os::libc::fileno(f), level) as int;
+    }
+}
+
+
+// FIXME: Convert this into pseudomethods on buf_reader.
+obj new_reader(rdr: buf_reader) {
+    fn get_buf_reader() -> buf_reader { ret rdr; }
+    fn read_byte() -> int { ret rdr.read_byte(); }
+    fn unread_byte(byte: int) { ret rdr.unread_byte(byte); }
+    fn read_bytes(len: uint) -> [u8] { ret rdr.read(len); }
+    fn read_char() -> char {
+        let c0 = rdr.read_byte();
+        if c0 == -1 {
+            ret -1 as char; // FIXME will this stay valid?
+
+        }
+        let b0 = c0 as u8;
+        let w = str::utf8_char_width(b0);
+        assert (w > 0u);
+        if w == 1u { ret b0 as char; }
+        let val = 0u;
+        while w > 1u {
+            w -= 1u;
+            let next = rdr.read_byte();
+            assert (next > -1);
+            assert (next & 192 == 128);
+            val <<= 6u;
+            val += next & 63 as uint;
+        }
+        // See str::char_at
+
+        val += (b0 << (w + 1u as u8) as uint) << (w - 1u) * 6u - w - 1u;
+        ret val as char;
+    }
+    fn eof() -> bool { ret rdr.eof(); }
+    fn read_line() -> str {
+        let buf: [u8] = [];
+        // No break yet in rustc
+
+        let go_on = true;
+        while go_on {
+            let ch = rdr.read_byte();
+            if ch == -1 || ch == 10 {
+                go_on = false;
+            } else { buf += [ch as u8]; }
+        }
+        ret str::unsafe_from_bytes(buf);
+    }
+    fn read_c_str() -> str {
+        let buf: [u8] = [];
+        let go_on = true;
+        while go_on {
+            let ch = rdr.read_byte();
+            if ch < 1 { go_on = false; } else { buf += [ch as u8]; }
+        }
+        ret str::unsafe_from_bytes(buf);
+    }
+
+    // FIXME deal with eof?
+    fn read_le_uint(size: uint) -> uint {
+        let val = 0u;
+        let pos = 0u;
+        let i = size;
+        while i > 0u {
+            val += (rdr.read_byte() as uint) << pos;
+            pos += 8u;
+            i -= 1u;
+        }
+        ret val;
+    }
+    fn read_le_int(size: uint) -> int {
+        let val = 0u, pos = 0u, i = size;
+        while i > 0u {
+            val += (rdr.read_byte() as uint) << pos;
+            pos += 8u;
+            i -= 1u;
+        }
+        ret val as int;
+    }
+
+    // FIXME deal with eof?
+    fn read_be_uint(sz: uint) -> uint {
+        let val = 0u, i = sz;
+
+        while i > 0u {
+            i -= 1u;
+            val += (rdr.read_byte() as uint) << i * 8u;
+        }
+        ret val;
+    }
+    fn read_whole_stream() -> [u8] {
+        let buf: [u8] = [];
+        while !rdr.eof() { buf += rdr.read(2048u); }
+        ret buf;
+    }
+    fn seek(offset: int, whence: seek_style) { ret rdr.seek(offset, whence); }
+    fn tell() -> uint { ret rdr.tell(); }
+}
+
+fn stdin() -> reader {
+    ret new_reader(FILE_buf_reader(rustrt::rust_get_stdin(), option::none));
+}
+
+fn file_reader(path: str) -> result::t<reader, str> {
+    let f = str::as_buf(path, {|pathbuf|
+        str::as_buf("r", {|modebuf|
+            os::libc::fopen(pathbuf, modebuf)
+        })
+    });
+    ret if f as uint == 0u { result::err("error opening " + path) }
+    else {
+        result::ok(new_reader(FILE_buf_reader(f, option::some(@FILE_res(f)))))
+    }
+}
+
+
+// Byte buffer readers
+
+// TODO: const u8, but this fails with rustboot.
+type byte_buf = @{buf: [u8], mutable pos: uint};
+
+obj byte_buf_reader(bbuf: byte_buf) {
+    fn read(len: uint) -> [u8] {
+        let rest = vec::len::<u8>(bbuf.buf) - bbuf.pos;
+        let to_read = len;
+        if rest < to_read { to_read = rest; }
+        let range = vec::slice::<u8>(bbuf.buf, bbuf.pos, bbuf.pos + to_read);
+        bbuf.pos += to_read;
+        ret range;
+    }
+    fn read_byte() -> int {
+        if bbuf.pos == vec::len::<u8>(bbuf.buf) { ret -1; }
+        let b = bbuf.buf[bbuf.pos];
+        bbuf.pos += 1u;
+        ret b as int;
+    }
+    fn unread_byte(_byte: int) { log_err "TODO: unread_byte"; fail; }
+    fn eof() -> bool { ret bbuf.pos == vec::len::<u8>(bbuf.buf); }
+    fn seek(offset: int, whence: seek_style) {
+        let pos = bbuf.pos;
+        let len = vec::len::<u8>(bbuf.buf);
+        bbuf.pos = seek_in_buf(offset, pos, len, whence);
+    }
+    fn tell() -> uint { ret bbuf.pos; }
+    fn fsync(_level: fsync::level) -> int { ret 0; }
+}
+
+fn new_byte_buf_reader(buf: [u8]) -> buf_reader {
+    ret byte_buf_reader(@{buf: buf, mutable pos: 0u});
+}
+
+fn string_reader(s: str) -> reader {
+    ret new_reader(new_byte_buf_reader(str::bytes(s)));
+}
+
+
+// Writing
+tag fileflag { append; create; truncate; none; }
+
+type buf_writer =
+    // FIXME: Seekable really should be orthogonal. We will need
+    // inheritance.
+    // FIXME: eventually u64
+
+    obj {
+        fn write([u8]);
+        fn seek(int, seek_style);
+        fn tell() -> uint;
+        fn flush() -> int;
+        fn fsync(level: fsync::level) -> int;
+    };
+
+obj FILE_writer(f: os::libc::FILE, res: option::t<@FILE_res>) {
+    fn write(v: [u8]) unsafe {
+        let len = vec::len::<u8>(v);
+        let vbuf = vec::unsafe::to_ptr::<u8>(v);
+        let nout = os::libc::fwrite(vbuf, len, 1u, f);
+        if nout < 1u { log_err "error dumping buffer"; }
+    }
+    fn seek(offset: int, whence: seek_style) {
+        assert (os::libc::fseek(f, offset, convert_whence(whence)) == 0i32);
+    }
+    fn tell() -> uint { ret os::libc::ftell(f) as uint; }
+    fn flush() -> int { ret os::libc::fflush(f) as int; }
+    fn fsync(level: fsync::level) -> int {
+        ret os::fsync_fd(os::libc::fileno(f), level) as int;
+    }
+}
+
+resource fd_res(fd: fd_t) { os::libc::close(fd); }
+
+obj fd_buf_writer(fd: fd_t, res: option::t<@fd_res>) {
+    fn write(v: [u8]) unsafe {
+        let len = vec::len::<u8>(v);
+        let count = 0u;
+        let vbuf;
+        while count < len {
+            vbuf = ptr::offset(vec::unsafe::to_ptr::<u8>(v), count);
+            let nout = os::libc::write(fd, vbuf, len);
+            if nout < 0 {
+                log_err "error dumping buffer";
+                log_err sys::last_os_error();
+                fail;
+            }
+            count += nout as uint;
+        }
+    }
+    fn seek(_offset: int, _whence: seek_style) {
+        log_err "need 64-bit native calls for seek, sorry";
+        fail;
+    }
+    fn tell() -> uint {
+        log_err "need 64-bit native calls for tell, sorry";
+        fail;
+    }
+
+    fn flush() -> int { ret 0; }
+
+    fn fsync(level: fsync::level) -> int {
+        ret os::fsync_fd(fd, level) as int;
+    }
+}
+
+fn file_buf_writer(path: str,
+                   flags: [fileflag]) -> result::t<buf_writer, str> {
+    let fflags: i32 =
+        os::libc_constants::O_WRONLY | os::libc_constants::O_BINARY;
+    for f: fileflag in flags {
+        alt f {
+          append. { fflags |= os::libc_constants::O_APPEND; }
+          create. { fflags |= os::libc_constants::O_CREAT; }
+          truncate. { fflags |= os::libc_constants::O_TRUNC; }
+          none. { }
+        }
+    }
+    let fd =
+        str::as_buf(path,
+                    {|pathbuf|
+                        os::libc::open(pathbuf, fflags,
+                                       os::libc_constants::S_IRUSR |
+                                           os::libc_constants::S_IWUSR)
+                    });
+    ret if fd < 0i32 {
+        log_err sys::last_os_error();
+        result::err("error opening " + path)
+    } else {
+        result::ok(fd_buf_writer(fd, option::some(@fd_res(fd))))
+    }
+}
+
+type writer =
+    // write_str will continue to do utf-8 output only. an alternative
+    // function will be provided for general encoded string output
+    obj {
+        fn get_buf_writer() -> buf_writer;
+        fn write_str(str);
+        fn write_line(str);
+        fn write_char(char);
+        fn write_int(int);
+        fn write_uint(uint);
+        fn write_bytes([u8]);
+        fn write_le_uint(uint, uint);
+        fn write_le_int(int, uint);
+        fn write_be_uint(uint, uint);
+    };
+
+fn uint_to_le_bytes(n: uint, size: uint) -> [u8] {
+    let bytes: [u8] = [], i = size, n = n;
+    while i > 0u { bytes += [n & 255u as u8]; n >>= 8u; i -= 1u; }
+    ret bytes;
+}
+
+fn uint_to_be_bytes(n: uint, size: uint) -> [u8] {
+    let bytes: [u8] = [];
+    let i = size - 1u as int;
+    while i >= 0 { bytes += [n >> (i * 8 as uint) & 255u as u8]; i -= 1; }
+    ret bytes;
+}
+
+obj new_writer(out: buf_writer) {
+    fn get_buf_writer() -> buf_writer { ret out; }
+    fn write_str(s: str) { out.write(str::bytes(s)); }
+    fn write_line(s: str) {
+        out.write(str::bytes(s));
+        out.write(str::bytes("\n"));
+    }
+    fn write_char(ch: char) {
+        // FIXME needlessly consy
+
+        out.write(str::bytes(str::from_char(ch)));
+    }
+    fn write_int(n: int) { out.write(str::bytes(int::to_str(n, 10u))); }
+    fn write_uint(n: uint) { out.write(str::bytes(uint::to_str(n, 10u))); }
+    fn write_bytes(bytes: [u8]) { out.write(bytes); }
+    fn write_le_uint(n: uint, size: uint) {
+        out.write(uint_to_le_bytes(n, size));
+    }
+    fn write_le_int(n: int, size: uint) {
+        out.write(uint_to_le_bytes(n as uint, size));
+    }
+    fn write_be_uint(n: uint, size: uint) {
+        out.write(uint_to_be_bytes(n, size));
+    }
+}
+
+fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> {
+    result::chain(file_buf_writer(path, flags), { |w|
+        result::ok(new_writer(w))
+    })
+}
+
+
+// FIXME: fileflags
+fn buffered_file_buf_writer(path: str) -> result::t<buf_writer, str> {
+    let f =
+        str::as_buf(path,
+                    {|pathbuf|
+                        str::as_buf("w",
+                                    {|modebuf|
+                                        os::libc::fopen(pathbuf, modebuf)
+                                    })
+                    });
+    ret if f as uint == 0u { result::err("error opening " + path) }
+    else { result::ok(FILE_writer(f, option::some(@FILE_res(f)))) }
+}
+
+
+// FIXME it would be great if this could be a const
+// Problem seems to be that new_writer is not pure
+fn stdout() -> writer { ret new_writer(fd_buf_writer(1i32, option::none)); }
+fn stderr() -> writer { ret new_writer(fd_buf_writer(2i32, option::none)); }
+
+fn print(s: str) { stdout().write_str(s); }
+fn println(s: str) { stdout().write_str(s + "\n"); }
+
+type str_writer =
+    obj {
+        fn get_writer() -> writer;
+        fn get_str() -> str;
+    };
+
+type mutable_byte_buf = @{mutable buf: [mutable u8], mutable pos: uint};
+
+obj byte_buf_writer(buf: mutable_byte_buf) {
+    fn write(v: [u8]) {
+        // Fast path.
+
+        if buf.pos == vec::len(buf.buf) {
+            for b: u8 in v { buf.buf += [mutable b]; }
+            buf.pos += vec::len::<u8>(v);
+            ret;
+        }
+        // FIXME: Optimize: These should be unique pointers.
+
+        let vlen = vec::len::<u8>(v);
+        let vpos = 0u;
+        while vpos < vlen {
+            let b = v[vpos];
+            if buf.pos == vec::len(buf.buf) {
+                buf.buf += [mutable b];
+            } else { buf.buf[buf.pos] = b; }
+            buf.pos += 1u;
+            vpos += 1u;
+        }
+    }
+    fn seek(offset: int, whence: seek_style) {
+        let pos = buf.pos;
+        let len = vec::len(buf.buf);
+        buf.pos = seek_in_buf(offset, pos, len, whence);
+    }
+    fn tell() -> uint { ret buf.pos; }
+    fn flush() -> int { ret 0; }
+    fn fsync(_level: fsync::level) -> int { ret 0; }
+}
+
+fn string_writer() -> str_writer {
+    // FIXME: yikes, this is bad. Needs fixing of mutable syntax.
+
+    let b: [mutable u8] = [mutable 0u8];
+    vec::pop(b);
+    let buf: mutable_byte_buf = @{mutable buf: b, mutable pos: 0u};
+    obj str_writer_wrap(wr: writer, buf: mutable_byte_buf) {
+        fn get_writer() -> writer { ret wr; }
+        fn get_str() -> str { ret str::unsafe_from_bytes(buf.buf); }
+    }
+    ret str_writer_wrap(new_writer(byte_buf_writer(buf)), buf);
+}
+
+
+// Utility functions
+fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
+   uint {
+    let bpos = pos as int;
+    let blen = len as int;
+    alt whence {
+      seek_set. { bpos = offset; }
+      seek_cur. { bpos += offset; }
+      seek_end. { bpos = blen + offset; }
+    }
+    if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; }
+    ret bpos as uint;
+}
+
+fn read_whole_file_str(file: str) -> result::t<str, str> {
+    result::chain(read_whole_file(file), { |bytes|
+        result::ok(str::unsafe_from_bytes(bytes))
+    })
+}
+
+fn read_whole_file(file: str) -> result::t<[u8], str> {
+
+    // FIXME: There's a lot of copying here
+    result::chain(file_reader(file), { |rdr|
+        result::ok(rdr.read_whole_stream())
+    })
+}
+
+// fsync related
+
+mod fsync {
+
+    tag level {
+        // whatever fsync does on that platform
+        fsync;
+
+        // fdatasync on linux, similiar or more on other platforms
+        fdatasync;
+
+        // full fsync
+        //
+        // You must additionally sync the parent directory as well!
+        fullfsync;
+    }
+
+
+    // Resource of artifacts that need to fsync on destruction
+    resource res<t>(arg: arg<t>) {
+        alt arg.opt_level {
+          option::none::<level>. { }
+          option::some::<level>(level) {
+            // fail hard if not succesful
+            assert(arg.fsync_fn(arg.val, level) != -1);
+          }
+        }
+    }
+
+    type arg<t> = {
+        val: t,
+        opt_level: option::t<level>,
+        fsync_fn: fn(t, level) -> int
+    };
+
+    // fsync file after executing blk
+    // FIXME find better way to create resources within lifetime of outer res
+    fn FILE_res_sync(&&file: FILE_res, opt_level: option::t<level>,
+                  blk: block(&&res<os::libc::FILE>)) {
+        blk(res({
+            val: *file, opt_level: opt_level,
+            fsync_fn: fn(&&file: os::libc::FILE, l: level) -> int {
+                ret os::fsync_fd(os::libc::fileno(file), l) as int;
+            }
+        }));
+    }
+
+    // fsync fd after executing blk
+    fn fd_res_sync(&&fd: fd_res, opt_level: option::t<level>,
+                   blk: block(&&res<fd_t>)) {
+        blk(res({
+            val: *fd, opt_level: opt_level,
+            fsync_fn: fn(&&fd: fd_t, l: level) -> int {
+                ret os::fsync_fd(fd, l) as int;
+            }
+        }));
+    }
+
+    // Type of objects that may want to fsync
+    type t = obj { fn fsync(l: level) -> int; };
+
+    // Call o.fsync after executing blk
+    fn obj_sync(&&o: t, opt_level: option::t<level>, blk: block(&&res<t>)) {
+        blk(res({
+            val: o, opt_level: opt_level,
+            fsync_fn: fn(&&o: t, l: level) -> int { ret o.fsync(l); }
+        }));
+    }
+}
+
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
new file mode 100644
index 00000000000..3f74c55507b
--- /dev/null
+++ b/src/libstd/json.rs
@@ -0,0 +1,258 @@
+// Rust JSON serialization library
+// Copyright (c) 2011 Google Inc.
+
+import float;
+import map;
+import option;
+import option::{some, none};
+import str;
+import vec;
+
+export json;
+export to_str;
+export from_str;
+
+export num;
+export string;
+export boolean;
+export list;
+export dict;
+
+/*
+Tag: json
+
+Represents a json value.
+*/
+tag json {
+    /* Variant: num */
+    num(float);
+    /* Variant: string */
+    string(str);
+    /* Variant: boolean */
+    boolean(bool);
+    /* Variant: list */
+    list(@[json]);
+    /* Variant: dict */
+    dict(map::hashmap<str,json>);
+}
+
+/*
+Function: to_str
+
+Serializes a json value into a string.
+*/
+fn to_str(j: json) -> str {
+    alt j {
+        num(f) { float::to_str(f, 6u) }
+        string(s) { #fmt["\"%s\"", s] } // XXX: escape
+        boolean(true) { "true" }
+        boolean(false) { "false" }
+        list(@js) {
+            str::concat(["[",
+                    str::connect(
+                        vec::map::<json,str>({ |e| to_str(e) }, js),
+                        ", "),
+                    "]"])
+        }
+        dict(m) {
+            let parts = [];
+            m.items({ |k, v|
+                        vec::grow(parts, 1u,
+                                  str::concat(["\"", k, "\": ", to_str(v)])
+                        )
+            });
+            str::concat(["{ ", str::connect(parts, ", "), " }"])
+        }
+    }
+}
+
+fn rest(s: str) -> str {
+    assert(str::char_len(s) >= 1u);
+    str::char_slice(s, 1u, str::char_len(s))
+}
+
+fn from_str_str(s: str) -> (option::t<json>, str) {
+    let pos = 0u;
+    let len = str::byte_len(s);
+    let escape = false;
+    let res = "";
+
+    alt str::char_at(s, 0u) {
+        '"' { pos = 1u; }
+        _ { ret (none, s); }
+    }
+
+    while (pos < len) {
+        let chr = str::char_range_at(s, pos);
+        let c = chr.ch;
+        pos = chr.next;
+        if (escape) {
+            res = res + str::from_char(c);
+            escape = false;
+            cont;
+        }
+        if (c == '\\') {
+            escape = true;
+            cont;
+        } else if (c == '"') {
+            ret (some(string(res)),
+                 str::char_slice(s, pos, str::char_len(s)));
+        }
+        res = res + str::from_char(c);
+    }
+
+    ret (none, s);
+}
+
+fn from_str_list(s: str) -> (option::t<json>, str) {
+    if str::char_at(s, 0u) != '[' { ret (none, s); }
+    let s0 = str::trim_left(rest(s));
+    let vals = [];
+    if str::is_empty(s0) { ret (none, s0); }
+    if str::char_at(s0, 0u) == ']' { ret (some(list(@[])), rest(s0)); }
+    while str::is_not_empty(s0) {
+        s0 = str::trim_left(s0);
+        let (next, s1) = from_str_helper(s0);
+        s0 = s1;
+        alt next {
+            some(j) { vec::grow(vals, 1u, j); }
+            none { ret (none, s0); }
+        }
+        s0 = str::trim_left(s0);
+        if str::is_empty(s0) { ret (none, s0); }
+        alt str::char_at(s0, 0u) {
+            ',' { }
+            ']' { ret (some(list(@vals)), rest(s0)); }
+            _ { ret (none, s0); }
+        }
+        s0 = rest(s0);
+    }
+    ret (none, s0);
+}
+
+fn from_str_dict(s: str) -> (option::t<json>, str) {
+    if str::char_at(s, 0u) != '{' { ret (none, s); }
+    let s0 = str::trim_left(rest(s));
+    let vals = map::new_str_hash::<json>();
+    if str::is_empty(s0) { ret (none, s0); }
+    if str::char_at(s0, 0u) == '}' { ret (some(dict(vals)), rest(s0)); }
+    while str::is_not_empty(s0) {
+        s0 = str::trim_left(s0);
+        let (next, s1) = from_str_helper(s0);    // key
+        let key = "";
+        s0 = s1;
+        alt next {
+            some(string(k)) { key = k; }
+            _ { ret (none, s0); }
+        }
+        s0 = str::trim_left(s0);
+        if str::is_empty(s0) { ret (none, s0); }
+        if str::char_at(s0, 0u) != ':' { ret (none, s0); }
+        s0 = str::trim_left(rest(s0));
+        let (next, s1) = from_str_helper(s0);    // value
+        s0 = s1;
+        alt next {
+            some(j) { vals.insert(key, j); }
+            _ { ret (none, s0); }
+        }
+        s0 = str::trim_left(s0);
+        if str::is_empty(s0) { ret (none, s0); }
+        alt str::char_at(s0, 0u) {
+            ',' { }
+            '}' { ret (some(dict(vals)), rest(s0)); }
+            _ { ret (none, s0); }
+        }
+        s0 = str::trim_left(rest(s0));
+    }
+    (none, s)
+}
+
+fn from_str_float(s: str) -> (option::t<json>, str) {
+    let pos = 0u;
+    let len = str::byte_len(s);
+    let res = 0f;
+    let neg = 1.f;
+
+    alt str::char_at(s, 0u) {
+        '-' {
+            neg = -1.f;
+            pos = 1u;
+        }
+        '+' {
+            pos = 1u;
+        }
+        '0' to '9' | '.' { }
+        _ { ret (none, s); }
+    }
+
+    while (pos < len) {
+        let opos = pos;
+        let chr = str::char_range_at(s, pos);
+        let c = chr.ch;
+        pos = chr.next;
+        alt c {
+            '0' to '9' {
+                res = res * 10f;
+                res += ((c as int) - ('0' as int)) as float;
+            }
+            '.' { break; }
+            _ { ret (some(num(neg * res)),
+                     str::char_slice(s, opos, str::char_len(s))); }
+        }
+    }
+
+    if pos == len {
+        ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
+    }
+
+    let dec = 1.f;
+    while (pos < len) {
+        let opos = pos;
+        let chr = str::char_range_at(s, pos);
+        let c = chr.ch;
+        pos = chr.next;
+        alt c {
+            '0' to '9' {
+                dec /= 10.f;
+                res += (((c as int) - ('0' as int)) as float) * dec;
+            }
+            _ { ret (some(num(neg * res)),
+                     str::char_slice(s, opos, str::char_len(s))); }
+        }
+    }
+    ret (some(num(neg * res)), str::char_slice(s, pos, str::char_len(s)));
+}
+
+fn from_str_bool(s: str) -> (option::t<json>, str) {
+    if (str::starts_with(s, "true")) {
+        (some(boolean(true)), str::slice(s, 4u, str::byte_len(s)))
+    } else if (str::starts_with(s, "false")) {
+        (some(boolean(false)), str::slice(s, 5u, str::byte_len(s)))
+    } else {
+        (none, s)
+    }
+}
+
+fn from_str_helper(s: str) -> (option::t<json>, str) {
+    let s = str::trim_left(s);
+    if str::is_empty(s) { ret (none, s); }
+    let start = str::char_at(s, 0u);
+    alt start {
+        '"' { from_str_str(s) }
+        '[' { from_str_list(s) }
+        '{' { from_str_dict(s) }
+        '0' to '9' | '-' | '+' | '.' { from_str_float(s) }
+        't' | 'f' { from_str_bool(s) }
+        _ { ret (none, s); }
+    }
+}
+
+/*
+Function: from_str
+
+Deserializes a json value from a string.
+*/
+fn from_str(s: str) -> option::t<json> {
+    let (j, _) = from_str_helper(s);
+    j
+}
diff --git a/src/libstd/linux_os.rs b/src/libstd/linux_os.rs
new file mode 100644
index 00000000000..7e30088ee3c
--- /dev/null
+++ b/src/libstd/linux_os.rs
@@ -0,0 +1,145 @@
+/*
+Module: os
+
+TODO: Restructure and document
+*/
+
+import ctypes::*;
+
+export libc;
+export libc_constants;
+export pipe;
+export fd_FILE;
+export close;
+export fclose;
+export waitpid;
+export getcwd;
+export exec_suffix;
+export target_os;
+export dylib_filename;
+export get_exe_path;
+export fsync_fd;
+
+// FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult
+// by https://github.com/graydon/rust/issues#issue/268
+
+#[link_name = ""]
+#[abi = "cdecl"]
+native mod libc {
+    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
+    fn close(fd: fd_t) -> c_int;
+    type FILE;
+    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
+    fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
+    fn fclose(f: FILE);
+    fn fflush(f: FILE) -> c_int;
+    fn fsync(fd: fd_t) -> c_int;
+    fn fdatasync(fd: fd_t) -> c_int;
+    fn fileno(f: FILE) -> fd_t;
+    fn fgetc(f: FILE) -> c_int;
+    fn ungetc(c: c_int, f: FILE);
+    fn feof(f: FILE) -> c_int;
+    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
+    fn ftell(f: FILE) -> long;
+    type dir;
+    fn opendir(d: str::sbuf) -> dir;
+    fn closedir(d: dir) -> c_int;
+    type dirent;
+    fn readdir(d: dir) -> dirent;
+    fn getenv(n: str::sbuf) -> str::sbuf;
+    fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
+    fn unsetenv(n: str::sbuf) -> c_int;
+    fn pipe(buf: *mutable fd_t) -> c_int;
+    fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> pid_t;
+    fn readlink(path: str::sbuf, buf: str::sbuf, bufsize: size_t) -> ssize_t;
+    fn mkdir(path: str::sbuf, mode: c_int) -> c_int;
+    fn rmdir(path: str::sbuf) -> c_int;
+    fn chdir(path: str::sbuf) -> c_int;
+}
+
+mod libc_constants {
+    const O_RDONLY: c_int = 0i32;
+    const O_WRONLY: c_int = 1i32;
+    const O_RDWR: c_int   = 2i32;
+    const O_APPEND: c_int = 1024i32;
+    const O_CREAT: c_int  = 64i32;
+    const O_EXCL: c_int   = 128i32;
+    const O_TRUNC: c_int  = 512i32;
+    const O_TEXT: c_int   = 0i32;     // nonexistent in linux libc
+    const O_BINARY: c_int = 0i32;     // nonexistent in linux libc
+
+    const S_IRUSR: unsigned = 256u32;
+    const S_IWUSR: unsigned = 128u32;
+}
+
+fn pipe() -> {in: fd_t, out: fd_t} {
+    let fds = {mutable in: 0i32, mutable out: 0i32};
+    assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32);
+    ret {in: fds.in, out: fds.out};
+}
+
+fn fd_FILE(fd: fd_t) -> libc::FILE {
+    ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
+}
+
+fn close(fd: fd_t) -> c_int {
+    libc::close(fd)
+}
+
+fn fclose(file: libc::FILE) {
+    libc::fclose(file)
+}
+
+fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
+    alt level {
+      io::fsync::fsync. | io::fsync::fullfsync. { ret libc::fsync(fd); }
+      io::fsync::fdatasync. { ret libc::fdatasync(fd); }
+    }
+}
+
+fn waitpid(pid: pid_t) -> i32 {
+    let status = 0i32;
+    assert (os::libc::waitpid(pid, status, 0i32) != -1i32);
+    ret status;
+}
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_getcwd() -> str;
+}
+
+fn getcwd() -> str { ret rustrt::rust_getcwd(); }
+
+fn exec_suffix() -> str { ret ""; }
+
+fn target_os() -> str { ret "linux"; }
+
+fn dylib_filename(base: str) -> str { ret "lib" + base + ".so"; }
+
+/// Returns the directory containing the running program
+/// followed by a path separator
+fn get_exe_path() -> option::t<fs::path> {
+    let bufsize = 1023u;
+    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize));
+    ret str::as_buf("/proc/self/exe", { |proc_self_buf|
+        str::as_buf(path, { |path_buf|
+            if libc::readlink(proc_self_buf, path_buf, bufsize) != -1 {
+                option::some(fs::dirname(path) + fs::path_sep())
+            } else {
+                option::none
+            }
+        })
+    });
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/list.rs b/src/libstd/list.rs
new file mode 100644
index 00000000000..ab712091819
--- /dev/null
+++ b/src/libstd/list.rs
@@ -0,0 +1,161 @@
+/*
+Module: list
+
+A standard linked list
+*/
+
+import option::{some, none};
+
+/* Section: Types */
+
+/*
+Tag: list
+*/
+tag list<T> {
+    /* Variant: cons */
+    cons(T, @list<T>);
+    /* Variant: nil */
+    nil;
+}
+
+/*Section: Operations */
+
+/*
+Function: from_vec
+
+Create a list from a vector
+*/
+fn from_vec<copy T>(v: [const T]) -> list<T> {
+    *vec::foldr({ |h, t| @cons(h, t) }, @nil::<T>, v)
+}
+
+/*
+Function: foldl
+
+Left fold
+
+Applies `f` to `u` and the first element in the list, then applies
+`f` to the result of the previous call and the second element,
+and so on, returning the accumulated result.
+
+Parameters:
+
+ls - The list to fold
+z - The initial value
+f - The function to apply
+*/
+fn foldl<copy T, copy U>(ls: list<U>, z: T, f: block(T, U) -> T) -> T {
+    let accum: T = z;
+    let ls = ls;
+    while true {
+        alt ls {
+          cons(hd, tl) { accum = f(accum, hd); ls = *tl; }
+          nil. { break; }
+        }
+    }
+    ret accum;
+}
+
+/*
+Function: find
+
+Search for an element that matches a given predicate
+
+Apply function `f` to each element of `v`, starting from the first.
+When function `f` returns true then an option containing the element
+is returned. If `f` matches no elements then none is returned.
+*/
+fn find<copy T, copy U>(ls: list<T>, f: block(T) -> option::t<U>)
+    -> option::t<U> {
+    let ls = ls;
+    while true {
+        alt ls {
+          cons(hd, tl) {
+            alt f(hd) { none. { ls = *tl; } some(rs) { ret some(rs); } }
+          }
+          nil. { break; }
+        }
+    }
+    ret none;
+}
+
+/*
+Function: has
+
+Returns true if a list contains an element with the given value
+*/
+fn has<copy T>(ls: list<T>, elt: T) -> bool {
+    let ls = ls;
+    while true {
+        alt ls {
+          cons(hd, tl) { if elt == hd { ret true; } else { ls = *tl; } }
+          nil. { break; }
+        }
+    }
+    ret false;
+}
+
+/*
+Function: len
+
+Returns the length of a list
+*/
+fn len<copy T>(ls: list<T>) -> uint {
+    fn count<T>(&&u: uint, _t: T) -> uint { ret u + 1u; }
+    ret foldl(ls, 0u, bind count(_, _));
+}
+
+/*
+Function: tail
+
+Returns all but the first element of a list
+*/
+fn tail<copy T>(ls: list<T>) -> list<T> {
+    alt ls { cons(_, tl) { ret *tl; } nil. { fail "list empty" } }
+}
+
+/*
+Function: head
+
+Returns the first element of a list
+*/
+fn head<copy T>(ls: list<T>) -> T {
+    alt ls { cons(hd, _) { ret hd; } nil. { fail "list empty" } }
+}
+
+/*
+Function: append
+
+Appends one list to another
+*/
+fn append<copy T>(l: list<T>, m: list<T>) -> list<T> {
+    alt l {
+      nil. { ret m; }
+      cons(x, xs) { let rest = append(*xs, m); ret cons(x, @rest); }
+    }
+}
+
+/*
+Function: iter
+
+Iterate over a list
+*/
+fn iter<copy T>(l: list<T>, f: block(T)) {
+    let cur = l;
+    while cur != nil {
+        alt cur {
+          cons(hd, tl) {
+            f(hd);
+            cur = *tl;
+          }
+        }
+    }
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/macos_os.rs b/src/libstd/macos_os.rs
new file mode 100644
index 00000000000..f23e82eaa63
--- /dev/null
+++ b/src/libstd/macos_os.rs
@@ -0,0 +1,153 @@
+import ctypes::*;
+
+export libc;
+export libc_constants;
+export pipe;
+export fd_FILE;
+export close;
+export fclose;
+export waitpid;
+export getcwd;
+export exec_suffix;
+export target_os;
+export dylib_filename;
+export get_exe_path;
+export fsync_fd;
+
+// FIXME Refactor into unix_os module or some such. Doesn't
+// seem to work right now.
+
+#[link_name = ""]
+#[abi = "cdecl"]
+native mod libc {
+    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
+    fn close(fd: fd_t) -> c_int;
+    type FILE;
+    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
+    fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
+    fn fflush(f: FILE) -> c_int;
+    fn fsync(fd: fd_t) -> c_int;
+    fn fileno(f: FILE) -> fd_t;
+    fn fclose(f: FILE);
+    fn fgetc(f: FILE) -> c_int;
+    fn ungetc(c: c_int, f: FILE);
+    fn feof(f: FILE) -> c_int;
+    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
+    fn ftell(f: FILE) -> long;
+    type dir;
+    fn opendir(d: str::sbuf) -> dir;
+    fn closedir(d: dir) -> c_int;
+    type dirent;
+    fn readdir(d: dir) -> dirent;
+    fn getenv(n: str::sbuf) -> str::sbuf;
+    fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
+    fn unsetenv(n: str::sbuf) -> c_int;
+    fn pipe(buf: *mutable c_int) -> c_int;
+    fn waitpid(pid: pid_t, &status: c_int, options: c_int) -> c_int;
+    fn mkdir(s: str::sbuf, mode: c_int) -> c_int;
+    fn rmdir(s: str::sbuf) -> c_int;
+    fn chdir(s: str::sbuf) -> c_int;
+
+    // FIXME: Needs varags
+    fn fcntl(fd: fd_t, cmd: c_int) -> c_int;
+}
+
+mod libc_constants {
+    const O_RDONLY: c_int    = 0i32;
+    const O_WRONLY: c_int    = 1i32;
+    const O_RDWR: c_int      = 2i32;
+    const O_APPEND: c_int    = 8i32;
+    const O_CREAT: c_int     = 512i32;
+    const O_EXCL: c_int      = 2048i32;
+    const O_TRUNC: c_int     = 1024i32;
+    const O_TEXT: c_int      = 0i32;    // nonexistent in darwin libc
+    const O_BINARY: c_int    = 0i32;    // nonexistent in darwin libc
+
+    const S_IRUSR: unsigned  = 256u32;
+    const S_IWUSR: unsigned  = 128u32;
+
+    const F_FULLFSYNC: c_int = 51i32;
+}
+
+fn pipe() -> {in: fd_t, out: fd_t} {
+    let fds = {mutable in: 0i32, mutable out: 0i32};
+    assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32);
+    ret {in: fds.in, out: fds.out};
+}
+
+fn fd_FILE(fd: fd_t) -> libc::FILE {
+    ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
+}
+
+fn close(fd: fd_t) -> c_int {
+    libc::close(fd)
+}
+
+fn fclose(file: libc::FILE) {
+    libc::fclose(file)
+}
+
+fn waitpid(pid: pid_t) -> i32 {
+    let status = 0i32;
+    assert (os::libc::waitpid(pid, status, 0i32) != -1i32);
+    ret status;
+}
+
+fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
+    alt level {
+      io::fsync::fsync. { ret libc::fsync(fd); }
+      _ {
+        // According to man fnctl, the ok retval is only specified to be !=-1
+        if (libc::fcntl(libc_constants::F_FULLFSYNC, fd) == -1 as c_int)
+            { ret -1 as c_int; }
+        else
+            { ret 0 as c_int; }
+      }
+    }
+}
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_getcwd() -> str;
+}
+
+fn getcwd() -> str { ret rustrt::rust_getcwd(); }
+
+#[link_name = ""]
+#[abi = "cdecl"]
+native mod mac_libc {
+    fn _NSGetExecutablePath(buf: str::sbuf,
+                            bufsize: *mutable uint32_t) -> c_int;
+}
+
+fn exec_suffix() -> str { ret ""; }
+
+fn target_os() -> str { ret "macos"; }
+
+fn dylib_filename(base: str) -> str { ret "lib" + base + ".dylib"; }
+
+fn get_exe_path() -> option::t<fs::path> {
+    // FIXME: This doesn't handle the case where the buffer is too small
+    let bufsize = 1023u32;
+    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize as uint));
+    ret str::as_buf(path, { |path_buf|
+        if mac_libc::_NSGetExecutablePath(path_buf,
+                                          ptr::mut_addr_of(bufsize)) == 0i32 {
+            option::some(fs::dirname(path) + fs::path_sep())
+        } else {
+            option::none
+        }
+    });
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/map.rs b/src/libstd/map.rs
new file mode 100644
index 00000000000..c802b5b889f
--- /dev/null
+++ b/src/libstd/map.rs
@@ -0,0 +1,336 @@
+/*
+Module: map
+
+A hashmap
+*/
+
+/* Section: Types */
+
+/*
+Type: hashfn
+
+A function that returns a hash of a value
+*/
+type hashfn<K> = fn(K) -> uint;
+
+/*
+Type: eqfn
+
+Equality
+*/
+type eqfn<K> = fn(K, K) -> bool;
+
+/*
+Type: hashset
+
+A convenience type to treat a hashmap as a set
+*/
+type hashset<K> = hashmap<K, ()>;
+
+/*
+Obj: hashmap
+*/
+type hashmap<K, V> = obj {
+    /*
+    Method: size
+
+    Return the number of elements in the map
+    */
+    fn size() -> uint;
+    /*
+    Method: insert
+
+    Add a value to the map. If the map already contains a value for
+    the specified key then the original value is replaced.
+
+    Returns:
+
+    True if the key did not already exist in the map
+    */
+    fn insert(K, V) -> bool;
+    /*
+    Method: contains_key
+
+    Returns true if the map contains a value for the specified key
+    */
+    fn contains_key(K) -> bool;
+    /*
+    Method: get
+
+    Get the value for the specified key
+
+    Failure:
+
+    If the key does not exist in the map
+    */
+    fn get(K) -> V;
+    /*
+    Method: find
+
+    Get the value for the specified key. If the key does not exist
+    in the map then returns none.
+    */
+    fn find(K) -> option::t<V>;
+    /*
+    Method: remove
+
+    Remove and return a value from the map. If the key does not exist
+    in the map then returns none.
+    */
+    fn remove(K) -> option::t<V>;
+    /*
+    Method: rehash
+
+    Force map growth and rehashing
+    */
+    fn rehash();
+    /*
+    Method: items
+
+    Iterate over all the key/value pairs in the map
+    */
+    fn items(block(K, V));
+    /*
+    Method: keys
+
+    Iterate over all the keys in the map
+    */
+    fn keys(block(K));
+    /*
+    Iterate over all the values in the map
+    */
+    fn values(block(V));
+};
+
+/* Section: Operations */
+
+/*
+Function: mk_hashmap
+
+Construct a hashmap
+
+Parameters:
+
+hasher - The hash function for key type K
+eqer - The equality function for key type K
+*/
+fn mk_hashmap<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>)
+    -> hashmap<K, V> {
+    let initial_capacity: uint = 32u; // 2^5
+
+    let load_factor: util::rational = {num: 3, den: 4};
+    tag bucket<copy K, copy V> { nil; deleted; some(K, V); }
+    fn make_buckets<copy K, copy V>(nbkts: uint) -> [mutable bucket<K, V>] {
+        ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts);
+    }
+    // Derive two hash functions from the one given by taking the upper
+    // half and lower half of the uint bits.  Our bucket probing
+    // sequence is then defined by
+    //
+    //   hash(key, i) := hashl(key) * i + hashr(key)   for i = 0, 1, 2, ...
+    //
+    // Tearing the hash function apart this way is kosher in practice
+    // as, assuming 32-bit uints, the table would have to be at 2^32
+    // buckets before the resulting pair of hash functions no longer
+    // probes all buckets for a fixed key.  Note that hashl is made to
+    // output odd numbers (hence coprime to the number of nbkts, which
+    // is always a power of 2), so that all buckets are probed for a
+    // fixed key.
+
+    fn hashl(n: uint, _nbkts: uint) -> uint { ret (n >>> 16u) * 2u + 1u; }
+    fn hashr(n: uint, _nbkts: uint) -> uint { ret 0x0000_ffff_u & n; }
+    fn hash(h: uint, nbkts: uint, i: uint) -> uint {
+        ret (hashl(h, nbkts) * i + hashr(h, nbkts)) % nbkts;
+    }
+    /**
+     * We attempt to never call this with a full table.  If we do, it
+     * will fail.
+     */
+
+    fn insert_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
+                                     bkts: [mutable bucket<K, V>],
+                                     nbkts: uint, key: K, val: V) -> bool {
+        let i: uint = 0u;
+        let h: uint = hasher(key);
+        while i < nbkts {
+            let j: uint = hash(h, nbkts, i);
+            alt bkts[j] {
+              some(k, _) {
+                // Copy key to please alias analysis.
+
+                let k_ = k;
+                if eqer(key, k_) { bkts[j] = some(k_, val); ret false; }
+                i += 1u;
+              }
+              _ { bkts[j] = some(key, val); ret true; }
+            }
+        }
+        fail; // full table
+    }
+    fn find_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
+                                   bkts: [mutable bucket<K, V>],
+                                   nbkts: uint, key: K) -> option::t<V> {
+        let i: uint = 0u;
+        let h: uint = hasher(key);
+        while i < nbkts {
+            let j: uint = hash(h, nbkts, i);
+            alt bkts[j] {
+              some(k, v) {
+                // Copy to please alias analysis.
+                let k_ = k;
+                let v_ = v;
+                if eqer(key, k_) { ret option::some(v_); }
+              }
+              nil. { ret option::none; }
+              deleted. { }
+            }
+            i += 1u;
+        }
+        ret option::none;
+    }
+    fn rehash<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
+                              oldbkts: [mutable bucket<K, V>],
+                              _noldbkts: uint,
+                              newbkts: [mutable bucket<K, V>],
+                              nnewbkts: uint) {
+        for b: bucket<K, V> in oldbkts {
+            alt b {
+              some(k_, v_) {
+                let k = k_;
+                let v = v_;
+                insert_common(hasher, eqer, newbkts, nnewbkts, k, v);
+              }
+              _ { }
+            }
+        }
+    }
+    obj hashmap<copy K, copy V>(hasher: hashfn<K>,
+                                eqer: eqfn<K>,
+                                mutable bkts: [mutable bucket<K, V>],
+                                mutable nbkts: uint,
+                                mutable nelts: uint,
+                                lf: util::rational) {
+        fn size() -> uint { ret nelts; }
+        fn insert(key: K, val: V) -> bool {
+            let load: util::rational =
+                {num: nelts + 1u as int, den: nbkts as int};
+            if !util::rational_leq(load, lf) {
+                let nnewbkts: uint = uint::next_power_of_two(nbkts + 1u);
+                let newbkts = make_buckets(nnewbkts);
+                rehash(hasher, eqer, bkts, nbkts, newbkts, nnewbkts);
+                bkts = newbkts;
+                nbkts = nnewbkts;
+            }
+            if insert_common(hasher, eqer, bkts, nbkts, key, val) {
+                nelts += 1u;
+                ret true;
+            }
+            ret false;
+        }
+        fn contains_key(key: K) -> bool {
+            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
+                  option::some(_) { true }
+                  _ { false }
+                };
+        }
+        fn get(key: K) -> V {
+            ret alt find_common(hasher, eqer, bkts, nbkts, key) {
+                  option::some(val) { val }
+                  _ { fail }
+                };
+        }
+        fn find(key: K) -> option::t<V> {
+            be find_common(hasher, eqer, bkts, nbkts, key);
+        }
+        fn remove(key: K) -> option::t<V> {
+            let i: uint = 0u;
+            let h: uint = hasher(key);
+            while i < nbkts {
+                let j: uint = hash(h, nbkts, i);
+                alt bkts[j] {
+                  some(k, v) {
+                    let k_ = k;
+                    let vo = option::some(v);
+                    if eqer(key, k_) {
+                        bkts[j] = deleted;
+                        nelts -= 1u;
+                        ret vo;
+                    }
+                  }
+                  deleted. { }
+                  nil. { ret option::none; }
+                }
+                i += 1u;
+            }
+            ret option::none;
+        }
+        fn rehash() {
+            let newbkts = make_buckets(nbkts);
+            rehash(hasher, eqer, bkts, nbkts, newbkts, nbkts);
+            bkts = newbkts;
+        }
+        fn items(it: block(K, V)) {
+            for b in bkts {
+                alt b { some(k, v) { it(copy k, copy v); } _ { } }
+            }
+        }
+        fn keys(it: block(K)) {
+            for b in bkts {
+                alt b { some(k, _) { it(copy k); } _ { } }
+            }
+        }
+        fn values(it: block(V)) {
+            for b in bkts {
+                alt b { some(_, v) { it(copy v); } _ { } }
+            }
+        }
+    }
+    let bkts = make_buckets(initial_capacity);
+    ret hashmap(hasher, eqer, bkts, initial_capacity, 0u, load_factor);
+}
+
+/*
+Function: new_str_hash
+
+Construct a hashmap for string keys
+*/
+fn new_str_hash<copy V>() -> hashmap<str, V> {
+    ret mk_hashmap(str::hash, str::eq);
+}
+
+/*
+Function: new_int_hash
+
+Construct a hashmap for int keys
+*/
+fn new_int_hash<copy V>() -> hashmap<int, V> {
+    fn hash_int(&&x: int) -> uint { ret x as uint; }
+    fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; }
+    ret mk_hashmap(hash_int, eq_int);
+}
+
+/*
+Function: new_uint_hash
+
+Construct a hashmap for uint keys
+*/
+fn new_uint_hash<copy V>() -> hashmap<uint, V> {
+    fn hash_uint(&&x: uint) -> uint { ret x; }
+    fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; }
+    ret mk_hashmap(hash_uint, eq_uint);
+}
+
+/*
+Function: set_add
+
+Convenience function for adding keys to a hashmap with nil type keys
+*/
+fn set_add<K>(set: hashset<K>, key: K) -> bool { ret set.insert(key, ()); }
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/math.rs b/src/libstd/math.rs
new file mode 100644
index 00000000000..72056548ca5
--- /dev/null
+++ b/src/libstd/math.rs
@@ -0,0 +1,387 @@
+/*
+
+Module: math
+
+Floating point operations and constants for `float`s
+*/
+
+export consts;
+export min, max;
+
+// Currently this module supports from -lmath:
+// C95 + log2 + log1p + trunc + round + rint
+
+export
+    acos, asin, atan, atan2, ceil, cos, cosh, exp, abs, floor, fmod, frexp,
+    ldexp, ln, ln1p, log10, log2, modf, rint, round, pow, sin, sinh, sqrt,
+    tan, tanh, trunc;
+
+// These two must match in width according to architecture
+
+import ctypes::m_float;
+import ctypes::c_int;
+import m_float = math_f64;
+
+// FIXME replace with redirect to m_float::consts::FOO as soon as it works
+mod consts {
+    /*
+    Const: pi
+
+    Archimedes' constant
+    */
+    const pi: float = 3.14159265358979323846264338327950288;
+
+    /*
+    Const: frac_pi_2
+
+    pi/2.0
+    */
+    const frac_pi_2: float = 1.57079632679489661923132169163975144;
+
+    /*
+    Const: frac_pi_4
+
+    pi/4.0
+    */
+    const frac_pi_4: float = 0.785398163397448309615660845819875721;
+
+    /*
+    Const: frac_1_pi
+
+    1.0/pi
+    */
+    const frac_1_pi: float = 0.318309886183790671537767526745028724;
+
+    /*
+    Const: frac_2_pi
+
+    2.0/pi
+    */
+    const frac_2_pi: float = 0.636619772367581343075535053490057448;
+
+    /*
+    Const: frac_2_sqrtpi
+
+    2.0/sqrt(pi)
+    */
+    const frac_2_sqrtpi: float = 1.12837916709551257389615890312154517;
+
+    /*
+    Const: sqrt2
+
+    sqrt(2.0)
+    */
+    const sqrt2: float = 1.41421356237309504880168872420969808;
+
+    /*
+    Const: frac_1_sqrt2
+
+    1.0/sqrt(2.0)
+    */
+    const frac_1_sqrt2: float = 0.707106781186547524400844362104849039;
+
+    /*
+    Const: e
+
+    Euler's number
+    */
+    const e: float = 2.71828182845904523536028747135266250;
+
+    /*
+    Const: log2_e
+
+    log2(e)
+    */
+    const log2_e: float = 1.44269504088896340735992468100189214;
+
+    /*
+    Const: log10_e
+
+    log10(e)
+    */
+    const log10_e: float = 0.434294481903251827651128918916605082;
+
+    /*
+    Const: ln_2
+
+    ln(2.0)
+    */
+    const ln_2: float = 0.693147180559945309417232121458176568;
+
+    /*
+    Const: ln_10
+
+    ln(10.0)
+    */
+    const ln_10: float = 2.30258509299404568401799145468436421;
+}
+
+
+// FIXME min/max type specialize via libm when overloading works
+// (in theory fmax/fmin, fmaxf, fminf /should/ be faster)
+
+/*
+Function: min
+
+Returns the minimum of two values
+*/
+pure fn min<copy T>(x: T, y: T) -> T { x < y ? x : y }
+
+/*
+Function: max
+
+Returns the maximum of two values
+*/
+pure fn max<copy T>(x: T, y: T) -> T { x < y ? y : x }
+
+/*
+Function: acos
+
+Returns the arccosine of an angle (measured in rad)
+*/
+pure fn acos(x: float) -> float
+    { m_float::acos(x as m_float) as float }
+
+/*
+Function: asin
+
+Returns the arcsine of an angle (measured in rad)
+*/
+pure fn asin(x: float) -> float
+    { m_float::asin(x as m_float) as float }
+
+/*
+Function: atan
+
+Returns the arctangents of an angle (measured in rad)
+*/
+pure fn atan(x: float) -> float
+    { m_float::atan(x as m_float) as float }
+
+
+/*
+Function: atan2
+
+Returns the arctangent of an angle (measured in rad)
+*/
+pure fn atan2(y: float, x: float) -> float
+    { m_float::atan2(y as m_float, x as m_float) as float }
+
+/*
+Function: ceil
+
+Returns the smallest integral value less than or equal to `n`
+*/
+pure fn ceil(n: float) -> float
+    { m_float::ceil(n as m_float) as float }
+
+/*
+Function: cos
+
+Returns the cosine of an angle `x` (measured in rad)
+*/
+pure fn cos(x: float) -> float
+    { m_float::cos(x as m_float) as float }
+
+/*
+Function: cosh
+
+Returns the hyperbolic cosine of `x`
+
+*/
+pure fn cosh(x: float) -> float
+    { m_float::cosh(x as m_float) as float }
+
+
+/*
+Function: exp
+
+Returns `consts::e` to the power of `n*
+*/
+pure fn exp(n: float) -> float
+    { m_float::exp(n as m_float) as float }
+
+/*
+Function: abs
+
+Returns the absolute value of  `n`
+*/
+pure fn abs(n: float) -> float
+    { m_float::abs(n as m_float) as float }
+
+/*
+Function: floor
+
+Returns the largest integral value less than or equal to `n`
+*/
+pure fn floor(n: float) -> float
+    { m_float::floor(n as m_float) as float }
+
+/*
+Function: fmod
+
+Returns the floating-point remainder of `x/y`
+*/
+pure fn fmod(x: float, y: float) -> float
+    { m_float::fmod(x as m_float, y as m_float) as float }
+
+/*
+Function: ln
+
+Returns the natural logaritm of `n`
+*/
+pure fn ln(n: float) -> float
+    { m_float::ln(n as m_float) as float }
+
+/*
+Function: ldexp
+
+Returns `x` multiplied by 2 to the power of `n`
+*/
+pure fn ldexp(n: float, i: int) -> float
+    { m_float::ldexp(n as m_float, i as c_int) as float }
+
+/*
+Function: ln1p
+
+Returns the natural logarithm of `1+n` accurately,
+even for very small values of `n`
+*/
+pure fn ln1p(n: float) -> float
+    { m_float::ln1p(n as m_float) as float }
+
+/*
+Function: log10
+
+Returns the logarithm to base 10 of `n`
+*/
+pure fn log10(n: float) -> float
+    { m_float::log10(n as m_float) as float }
+
+/*
+Function: log2
+
+Returns the logarithm to base 2 of `n`
+*/
+pure fn log2(n: float) -> float
+    { m_float::log2(n as m_float) as float }
+
+
+/*
+Function: modf
+
+Breaks `n` into integral and fractional parts such that both
+have the same sign as `n`
+
+The integral part is stored in `iptr`.
+
+Returns:
+
+The fractional part of `n`
+*/
+pure fn modf(n: float, &iptr: float) -> float {
+    unchecked {
+        let f = iptr as m_float;
+        let r = m_float::modf(n as m_float, f) as float;
+        iptr  = f as float;
+        ret r;
+    }
+}
+
+/*
+Function: frexp
+
+Breaks `n` into a normalized fraction and an integral power of 2
+
+The inegral part is stored in iptr.
+
+The functions return a number x such that x has a magnitude in the interval
+[1/2, 1) or 0, and `n == x*(2 to the power of exp)`.
+
+Returns:
+
+The fractional part of `n`
+*/
+pure fn frexp(n: float, &exp: c_int) -> float
+    { m_float::frexp(n as m_float, exp) as float }
+
+/*
+Function: pow
+*/
+pure fn pow(v: float, e: float) -> float
+    { m_float::pow(v as m_float, e as m_float) as float }
+
+
+/*
+Function: rint
+
+Returns the integral value nearest to `x` (according to the
+prevailing rounding mode) in floating-point format
+*/
+pure fn rint(x: float) -> float
+    { m_float::rint(x as m_float) as float }
+
+/*
+Function: round
+
+
+Return the integral value nearest to `x` rounding half-way
+cases away from zero, regardless of the current rounding direction.
+*/
+pure fn round(x: float) -> float
+    { m_float::round(x as m_float) as float }
+
+/*
+Function: sin
+
+Returns the sine of an angle `x` (measured in rad)
+*/
+pure fn sin(x: float) -> float
+    { m_float::sin(x as m_float) as float }
+
+/*
+Function: sinh
+
+Returns the hyperbolic sine of an angle `x` (measured in rad)
+*/
+pure fn sinh(x: float) -> float
+    { m_float::sinh(x as m_float) as float }
+
+/*
+Function: sqrt
+
+Returns the square root of `x`
+*/
+pure fn sqrt(x: float) -> float
+    { m_float::sqrt(x as m_float) as float }
+
+/*
+Function: tan
+
+Returns the tangent of an angle `x` (measured in rad)
+
+*/
+pure fn tan(x: float) -> float
+    { m_float::tan(x as m_float) as float }
+
+/*
+Function: tanh
+
+Returns the hyperbolic tangent of an angle `x` (measured in rad)
+
+*/
+pure fn tanh(x: float) -> float
+    { m_float::tanh(x as m_float) as float }
+
+/*
+Function: trunc
+
+Returns the integral value nearest to but no larger in magnitude than `x`
+
+*/
+pure fn trunc(x: float) -> float
+    { m_float::trunc(x as m_float) as float }
+
+
+
+
diff --git a/src/libstd/math_f32.rs b/src/libstd/math_f32.rs
new file mode 100644
index 00000000000..2172c9f8a99
--- /dev/null
+++ b/src/libstd/math_f32.rs
@@ -0,0 +1,112 @@
+
+/*
+Module: math_f32
+
+Floating point operations and constants for `f32`
+
+This exposes the same operations as `math`, just for `f32` even though
+they do not show up in the docs right now!
+*/
+
+import cmath::f32::*;
+
+export
+    acos, asin, atan, atan2, ceil, cos, cosh, exp, abs, floor, fmod,
+    frexp, ldexp, ln, ln1p, log10, log2, modf, rint, round, pow, sin,
+    sinh, sqrt, tan, tanh, trunc;
+
+export consts;
+
+mod consts {
+
+    /*
+    Const: pi
+
+    Archimedes' constant
+    */
+    const pi: f32 = 3.14159265358979323846264338327950288f32;
+
+    /*
+    Const: frac_pi_2
+
+    pi/2.0
+    */
+    const frac_pi_2: f32 = 1.57079632679489661923132169163975144f32;
+
+    /*
+    Const: frac_pi_4
+
+    pi/4.0
+    */
+    const frac_pi_4: f32 = 0.785398163397448309615660845819875721f32;
+
+    /*
+    Const: frac_1_pi
+
+    1.0/pi
+    */
+    const frac_1_pi: f32 = 0.318309886183790671537767526745028724f32;
+
+    /*
+    Const: frac_2_pi
+
+    2.0/pi
+    */
+    const frac_2_pi: f32 = 0.636619772367581343075535053490057448f32;
+
+    /*
+    Const: frac_2_sqrtpi
+
+    2.0/sqrt(pi)
+    */
+    const frac_2_sqrtpi: f32 = 1.12837916709551257389615890312154517f32;
+
+    /*
+    Const: sqrt2
+
+    sqrt(2.0)
+    */
+    const sqrt2: f32 = 1.41421356237309504880168872420969808f32;
+
+    /*
+    Const: frac_1_sqrt2
+
+    1.0/sqrt(2.0)
+    */
+    const frac_1_sqrt2: f32 = 0.707106781186547524400844362104849039f32;
+
+    /*
+    Const: e
+
+    Euler's number
+    */
+    const e: f32 = 2.71828182845904523536028747135266250f32;
+
+    /*
+    Const: log2_e
+
+    log2(e)
+    */
+    const log2_e: f32 = 1.44269504088896340735992468100189214f32;
+
+    /*
+    Const: log10_e
+
+    log10(e)
+    */
+    const log10_e: f32 = 0.434294481903251827651128918916605082f32;
+
+    /*
+    Const: ln_2
+
+    ln(2.0)
+    */
+    const ln_2: f32 = 0.693147180559945309417232121458176568f32;
+
+    /*
+    Const: ln_10
+
+    ln(10.0)
+    */
+    const ln_10: f32 = 2.30258509299404568401799145468436421f32;
+}
\ No newline at end of file
diff --git a/src/libstd/math_f64.rs b/src/libstd/math_f64.rs
new file mode 100644
index 00000000000..639dc4a29b2
--- /dev/null
+++ b/src/libstd/math_f64.rs
@@ -0,0 +1,112 @@
+
+/*
+Module: math_f64
+
+Floating point operations and constants for `f64`s
+
+This exposes the same operations as `math`, just for `f64` even though
+they do not show up in the docs right now!
+*/
+
+import cmath::f64::*;
+
+export
+    acos, asin, atan, atan2, ceil, cos, cosh, exp, abs, floor, fmod,
+    frexp, ldexp, ln, ln1p, log10, log2, modf, rint, round, pow, sin,
+    sinh, sqrt, tan, tanh, trunc;
+
+export consts;
+
+mod consts {
+
+    /*
+    Const: pi
+
+    Archimedes' constant
+    */
+    const pi: f64 = 3.14159265358979323846264338327950288f64;
+
+    /*
+    Const: frac_pi_2
+
+    pi/2.0
+    */
+    const frac_pi_2: f64 = 1.57079632679489661923132169163975144f64;
+
+    /*
+    Const: frac_pi_4
+
+    pi/4.0
+    */
+    const frac_pi_4: f64 = 0.785398163397448309615660845819875721f64;
+
+    /*
+    Const: frac_1_pi
+
+    1.0/pi
+    */
+    const frac_1_pi: f64 = 0.318309886183790671537767526745028724f64;
+
+    /*
+    Const: frac_2_pi
+
+    2.0/pi
+    */
+    const frac_2_pi: f64 = 0.636619772367581343075535053490057448f64;
+
+    /*
+    Const: frac_2_sqrtpi
+
+    2.0/sqrt(pi)
+    */
+    const frac_2_sqrtpi: f64 = 1.12837916709551257389615890312154517f64;
+
+    /*
+    Const: sqrt2
+
+    sqrt(2.0)
+    */
+    const sqrt2: f64 = 1.41421356237309504880168872420969808f64;
+
+    /*
+    Const: frac_1_sqrt2
+
+    1.0/sqrt(2.0)
+    */
+    const frac_1_sqrt2: f64 = 0.707106781186547524400844362104849039f64;
+
+    /*
+    Const: e
+
+    Euler's number
+    */
+    const e: f64 = 2.71828182845904523536028747135266250f64;
+
+    /*
+    Const: log2_e
+
+    log2(e)
+    */
+    const log2_e: f64 = 1.44269504088896340735992468100189214f64;
+
+    /*
+    Const: log10_e
+
+    log10(e)
+    */
+    const log10_e: f64 = 0.434294481903251827651128918916605082f64;
+
+    /*
+    Const: ln_2
+
+    ln(2.0)
+    */
+    const ln_2: f64 = 0.693147180559945309417232121458176568f64;
+
+    /*
+    Const: ln_10
+
+    ln(10.0)
+    */
+    const ln_10: f64 = 2.30258509299404568401799145468436421f64;
+}
\ No newline at end of file
diff --git a/src/libstd/net.rs b/src/libstd/net.rs
new file mode 100644
index 00000000000..5ee7cfa602c
--- /dev/null
+++ b/src/libstd/net.rs
@@ -0,0 +1,56 @@
+/*
+Module: net
+*/
+
+import vec;
+import uint;
+
+/* Section: Types */
+
+/*
+Tag: ip_addr
+
+An IP address
+*/
+tag ip_addr {
+    /*
+    Variant: ipv4
+
+    An IPv4 address
+    */
+    ipv4(u8, u8, u8, u8);
+}
+
+/* Section: Operations */
+
+/*
+Function: format_addr
+
+Convert an <ip_addr> to a str
+*/
+fn format_addr(ip: ip_addr) -> str {
+    alt ip {
+      ipv4(a, b, c, d) {
+        #fmt["%u.%u.%u.%u", a as uint, b as uint, c as uint, d as uint]
+      }
+      _ { fail "Unsupported address type"; }
+    }
+}
+
+/*
+Function: parse_addr
+
+Convert a str to <ip_addr>
+
+Converts a string of the format "x.x.x.x" into an ip_addr tag.
+
+Failure:
+
+String must be a valid IPv4 address
+*/
+fn parse_addr(ip: str) -> ip_addr {
+    let parts = vec::map({|s| uint::from_str(s) }, str::split(ip, "."[0]));
+    if vec::len(parts) != 4u { fail "Too many dots in IP address"; }
+    for i in parts { if i > 255u { fail "Invalid IP Address part."; } }
+    ipv4(parts[0] as u8, parts[1] as u8, parts[2] as u8, parts[3] as u8)
+}
diff --git a/src/libstd/option.rs b/src/libstd/option.rs
new file mode 100644
index 00000000000..403cb47f47e
--- /dev/null
+++ b/src/libstd/option.rs
@@ -0,0 +1,93 @@
+/*
+Module: option
+
+Represents the presence or absence of a value.
+
+Every option<T> value can either be some(T) or none. Where in other languages
+you might use a nullable type, in Rust you would use an option type.
+*/
+
+/*
+Tag: t
+
+The option type
+*/
+tag t<T> {
+    /* Variant: none */
+    none;
+    /* Variant: some */
+    some(T);
+}
+
+/* Section: Operations */
+
+/*
+Function: get
+
+Gets the value out of an option
+
+Failure:
+
+Fails if the value equals `none`.
+*/
+fn get<copy T>(opt: t<T>) -> T {
+    alt opt { some(x) { ret x; } none. { fail "option none"; } }
+}
+
+/*
+*/
+fn map<T, U>(f: block(T) -> U, opt: t<T>) -> t<U> {
+    alt opt { some(x) { some(f(x)) } none. { none } }
+}
+
+/*
+Function: is_none
+
+Returns true if the option equals none
+*/
+pure fn is_none<T>(opt: t<T>) -> bool {
+    alt opt { none. { true } some(_) { false } }
+}
+
+/*
+Function: is_some
+
+Returns true if the option contains some value
+*/
+pure fn is_some<T>(opt: t<T>) -> bool { !is_none(opt) }
+
+/*
+Function: from_maybe
+
+Returns the contained value or a default
+*/
+fn from_maybe<T>(def: T, opt: t<T>) -> T {
+    alt opt { some(x) { x } none. { def } }
+}
+
+/*
+Function: maybe
+
+Applies a function to the contained value or returns a default
+*/
+fn maybe<T, U>(def: U, f: block(T) -> U, opt: t<T>) -> U {
+    alt opt { none. { def } some(t) { f(t) } }
+}
+
+// FIXME: Can be defined in terms of the above when/if we have const bind.
+/*
+Function: may
+
+Performs an operation on the contained value or does nothing
+*/
+fn may<T>(f: block(T), opt: t<T>) {
+    alt opt { none. {/* nothing */ } some(t) { f(t); } }
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/posix_fs.rs b/src/libstd/posix_fs.rs
new file mode 100644
index 00000000000..befa4c9829c
--- /dev/null
+++ b/src/libstd/posix_fs.rs
@@ -0,0 +1,45 @@
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_list_files(path: str) -> [str];
+}
+
+fn list_dir(path: str) -> [str] {
+    ret rustrt::rust_list_files(path);
+
+    // FIXME: No idea why, but this appears to corrupt memory on OSX. I
+    // suspect it has to do with the tasking primitives somehow, or perhaps
+    // the FFI. Worth investigating more when we're digging into the FFI and
+    // unsafe mode in more detail; in the meantime we just call list_files
+    // above and skip this code.
+
+    /*
+    auto dir = os::libc::opendir(str::buf(path));
+    assert (dir as uint != 0u);
+    let vec<str> result = [];
+    while (true) {
+        auto ent = os::libc::readdir(dir);
+        if (ent as int == 0) {
+            os::libc::closedir(dir);
+            ret result;
+        }
+        vec::push::<str>(result, rustrt::rust_dirent_filename(ent));
+    }
+    os::libc::closedir(dir);
+    ret result;
+    */
+
+}
+
+fn path_is_absolute(p: str) -> bool { ret str::char_at(p, 0u) == '/'; }
+
+const path_sep: char = '/';
+
+const alt_path_sep: char = '/';
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs
new file mode 100644
index 00000000000..0372b17cdf1
--- /dev/null
+++ b/src/libstd/ptr.rs
@@ -0,0 +1,52 @@
+/*
+Module: ptr
+
+Unsafe pointer utility functions
+*/
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn addr_of<T>(val: T) -> *T;
+    fn ptr_offset<T>(ptr: *T, count: uint) -> *T;
+}
+
+/*
+Function: addr_of
+
+Get an unsafe pointer to a value
+*/
+fn addr_of<T>(val: T) -> *T { ret rusti::addr_of(val); }
+
+/*
+Function: mut_addr_of
+
+Get an unsafe mutable pointer to a value
+*/
+fn mut_addr_of<T>(val: T) -> *mutable T unsafe {
+    ret unsafe::reinterpret_cast(rusti::addr_of(val));
+}
+
+/*
+Function: offset
+
+Calculate the offset from a pointer
+*/
+fn offset<T>(ptr: *T, count: uint) -> *T {
+    ret rusti::ptr_offset(ptr, count);
+}
+
+/*
+Function: mut_offset
+
+Calculate the offset from a mutable pointer
+*/
+fn mut_offset<T>(ptr: *mutable T, count: uint) -> *mutable T {
+    ret rusti::ptr_offset(ptr as *T, count) as *mutable T;
+}
+
+
+/*
+Function: null
+
+Create an unsafe null pointer
+*/
+fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }
diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs
new file mode 100644
index 00000000000..be350baadbe
--- /dev/null
+++ b/src/libstd/rand.rs
@@ -0,0 +1,86 @@
+/*
+Module: rand
+
+Random number generation
+*/
+#[abi = "cdecl"]
+native mod rustrt {
+    type rctx;
+    fn rand_new() -> rctx;
+    fn rand_next(c: rctx) -> u32;
+    fn rand_free(c: rctx);
+}
+
+/* Section: Types */
+
+/*
+Obj: rng
+
+A random number generator
+*/
+type rng = obj {
+    /*
+    Method: next
+
+    Return the next random integer
+    */
+    fn next() -> u32;
+
+    /*
+    Method: next_float
+
+    Return the next random float
+    */
+    fn next_float() -> float;
+
+    /*
+    Method: gen_str
+
+    Return a random string composed of A-Z, a-z, 0-9.
+    */
+    fn gen_str(len: uint) -> str;
+};
+
+resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }
+
+/* Section: Operations */
+
+/*
+Function: mk_rng
+
+Create a random number generator
+*/
+fn mk_rng() -> rng {
+    obj rt_rng(c: @rand_res) {
+        fn next() -> u32 { ret rustrt::rand_next(**c); }
+        fn next_float() -> float {
+          let u1 = rustrt::rand_next(**c) as float;
+          let u2 = rustrt::rand_next(**c) as float;
+          let u3 = rustrt::rand_next(**c) as float;
+          let scale = u32::max_value as float;
+          ret ((u1 / scale + u2) / scale + u3) / scale;
+        }
+        fn gen_str(len: uint) -> str {
+            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+                          "abcdefghijklmnopqrstuvwxyz" +
+                          "0123456789";
+            let s = "";
+            let i = 0u;
+            while (i < len) {
+                let n = rustrt::rand_next(**c) as uint %
+                    str::char_len(charset);
+                s = s + str::from_char(str::char_at(charset, n));
+                i += 1u;
+            }
+            s
+        }
+    }
+    ret rt_rng(@rand_res(rustrt::rand_new()));
+}
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/result.rs b/src/libstd/result.rs
new file mode 100644
index 00000000000..550f53470bb
--- /dev/null
+++ b/src/libstd/result.rs
@@ -0,0 +1,112 @@
+/*
+Module: result
+
+A type representing either success or failure
+*/
+
+/* Section: Types */
+
+/*
+Tag: t
+
+The result type
+*/
+tag t<T, U> {
+    /*
+    Variant: ok
+
+    Contains the result value
+    */
+    ok(T);
+    /*
+    Variant: err
+
+    Contains the error value
+    */
+    err(U);
+}
+
+/* Section: Operations */
+
+/*
+Function: get
+
+Get the value out of a successful result
+
+Failure:
+
+If the result is an error
+*/
+fn get<T, U>(res: t<T, U>) -> T {
+    alt res {
+      ok(t) { t }
+      err(_) {
+        // FIXME: Serialize the error value
+        // and include it in the fail message
+        fail "get called on error result";
+      }
+    }
+}
+
+/*
+Function: get_err
+
+Get the value out of an error result
+
+Failure:
+
+If the result is not an error
+*/
+fn get_err<T, U>(res: t<T, U>) -> U {
+    alt res {
+      err(u) { u }
+      ok(_) {
+        fail "get_error called on ok result";
+      }
+    }
+}
+
+/*
+Function: success
+
+Returns true if the result is <ok>
+*/
+fn success<T, U>(res: t<T, U>) -> bool {
+    alt res {
+      ok(_) { true }
+      err(_) { false }
+    }
+}
+
+/*
+Function: failure
+
+Returns true if the result is <error>
+*/
+fn failure<T, U>(res: t<T, U>) -> bool {
+    !success(res)
+}
+
+/*
+Function: chain
+
+Call a function based on a previous result
+
+If `res` is <ok> then the value is extracted and passed to `op` whereupon
+`op`s result is returned. if `res` is <err> then it is immediately returned.
+This function can be used to compose the results of two functions.
+
+Example:
+
+> let res = chain(read_file(file), { |buf|
+>   ok(parse_buf(buf))
+> })
+
+*/
+fn chain<T, copy U, copy V>(res: t<T, V>, op: block(T) -> t<U, V>)
+    -> t<U, V> {
+    alt res {
+      ok(t) { op(t) }
+      err(e) { err(e) }
+    }
+}
diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs
new file mode 100644
index 00000000000..19819a968bf
--- /dev/null
+++ b/src/libstd/rope.rs
@@ -0,0 +1,1337 @@
+/*
+Module: rope
+
+
+High-level text containers.
+
+Ropes are a high-level representation of text that offers
+much better performance than strings for common operations,
+and generally reduce memory allocations and copies, while only
+entailing a small degradation of less common operations.
+
+More precisely, where a string is represented as a memory buffer,
+a rope is a tree structure whose leaves are slices of immutable
+strings. Therefore, concatenation, appending, prepending, substrings,
+etc. are operations that require only trivial tree manipulation,
+generally without having to copy memory. In addition, the tree
+structure of ropes makes them suitable as a form of index to speed-up
+access to Unicode characters by index in long chunks of text.
+
+The following operations are algorithmically faster in ropes:
+- extracting a subrope is logarithmic (linear in strings);
+- appending/prepending is near-constant time (linear in strings);
+- concatenation is near-constant time (linear in strings);
+- char length is constant-time (linear in strings);
+- access to a character by index is logarithmic (linear in strings);
+ */
+
+
+
+
+/*
+ Type: rope
+
+ The type of ropes.
+ */
+type rope = node::root;
+
+/*
+ Section: Creating a rope
+ */
+
+/*
+ Function:empty
+
+ Create an empty rope
+ */
+fn empty() -> rope {
+   ret node::empty;
+}
+
+/*
+ Function: of_str
+
+ Adopt a string as a rope.
+
+ Parameters:
+
+str - A valid string.
+
+ Returns:
+
+A rope representing the same string as `str`. Depending of the length
+of `str`, this rope may be empty, flat or complex.
+
+Performance notes:
+- this operation does not copy the string;
+- the function runs in linear time.
+ */
+fn of_str(str: @str) -> rope {
+    ret of_substr(str, 0u, str::byte_len(*str));
+}
+
+/*
+Function: of_substr
+
+As `of_str` but for a substring.
+
+Performance note:
+- this operation does not copy the substring.
+
+Parameters:
+
+byte_offset - The offset of `str` at which the rope starts.
+byte_len    - The number of bytes of `str` to use.
+
+Returns:
+
+A rope representing the same string as
+`str::substr(str, byte_offset, byte_len)`.
+Depending on `byte_len`, this rope may be empty, flat or complex.
+
+Safety notes:
+- this function does _not_ check the validity of the substring;
+- this function fails if `byte_offset` or `byte_len` do not match `str`.
+ */
+fn of_substr(str: @str, byte_offset: uint, byte_len: uint) -> rope {
+    if byte_len == 0u { ret node::empty; }
+    if byte_offset + byte_len  > str::byte_len(*str) { fail; }
+    ret node::content(node::of_substr(str, byte_offset, byte_len));
+}
+
+/*
+Section: Adding things to a rope
+ */
+
+/*
+Function: append_char
+
+Add one char to the end of the rope
+
+Performance note:
+- this function executes in near-constant time
+ */
+fn append_char(rope: rope, char: char) -> rope {
+    ret append_str(rope, @str::from_chars([char]));
+}
+
+/*
+Function: append_str
+
+Add one string to the end of the rope
+
+Performance note:
+- this function executes in near-linear time
+ */
+fn append_str(rope: rope, str: @str) -> rope {
+    ret append_rope(rope, of_str(str))
+}
+
+/*
+Function: prepend_char
+
+Add one char to the beginning of the rope
+
+Performance note:
+- this function executes in near-constant time
+ */
+fn prepend_char(rope: rope, char: char) -> rope {
+    ret prepend_str(rope, @str::from_chars([char]));
+}
+
+/*
+Function: prepend_str
+
+Add one string to the beginning of the rope
+
+Performance note:
+- this function executes in near-linear time
+ */
+fn prepend_str(rope: rope, str: @str) -> rope {
+    ret append_rope(of_str(str), rope)
+}
+
+/*
+Function: append_rope
+
+Concatenate two ropes
+ */
+fn append_rope(left: rope, right: rope) -> rope {
+   alt(left) {
+     node::empty. { ret right; }
+     node::content(left_content) {
+       alt(right) {
+         node::empty. { ret left; }
+     node::content(right_content) {
+           ret node::content(node::concat2(left_content, right_content));
+     }
+       }
+     }
+   }
+}
+
+/*
+Function: concat
+
+Concatenate many ropes.
+
+If the ropes are balanced initially and have the same height, the resulting
+rope remains balanced. However, this function does not take any further
+measure to ensure that the result is balanced.
+ */
+fn concat(v: [rope]) -> rope {
+    //Copy `v` into a mutable vector
+    let len   = vec::len(v);
+    if len == 0u { ret node::empty; }
+    let ropes = vec::init_elt_mut(v[0], len);
+    uint::range(1u, len) {|i|
+       ropes[i] = v[i];
+    }
+
+    //Merge progresively
+    while len > 1u {
+        uint::range(0u, len/2u) {|i|
+            ropes[i] = append_rope(ropes[2u*i], ropes[2u*i+1u]);
+        }
+        if len%2u != 0u {
+            ropes[len/2u] = ropes[len - 1u];
+            len = len/2u + 1u;
+        } else {
+            len = len/2u;
+        }
+    }
+
+    //Return final rope
+    ret ropes[0];
+}
+
+
+/*
+Section: Keeping ropes healthy
+ */
+
+
+
+/*
+Function: bal
+
+Balance a rope.
+
+Returns:
+
+A copy of the rope in which small nodes have been grouped in memory,
+and with a reduced height.
+
+If you perform numerous rope concatenations, it is generally a good idea
+to rebalance your rope at some point, before using it for other purposes.
+ */
+fn bal(rope:rope) -> rope {
+    alt(rope) {
+      node::empty. { ret rope }
+      node::content(x) {
+        alt(node::bal(x)) {
+          option::none.   { rope }
+          option::some(y) { node::content(y) }
+        }
+      }
+    }
+}
+
+/*
+Section: Transforming ropes
+ */
+
+
+/*
+Function: sub_chars
+
+Extract a subrope from a rope.
+
+Performance note:
+- on a balanced rope, this operation takes algorithmic time;
+- this operation does not involve any copying
+
+Safety note:
+- this function fails if char_offset/char_len do not represent
+valid positions in rope
+ */
+fn sub_chars(rope: rope, char_offset: uint, char_len: uint) -> rope {
+    if char_len == 0u { ret node::empty; }
+    alt(rope) {
+      node::empty. { fail }
+      node::content(node) {
+        if char_len > node::char_len(node) { fail }
+        else {
+            ret node::content(node::sub_chars(node, char_offset, char_len))
+        }
+      }
+    }
+}
+
+/*
+Function:sub_bytes
+
+Extract a subrope from a rope.
+
+Performance note:
+- on a balanced rope, this operation takes algorithmic time;
+- this operation does not involve any copying
+
+Safety note:
+- this function fails if byte_offset/byte_len do not represent
+valid positions in rope
+ */
+fn sub_bytes(rope: rope, byte_offset: uint, byte_len: uint) -> rope {
+    if byte_len == 0u { ret node::empty; }
+    alt(rope) {
+      node::empty. { fail }
+      node::content(node) {
+        if byte_len > node::byte_len(node) { fail }
+        else {
+            ret node::content(node::sub_bytes(node, byte_offset, byte_len))
+        }
+      }
+    }
+}
+
+/*
+Section: Comparing ropes
+ */
+
+/*
+Function: cmp
+
+Compare two ropes by Unicode lexicographical order.
+
+This function compares only the contents of the rope, not their structure.
+
+Returns:
+
+A negative value if `left < right`, 0 if eq(left, right) or a positive
+value if `left > right`
+ */
+fn cmp(left: rope, right: rope) -> int {
+    alt((left, right)) {
+      (node::empty., node::empty.) { ret 0; }
+      (node::empty., _)     { ret -1;}
+      (_, node::empty.)     { ret  1;}
+      (node::content(a), node::content(b)) {
+        ret node::cmp(a, b);
+      }
+    }
+}
+
+/*
+Function: eq
+
+Returns:
+
+ `true` if both ropes have the same content (regardless of their structure),
+`false` otherwise
+*/
+fn eq(left: rope, right: rope) -> bool {
+    ret cmp(left, right) == 0;
+}
+
+/*
+Function: le
+
+Parameters
+  left - an arbitrary rope
+  right - an arbitrary rope
+
+Returns:
+
+ `true` if `left <= right` in lexicographical order (regardless of their
+structure), `false` otherwise
+*/
+fn le(left: rope, right: rope) -> bool {
+    ret cmp(left, right) <= 0;
+}
+
+/*
+Function: lt
+
+Parameters
+  left - an arbitrary rope
+  right - an arbitrary rope
+
+Returns:
+
+ `true` if `left < right` in lexicographical order (regardless of their
+structure), `false` otherwise
+*/
+fn lt(left: rope, right: rope) -> bool {
+    ret cmp(left, right) < 0;
+}
+
+/*
+Function: ge
+
+Parameters
+  left - an arbitrary rope
+  right - an arbitrary rope
+
+Returns:
+
+ `true` if `left >= right` in lexicographical order (regardless of their
+structure), `false` otherwise
+*/
+fn ge(left: rope, right: rope) -> bool {
+    ret cmp(left, right) >= 0;
+}
+
+/*
+Function: gt
+
+Parameters
+  left - an arbitrary rope
+  right - an arbitrary rope
+
+Returns:
+
+ `true` if `left > right` in lexicographical order (regardless of their
+structure), `false` otherwise
+*/
+fn gt(left: rope, right: rope) -> bool {
+    ret cmp(left, right) > 0;
+}
+
+/*
+Section: Iterating
+ */
+
+/*
+Function: loop_chars
+
+Loop through a rope, char by char
+
+While other mechanisms are available, this is generally the best manner
+of looping through the contents of a rope char by char. If you prefer a
+loop that iterates through the contents string by string (e.g. to print
+the contents of the rope or output it to the system), however,
+you should rather use `traverse_components`.
+
+Parameters:
+rope - A rope to traverse. It may be empty.
+it - A block to execute with each consecutive character of the rope.
+Return `true` to continue, `false` to stop.
+
+Returns:
+
+`true` If execution proceeded correctly, `false` if it was interrupted,
+that is if `it` returned `false` at any point.
+ */
+fn loop_chars(rope: rope, it: block(char) -> bool) -> bool {
+   alt(rope) {
+      node::empty. { ret true }
+      node::content(x) { ret node::loop_chars(x, it) }
+   }
+}
+
+/*
+Function: iter_chars
+
+Loop through a rope, char by char, until the end.
+
+Parameters:
+rope - A rope to traverse. It may be empty.
+it - A block to execute with each consecutive character of the rope.
+ */
+fn iter_chars(rope: rope, it: block(char)) {
+    loop_chars(rope) {|x|
+        it(x);
+        ret true
+    }
+}
+
+/*
+Function: loop_leaves
+
+Loop through a rope, string by string
+
+While other mechanisms are available, this is generally the best manner of
+looping through the contents of a rope string by string, which may be useful
+e.g. to print strings as you see them (without having to copy their
+contents into a new string), to send them to then network, to write them to
+a file, etc.. If you prefer a loop that iterates through the contents
+char by char (e.g. to search for a char), however, you should rather
+use `traverse`.
+
+Parameters:
+
+rope - A rope to traverse. It may be empty.
+it - A block to execute with each consecutive string component of the rope.
+Return `true` to continue, `false` to stop.
+
+Returns:
+
+`true` If execution proceeded correctly, `false` if it was interrupted,
+that is if `it` returned `false` at any point.
+ */
+fn loop_leaves(rope: rope, it: block(node::leaf) -> bool) -> bool{
+   alt(rope) {
+      node::empty. { ret true }
+      node::content(x) {ret node::loop_leaves(x, it)}
+   }
+}
+
+mod iterator {
+    mod leaf {
+        fn start(rope: rope) -> node::leaf_iterator::t {
+            alt(rope) {
+              node::empty.     { ret node::leaf_iterator::empty() }
+              node::content(x) { ret node::leaf_iterator::start(x) }
+            }
+        }
+        fn next(it: node::leaf_iterator::t) -> option::t<node::leaf> {
+            ret node::leaf_iterator::next(it);
+        }
+    }
+    mod char {
+        fn start(rope: rope) -> node::char_iterator::t {
+            alt(rope) {
+              node::empty.   { ret node::char_iterator::empty() }
+              node::content(x) { ret node::char_iterator::start(x) }
+            }
+        }
+        fn next(it: node::char_iterator::t) -> option::t<char> {
+            ret node::char_iterator::next(it)
+        }
+    }
+}
+
+/*
+ Section: Rope properties
+ */
+
+/*
+ Function: height
+
+ Returns: The height of the rope, i.e. a bound on the number of
+operations which must be performed during a character access before
+finding the leaf in which a character is contained.
+
+ Performance note: Constant time.
+*/
+fn height(rope: rope) -> uint {
+   alt(rope) {
+      node::empty.    { ret 0u; }
+      node::content(x) { ret node::height(x); }
+   }
+}
+
+
+
+/*
+ Function: char_len
+
+ Returns: The number of character in the rope
+
+ Performance note: Constant time.
+ */
+pure fn char_len(rope: rope) -> uint {
+   alt(rope) {
+     node::empty.           { ret 0u; }
+     node::content(x)       { ret node::char_len(x) }
+   }
+}
+
+/*
+ Function: char_len
+
+ Returns: The number of bytes in the rope
+
+ Performance note: Constant time.
+ */
+pure fn byte_len(rope: rope) -> uint {
+   alt(rope) {
+     node::empty.           { ret 0u; }
+     node::content(x)       { ret node::byte_len(x) }
+   }
+}
+
+/*
+ Function: char_at
+
+ Parameters:
+  pos - A position in the rope
+
+ Returns: The character at position `pos`
+
+ Safety notes: The function will fail if `pos`
+ is not a valid position in the rope.
+
+ Performance note: This function executes in a time
+ proportional to the height of the rope + the (bounded)
+ length of the largest leaf.
+ */
+fn char_at(rope: rope, pos: uint) -> char {
+   alt(rope) {
+      node::empty. { fail }
+      node::content(x) { ret node::char_at(x, pos) }
+   }
+}
+
+
+/*
+ Section: Implementation
+*/
+mod node {
+
+    /*
+     Enum: node::root
+
+     Implementation of type `rope`
+
+     Constants:
+       empty   - An empty rope
+       content - A non-empty rope
+    */
+    tag root {
+        empty;
+        content(@node);
+    }
+
+    /*
+     Struct: node::leaf
+
+     A text component in a rope.
+
+     This is actually a slice in a rope, so as to ensure maximal sharing.
+    */
+    type leaf = {
+
+    /*
+     Field: byte_offset
+
+     The number of bytes skipped in `content`
+    */
+    byte_offset: uint,
+
+    /*
+     Field: byte_len
+
+     The number of bytes of `content` to use
+    */
+    byte_len:    uint,
+
+    /*
+     Field: char_len
+
+
+     The number of chars in the leaf.
+    */
+    char_len:   uint,
+
+    /*
+    Field: content
+
+    Contents of the leaf.
+
+    Note that we can have `char_len < str::char_len(content)`, if this
+    leaf is only a subset of the string. Also note that the string
+    can be shared between several ropes, e.g. for indexing purposes.
+    */
+    content:    @str
+    };
+
+
+    /*
+     Struct node::concat
+
+     A node obtained from the concatenation of two other nodes
+    */
+    type concat = {
+
+        /*
+        Field: left
+
+        The node containing the beginning of the text.
+        */
+        left:     @node,//TODO: Perhaps a `vec` instead of `left`/`right`
+
+        /*
+        Field: right
+
+        The node containing the end of the text.
+        */
+        right:    @node,
+
+        /*
+        Field: char_len
+
+        The number of chars contained in all leaves of this node.
+        */
+        char_len: uint,
+
+        /*
+        Field: byte_len
+
+        The number of bytes in the subrope.
+
+        Used to pre-allocate the correct amount of storage for serialization.
+        */
+        byte_len: uint,
+
+        /*
+        Field: height
+
+        Height of the subrope.
+
+        Used for rebalancing and to allocate stacks for
+        traversals.
+        */
+        height:   uint
+    };
+
+    /*
+    Enum: node::node
+
+    leaf - A leaf consisting in a `str`
+    concat - The concatenation of two ropes
+    */
+    tag node {
+        leaf(leaf);
+        concat(concat);
+    }
+
+    /*
+    The maximal number of chars that _should_ be permitted in a single node.
+
+    This is not a strict value
+     */
+    const hint_max_leaf_char_len: uint = 256u;
+
+    /*
+    The maximal height that _should_ be permitted in a tree.
+
+    This is not a strict value
+     */
+    const hint_max_node_height:   uint = 16u;
+
+    /*
+    Function: of_str
+
+    Adopt a string as a node.
+
+    If the string is longer than `max_leaf_char_len`, it is
+    logically split between as many leaves as necessary. Regardless,
+    the string itself is not copied.
+
+    Performance note: The complexity of this function is linear in
+    the length of `str`.
+     */
+    fn of_str(str: @str) -> @node {
+        ret of_substr(str, 0u, str::byte_len(*str));
+    }
+
+    /*
+    Function: of_substr
+
+    Adopt a slice of a string as a node.
+
+    If the slice is longer than `max_leaf_char_len`, it is logically split
+    between as many leaves as necessary. Regardless, the string itself
+    is not copied.
+
+    Parameters:
+    byte_start - The byte offset where the slice of `str` starts.
+    byte_len   - The number of bytes from `str` to use.
+
+    Safety note:
+    - Behavior is undefined if `byte_start` or `byte_len` do not represent
+     valid positions in `str`
+     */
+    fn of_substr(str: @str, byte_start: uint, byte_len: uint) -> @node {
+        ret of_substr_unsafer(str, byte_start, byte_len,
+                  str::char_len_range(*str, byte_start, byte_len));
+    }
+
+    /*
+    Function: of_substr_unsafer
+
+    Adopt a slice of a string as a node.
+
+    If the slice is longer than `max_leaf_char_len`, it is logically split
+    between as many leaves as necessary. Regardless, the string itself
+    is not copied.
+
+    byte_start - The byte offset where the slice of `str` starts.
+    byte_len   - The number of bytes from `str` to use.
+    char_len   - The number of chars in `str` in the interval
+          [byte_start, byte_start+byte_len(
+
+    Safety note:
+    - Behavior is undefined if `byte_start` or `byte_len` do not represent
+     valid positions in `str`
+    - Behavior is undefined if `char_len` does not accurately represent the
+     number of chars between byte_start and byte_start+byte_len
+    */
+    fn of_substr_unsafer(str: @str, byte_start: uint, byte_len: uint,
+                          char_len: uint) -> @node {
+        assert(byte_start + byte_len <= str::byte_len(*str));
+        let candidate = @leaf({
+                byte_offset: byte_start,
+                byte_len:    byte_len,
+                char_len:    char_len,
+                content:     str});
+        if char_len <= hint_max_leaf_char_len {
+            ret candidate;
+        } else {
+            //Firstly, split `str` in slices of hint_max_leaf_char_len
+            let leaves = uint::div_ceil(char_len, hint_max_leaf_char_len);
+            //Number of leaves
+            let nodes  = vec::init_elt_mut(candidate, leaves);
+
+            let i = 0u;
+            let offset = byte_start;
+            let first_leaf_char_len =
+                if char_len%hint_max_leaf_char_len == 0u {
+                  hint_max_leaf_char_len
+                } else {
+                char_len%hint_max_leaf_char_len
+               };
+            while i < leaves {
+                let chunk_char_len: uint =
+                    if i == 0u  { first_leaf_char_len }
+                    else { hint_max_leaf_char_len };
+                let chunk_byte_len =
+                    str::byte_len_range(*str, offset, chunk_char_len);
+                nodes[i] = @leaf({
+                    byte_offset: offset,
+                    byte_len:    chunk_byte_len,
+                    char_len:    chunk_char_len,
+                    content:     str
+                });
+
+                offset += chunk_byte_len;
+                i      += 1u;
+            }
+
+            //Then, build a tree from these slices by collapsing them
+            while leaves > 1u {
+                i = 0u;
+                while i < leaves - 1u {//Concat nodes 0 with 1, 2 with 3 etc.
+                    nodes[i/2u] = concat2(nodes[i], nodes[i + 1u]);
+                    i += 2u;
+                }
+                if i == leaves - 1u {
+                    //And don't forget the last node if it is in even position
+                    nodes[i/2u] = nodes[i];
+                }
+                leaves = uint::div_ceil(leaves, 2u);
+            }
+            ret nodes[0u];
+        }
+    }
+
+    pure fn byte_len(node: @node) -> uint {
+        alt(*node) {//TODO: Could we do this without the pattern-matching?
+          leaf(y)  { ret y.byte_len; }
+          concat(y){ ret y.byte_len; }
+        }
+    }
+
+    pure fn char_len(node: @node) -> uint {
+        alt(*node) {
+          leaf(y)   { ret y.char_len; }
+          concat(y) { ret y.char_len; }
+        }
+    }
+
+
+    /*
+    Function: tree_from_forest_destructive
+
+    Concatenate a forest of nodes into one tree.
+
+    Parameters:
+    forest - The forest. This vector is progressively rewritten during
+    execution and should be discarded as meaningless afterwards.
+    */
+    fn tree_from_forest_destructive(forest: [mutable @node]) -> @node {
+        let i = 0u;
+        let len = vec::len(forest);
+        while len > 1u {
+            i = 0u;
+            while i < len - 1u {//Concat nodes 0 with 1, 2 with 3 etc.
+                let left  = forest[i];
+                let right = forest[i+1u];
+                let left_len = char_len(left);
+                let right_len= char_len(right);
+                let left_height= height(left);
+                let right_height=height(right);
+                if left_len + right_len > hint_max_leaf_char_len {
+                    if left_len <= hint_max_leaf_char_len {
+                        left = flatten(left);
+                        left_height = height(left);
+                    }
+                    if right_len <= hint_max_leaf_char_len {
+                        right = flatten(right);
+                        right_height = height(right);
+                    }
+                }
+                if left_height >= hint_max_node_height {
+                    left = of_substr_unsafer(@serialize_node(left),
+                                             0u,byte_len(left),
+                                             left_len);
+                }
+                if right_height >= hint_max_node_height {
+                    right = of_substr_unsafer(@serialize_node(right),
+                                             0u,byte_len(right),
+                                             right_len);
+                }
+                forest[i/2u] = concat2(left, right);
+                i += 2u;
+            }
+            if i == len - 1u {
+                //And don't forget the last node if it is in even position
+                forest[i/2u] = forest[i];
+            }
+            len = uint::div_ceil(len, 2u);
+        }
+        ret forest[0];
+    }
+
+    fn serialize_node(node: @node) -> str unsafe {
+        let buf = vec::init_elt_mut(0u8, byte_len(node));
+        let offset = 0u;//Current position in the buffer
+        let it = leaf_iterator::start(node);
+        while true {
+            alt(leaf_iterator::next(it)) {
+              option::none. { break; }
+              option::some(x) {
+                //TODO: Replace with memcpy or something similar
+                let local_buf: [u8] = unsafe::reinterpret_cast(*x.content);
+                let i = x.byte_offset;
+                while i < x.byte_len {
+                    buf[offset] = local_buf[i];
+                    offset += 1u;
+                    i      += 1u;
+                }
+                unsafe::leak(local_buf);
+              }
+            }
+        }
+        let str : str = unsafe::reinterpret_cast(buf);
+        unsafe::leak(buf);//TODO: Check if this is correct
+        ret str;
+    }
+
+    /*
+    Function: flatten
+
+    Replace a subtree by a single leaf with the same contents.
+
+    Performance note: This function executes in linear time.
+     */
+    fn flatten(node: @node) -> @node unsafe {
+        alt(*node) {
+          leaf(_) { ret node }
+          concat(x) {
+            ret @leaf({
+                byte_offset: 0u,
+                byte_len:    x.byte_len,
+                char_len:    x.char_len,
+                content:     @serialize_node(node)
+            })
+          }
+        }
+    }
+
+    /*
+    Function: bal
+
+    Balance a node.
+
+    Algorithm:
+    - if the node height is smaller than `hint_max_node_height`, do nothing
+    - otherwise, gather all leaves as a forest, rebuild a balanced node,
+         concatenating small leaves along the way
+
+    Returns:
+    - `option::none` if no transformation happened
+    - `option::some(x)` otherwise, in which case `x` has the same contents
+       as `node` bot lower height and/or fragmentation.
+    */
+    fn bal(node: @node) -> option::t<@node> {
+        if height(node) < hint_max_node_height { ret option::none; }
+        //1. Gather all leaves as a forest
+        let forest = [mutable];
+        let it = leaf_iterator::start(node);
+        while true {
+            alt (leaf_iterator::next(it)) {
+              option::none.   { break; }
+              option::some(x) { forest += [mutable @leaf(x)]; }
+            }
+        }
+        //2. Rebuild tree from forest
+        let root = @*tree_from_forest_destructive(forest);
+        ret option::some(root);
+
+    }
+
+    /*
+    Function: sub_bytes
+
+    Compute the subnode of a node.
+
+    Parameters:
+    node        - A node
+    byte_offset - A byte offset in `node`
+    byte_len    - The number of bytes to return
+
+    Performance notes:
+    - this function performs no copying;
+    - this function executes in a time proportional to the height of `node`.
+
+    Safety notes:
+    - this function fails if `byte_offset` or `byte_len` do not represent
+    valid positions in `node`.
+    */
+    fn sub_bytes(node: @node, byte_offset: uint, byte_len: uint) -> @node {
+        let node        = node;
+        let byte_offset = byte_offset;
+        while true {
+            if byte_offset == 0u && byte_len == node::byte_len(node) {
+                ret node;
+            }
+            alt(*node) {
+              node::leaf(x) {
+                let char_len =
+                    str::char_len_range(*x.content, byte_offset, byte_len);
+                ret @leaf({byte_offset: byte_offset,
+                                byte_len:    byte_len,
+                                char_len:    char_len,
+                                content:     x.content});
+              }
+              node::concat(x) {
+                let left_len: uint = node::byte_len(x.left);
+                if byte_offset <= left_len {
+                    if byte_offset + byte_len <= left_len {
+                        //Case 1: Everything fits in x.left, tail-call
+                        node = x.left;
+                    } else {
+                        //Case 2: A (non-empty, possibly full) suffix
+                        //of x.left and a (non-empty, possibly full) prefix
+                        //of x.right
+                        let left_result  =
+                            sub_bytes(x.left, byte_offset, left_len);
+                        let right_result =
+                            sub_bytes(x.right, 0u, left_len - byte_offset);
+                        ret concat2(left_result, right_result);
+                    }
+                } else {
+                    //Case 3: Everything fits in x.right
+                    byte_offset -= left_len;
+                    node = x.right;
+                }
+              }
+            }
+        }
+        fail;//Note: unreachable
+    }
+
+    /*
+    Function: sub_chars
+
+    Compute the subnode of a node.
+
+    Parameters:
+    node        - A node
+    char_offset - A char offset in `node`
+    char_len    - The number of chars to return
+
+    Performance notes:
+    - this function performs no copying;
+    - this function executes in a time proportional to the height of `node`.
+
+    Safety notes:
+    - this function fails if `char_offset` or `char_len` do not represent
+    valid positions in `node`.
+    */
+    fn sub_chars(node: @node, char_offset: uint, char_len: uint) -> @node {
+        let node        = node;
+        let char_offset = char_offset;
+        while true {
+            alt(*node) {
+              node::leaf(x) {
+                if char_offset == 0u && char_len == x.char_len {
+                    ret node;
+                }
+                let byte_offset =
+                    str::byte_len_range(*x.content, 0u, char_offset);
+                let byte_len    =
+                    str::byte_len_range(*x.content, byte_offset, char_len);
+                ret @leaf({byte_offset: byte_offset,
+                           byte_len:    byte_len,
+                           char_len:    char_len,
+                           content:     x.content});
+              }
+              node::concat(x) {
+                if char_offset == 0u && char_len == x.char_len {ret node;}
+                let left_len : uint = node::char_len(x.left);
+                if char_offset <= left_len {
+                    if char_offset + char_len <= left_len {
+                        //Case 1: Everything fits in x.left, tail call
+                        node        = x.left;
+                    } else {
+                        //Case 2: A (non-empty, possibly full) suffix
+                        //of x.left and a (non-empty, possibly full) prefix
+                        //of x.right
+                        let left_result  =
+                            sub_chars(x.left, char_offset, left_len);
+                        let right_result =
+                            sub_chars(x.right, 0u, left_len - char_offset);
+                        ret concat2(left_result, right_result);
+                    }
+                } else {
+                    //Case 3: Everything fits in x.right, tail call
+                    node = x.right;
+                    char_offset -= left_len;
+                }
+              }
+            }
+        }
+        fail;
+    }
+
+    fn concat2(left: @node, right: @node) -> @node {
+        ret @concat({left    : left,
+                     right   : right,
+             char_len: char_len(left) + char_len(right),
+                     byte_len: byte_len(left) + byte_len(right),
+             height: math::max(height(left), height(right)) + 1u
+                    })
+    }
+
+    fn height(node: @node) -> uint {
+        alt(*node) {
+          leaf(_)   { ret 0u; }
+          concat(x) { ret x.height; }
+        }
+    }
+
+    fn cmp(a: @node, b: @node) -> int {
+        let ita = char_iterator::start(a);
+        let itb = char_iterator::start(b);
+        let result = 0;
+        let pos = 0u;
+        while result == 0 {
+            alt((char_iterator::next(ita), char_iterator::next(itb))) {
+              (option::none., option::none.) {
+                break;
+              }
+              (option::some(chara), option::some(charb)) {
+                result = char::cmp(chara, charb);
+              }
+              (option::some(_), _)         {
+                result = 1;
+              }
+              (_, option::some(_))         {
+                result = -1;
+              }
+            }
+            pos += 1u;
+        }
+        ret result;
+    }
+
+    fn loop_chars(node: @node, it: block(char) -> bool) -> bool {
+        ret loop_leaves(node, {|leaf|
+            ret str::loop_chars_sub(*leaf.content,
+                                    leaf.byte_offset,
+                                    leaf.byte_len, it)
+        })
+    }
+
+    /*
+    Function: loop_leaves
+
+    Loop through a node, leaf by leaf
+
+    Parameters:
+
+    rope - A node to traverse.
+    it - A block to execute with each consecutive leaf of the node.
+    Return `true` to continue, `false` to stop.
+
+    Returns:
+
+    `true` If execution proceeded correctly, `false` if it was interrupted,
+    that is if `it` returned `false` at any point.
+    */
+    fn loop_leaves(node: @node, it: block(leaf) -> bool) -> bool{
+        let current = node;
+        while true {
+            alt(*current) {
+              leaf(x) {
+                ret it(x);
+              }
+              concat(x) {
+                if loop_leaves(x.left, it) { //non tail call
+                    current = x.right;       //tail call
+                } else {
+                    ret false;
+                }
+              }
+            }
+        }
+        fail;//unreachable
+    }
+
+    /*
+    Function: char_at
+
+    Parameters:
+    pos - A position in the rope
+
+    Returns: The character at position `pos`
+
+    Safety notes: The function will fail if `pos`
+    is not a valid position in the rope.
+
+    Performance note: This function executes in a time
+    proportional to the height of the rope + the (bounded)
+    length of the largest leaf.
+    */
+    fn char_at(node: @node, pos: uint) -> char {
+        let node    = node;
+        let pos     = pos;
+        while true {
+            alt *node {
+              leaf(x) {
+                ret str::char_at(*x.content, pos);
+              }
+              concat({left, right, _}) {
+                let left_len = char_len(left);
+                node = if left_len > pos { left }
+                       else { pos -= left_len; right };
+              }
+            }
+        }
+        fail;//unreachable
+    }
+
+    mod leaf_iterator {
+        type t = {
+            stack:            [mutable @node],
+            mutable stackpos: int
+        };
+
+        fn empty() -> t {
+            let stack : [mutable @node] = [mutable];
+            ret {stack: stack, mutable stackpos: -1}
+        }
+
+        fn start(node: @node) -> t {
+            let stack = vec::init_elt_mut(node, height(node)+1u);
+            ret {
+                stack:             stack,
+                mutable stackpos:  0
+            }
+        }
+
+        fn next(it: t) -> option::t<leaf> {
+            if it.stackpos < 0 { ret option::none; }
+            while true {
+                let current = it.stack[it.stackpos];
+                it.stackpos -= 1;
+                alt(*current) {
+                  concat(x) {
+                    it.stackpos += 1;
+                    it.stack[it.stackpos] = x.right;
+                    it.stackpos += 1;
+                    it.stack[it.stackpos] = x.left;
+                  }
+                  leaf(x) {
+                    ret option::some(x);
+                  }
+                }
+            }
+            fail;//unreachable
+        }
+    }
+
+    mod char_iterator {
+        type t = {
+            leaf_iterator: leaf_iterator::t,
+            mutable leaf:  option::t<leaf>,
+            mutable leaf_byte_pos: uint
+        };
+
+        fn start(node: @node) -> t {
+            ret {
+                leaf_iterator: leaf_iterator::start(node),
+                mutable leaf:          option::none,
+                mutable leaf_byte_pos: 0u
+            }
+        }
+
+        fn empty() -> t {
+            ret {
+                leaf_iterator: leaf_iterator::empty(),
+                mutable leaf:  option::none,
+                mutable leaf_byte_pos: 0u
+            }
+        }
+
+        fn next(it: t) -> option::t<char> {
+            while true {
+                alt(get_current_or_next_leaf(it)) {
+                  option::none. { ret option::none; }
+                  option::some(leaf) {
+                    let next_char = get_next_char_in_leaf(it);
+                    alt(next_char) {
+                      option::none. {
+                        cont;
+                      }
+                      option::some(_) {
+                        ret next_char;
+                      }
+                    }
+                  }
+                }
+            }
+            fail;//unreachable
+        }
+
+        fn get_current_or_next_leaf(it: t) -> option::t<leaf> {
+            alt(it.leaf) {
+              option::some(_) { ret it.leaf }
+              option::none. {
+                let next = leaf_iterator::next(it.leaf_iterator);
+                alt(next) {
+                  option::none. { ret option::none }
+                  option::some(leaf) {
+                    it.leaf          = next;
+                    it.leaf_byte_pos = 0u;
+                    ret next;
+                  }
+                }
+              }
+            }
+        }
+
+        fn get_next_char_in_leaf(it: t) -> option::t<char> {
+            alt(it.leaf) {
+              option::none. { ret option::none }
+              option::some(leaf) {
+                if it.leaf_byte_pos >= leaf.byte_len {
+                    //We are actually past the end of the leaf
+                    it.leaf = option::none;
+                    ret option::none
+                } else {
+                    let {ch, next} =
+                        str::char_range_at(*leaf.content,
+                                     it.leaf_byte_pos + leaf.byte_offset);
+                    it.leaf_byte_pos = next - leaf.byte_offset;
+                    ret option::some(ch)
+                }
+              }
+            }
+        }
+    }
+}
+
diff --git a/src/libstd/run_program.rs b/src/libstd/run_program.rs
new file mode 100644
index 00000000000..6f4ad2da3d6
--- /dev/null
+++ b/src/libstd/run_program.rs
@@ -0,0 +1,304 @@
+/*
+Module: run
+
+Process spawning
+*/
+import str::sbuf;
+import ctypes::{fd_t, pid_t};
+
+export program;
+export run_program;
+export start_program;
+export program_output;
+export spawn_process;
+export waitpid;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_run_program(argv: *sbuf, in_fd: fd_t,
+                        out_fd: fd_t, err_fd: fd_t) -> pid_t;
+}
+
+/* Section: Types */
+
+/*
+Resource: program_res
+
+A resource that manages the destruction of a <program> object
+
+program_res ensures that the destroy method is called on a
+program object in order to close open file descriptors.
+*/
+resource program_res(p: program) { p.destroy(); }
+
+/*
+Obj: program
+
+An object representing a child process
+*/
+type program = obj {
+    /*
+    Method: get_id
+
+    Returns the process id of the program
+    */
+    fn get_id() -> pid_t;
+
+    /*
+    Method: input
+
+    Returns an io::writer that can be used to write to stdin
+    */
+    fn input() -> io::writer;
+
+    /*
+    Method: output
+
+    Returns an io::reader that can be used to read from stdout
+    */
+    fn output() -> io::reader;
+
+    /*
+    Method: err
+
+    Returns an io::reader that can be used to read from stderr
+    */
+    fn err() -> io::reader;
+
+    /*
+    Method: close_input
+
+    Closes the handle to the child processes standard input
+    */
+    fn close_input();
+
+    /*
+    Method: finish
+
+    Waits for the child process to terminate. Closes the handle
+    to stdin if necessary.
+    */
+    fn finish() -> int;
+
+    /*
+    Method: destroy
+
+    Closes open handles
+    */
+    fn destroy();
+};
+
+
+/* Section: Operations */
+
+fn arg_vec(prog: str, args: [@str]) -> [sbuf] {
+    let argptrs = str::as_buf(prog, {|buf| [buf] });
+    for arg in args { argptrs += str::as_buf(*arg, {|buf| [buf] }); }
+    argptrs += [ptr::null()];
+    ret argptrs;
+}
+
+/*
+Function: spawn_process
+
+Run a program, providing stdin, stdout and stderr handles
+
+Parameters:
+
+prog - The path to an executable
+args - Vector of arguments to pass to the child process
+in_fd - A file descriptor for the child to use as std input
+out_fd - A file descriptor for the child to use as std output
+err_fd - A file descriptor for the child to use as std error
+
+Returns:
+
+The process id of the spawned process
+*/
+fn spawn_process(prog: str, args: [str], in_fd: fd_t,
+                 out_fd: fd_t, err_fd: fd_t)
+   -> pid_t unsafe {
+    // Note: we have to hold on to these vector references while we hold a
+    // pointer to their buffers
+    let prog = prog;
+    let args = vec::map({|arg| @arg }, args);
+    let argv = arg_vec(prog, args);
+    let pid =
+        rustrt::rust_run_program(vec::unsafe::to_ptr(argv), in_fd, out_fd,
+                                 err_fd);
+    ret pid;
+}
+
+/*
+Function: run_program
+
+Spawns a process and waits for it to terminate
+
+Parameters:
+
+prog - The path to an executable
+args - Vector of arguments to pass to the child process
+
+Returns:
+
+The process id
+*/
+fn run_program(prog: str, args: [str]) -> int {
+    ret waitpid(spawn_process(prog, args, 0i32, 0i32, 0i32));
+}
+
+/*
+Function: start_program
+
+Spawns a process and returns a boxed <program_res>
+
+The returned value is a boxed resource containing a <program> object that can
+be used for sending and recieving data over the standard file descriptors.
+The resource will ensure that file descriptors are closed properly.
+
+Parameters:
+
+prog - The path to an executable
+args - Vector of arguments to pass to the child process
+
+Returns:
+
+A boxed resource of <program>
+*/
+fn start_program(prog: str, args: [str]) -> @program_res {
+    let pipe_input = os::pipe();
+    let pipe_output = os::pipe();
+    let pipe_err = os::pipe();
+    let pid =
+        spawn_process(prog, args, pipe_input.in, pipe_output.out,
+                      pipe_err.out);
+
+    if pid == -1i32 { fail; }
+    os::libc::close(pipe_input.in);
+    os::libc::close(pipe_output.out);
+    os::libc::close(pipe_err.out);
+    obj new_program(pid: pid_t,
+                    mutable in_fd: fd_t,
+                    out_file: os::libc::FILE,
+                    err_file: os::libc::FILE,
+                    mutable finished: bool) {
+        fn get_id() -> pid_t { ret pid; }
+        fn input() -> io::writer {
+            ret io::new_writer(io::fd_buf_writer(in_fd, option::none));
+        }
+        fn output() -> io::reader {
+            ret io::new_reader(io::FILE_buf_reader(out_file, option::none));
+        }
+        fn err() -> io::reader {
+            ret io::new_reader(io::FILE_buf_reader(err_file, option::none));
+        }
+        fn close_input() {
+            let invalid_fd = -1i32;
+            if in_fd != invalid_fd {
+                os::libc::close(in_fd);
+                in_fd = invalid_fd;
+            }
+        }
+        fn finish() -> int {
+            if finished { ret 0; }
+            finished = true;
+            self.close_input();
+            ret waitpid(pid);
+        }
+        fn destroy() {
+            self.finish();
+            os::libc::fclose(out_file);
+            os::libc::fclose(err_file);
+        }
+    }
+    ret @program_res(new_program(pid, pipe_input.out,
+                                 os::fd_FILE(pipe_output.in),
+                                 os::fd_FILE(pipe_err.in), false));
+}
+
+fn read_all(rd: io::reader) -> str {
+    let buf = "";
+    while !rd.eof() {
+        let bytes = rd.read_bytes(4096u);
+        buf += str::unsafe_from_bytes(bytes);
+    }
+    ret buf;
+}
+
+/*
+Function: program_output
+
+Spawns a process, waits for it to exit, and returns the exit code, and
+contents of stdout and stderr.
+
+Parameters:
+
+prog - The path to an executable
+args - Vector of arguments to pass to the child process
+
+Returns:
+
+A record, {status: int, out: str, err: str} containing the exit code,
+the contents of stdout and the contents of stderr.
+*/
+fn program_output(prog: str, args: [str]) ->
+   {status: int, out: str, err: str} {
+    let pr = start_program(prog, args);
+    pr.close_input();
+    let out = read_all(pr.output());
+    let err = read_all(pr.err());
+    ret {status: pr.finish(), out: out, err: err};
+}
+
+/*
+Function: waitpid
+
+Waits for a process to exit and returns the exit code
+*/
+fn waitpid(pid: pid_t) -> int {
+    ret waitpid_os(pid);
+
+    #[cfg(target_os = "win32")]
+    fn waitpid_os(pid: pid_t) -> int {
+        os::waitpid(pid) as int
+    }
+
+    #[cfg(target_os = "linux")]
+    #[cfg(target_os = "macos")]
+    fn waitpid_os(pid: pid_t) -> int {
+        #[cfg(target_os = "linux")]
+        fn WIFEXITED(status: i32) -> bool {
+            (status & 0xffi32) == 0i32
+        }
+
+        #[cfg(target_os = "macos")]
+        fn WIFEXITED(status: i32) -> bool {
+            (status & 0x7fi32) == 0i32
+        }
+
+        #[cfg(target_os = "linux")]
+        fn WEXITSTATUS(status: i32) -> i32 {
+            (status >> 8i32) & 0xffi32
+        }
+
+        #[cfg(target_os = "macos")]
+        fn WEXITSTATUS(status: i32) -> i32 {
+            status >> 8i32
+        }
+
+        let status = os::waitpid(pid);
+        ret if WIFEXITED(status) {
+            WEXITSTATUS(status) as int
+        } else {
+            1
+        };
+    }
+}
+
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/sha1.rs b/src/libstd/sha1.rs
new file mode 100644
index 00000000000..a51cbdc65d1
--- /dev/null
+++ b/src/libstd/sha1.rs
@@ -0,0 +1,294 @@
+/*
+Module: sha1
+
+An implementation of the SHA-1 cryptographic hash.
+
+First create a <sha1> object using the <mk_sha1> constructor, then
+feed it input using the <input> or <input_str> methods, which may be
+called any number of times.
+
+After the entire input has been fed to the hash read the result using
+the <result> or <result_str> methods.
+
+The <sha1> object may be reused to create multiple hashes by calling
+the <reset> method.
+*/
+
+/*
+ * A SHA-1 implementation derived from Paul E. Jones's reference
+ * implementation, which is written for clarity, not speed. At some
+ * point this will want to be rewritten.
+ */
+export sha1;
+export mk_sha1;
+
+/* Section: Types */
+
+/*
+Obj: sha1
+
+The SHA-1 object
+*/
+type sha1 = obj {
+    /*
+    Method: input
+
+    Provide message input as bytes
+    */
+    fn input([u8]);
+    /*
+    Method: input_str
+
+    Provide message input as string
+    */
+    fn input_str(str);
+    /*
+    Method: result
+
+    Read the digest as a vector of 20 bytes. After calling this no further
+    input may be provided until reset is called.
+    */
+    fn result() -> [u8];
+    /*
+    Method: result_str
+
+    Read the digest as a hex string. After calling this no further
+    input may be provided until reset is called.
+    */
+    fn result_str() -> str;
+    /*
+    Method: reset
+
+    Reset the SHA-1 state for reuse
+    */
+    fn reset();
+};
+
+/* Section: Operations */
+
+// Some unexported constants
+const digest_buf_len: uint = 5u;
+const msg_block_len: uint = 64u;
+const work_buf_len: uint = 80u;
+const k0: u32 = 0x5A827999u32;
+const k1: u32 = 0x6ED9EBA1u32;
+const k2: u32 = 0x8F1BBCDCu32;
+const k3: u32 = 0xCA62C1D6u32;
+
+
+/*
+Function: mk_sha1
+
+Construct a <sha1> object
+*/
+fn mk_sha1() -> sha1 {
+    type sha1state =
+        {h: [mutable u32],
+         mutable len_low: u32,
+         mutable len_high: u32,
+         msg_block: [mutable u8],
+         mutable msg_block_idx: uint,
+         mutable computed: bool,
+         work_buf: [mutable u32]};
+
+    fn add_input(st: sha1state, msg: [u8]) {
+        // FIXME: Should be typestate precondition
+        assert (!st.computed);
+        for element: u8 in msg {
+            st.msg_block[st.msg_block_idx] = element;
+            st.msg_block_idx += 1u;
+            st.len_low += 8u32;
+            if st.len_low == 0u32 {
+                st.len_high += 1u32;
+                if st.len_high == 0u32 {
+                    // FIXME: Need better failure mode
+
+                    fail;
+                }
+            }
+            if st.msg_block_idx == msg_block_len { process_msg_block(st); }
+        }
+    }
+    fn process_msg_block(st: sha1state) {
+        // FIXME: Make precondition
+        assert (vec::len(st.h) == digest_buf_len);
+        assert (vec::len(st.work_buf) == work_buf_len);
+        let t: int; // Loop counter
+        let w = st.work_buf;
+
+        // Initialize the first 16 words of the vector w
+        t = 0;
+        while t < 16 {
+            let tmp;
+            tmp = (st.msg_block[t * 4] as u32) << 24u32;
+            tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32;
+            tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32;
+            tmp = tmp | (st.msg_block[t * 4 + 3] as u32);
+            w[t] = tmp;
+            t += 1;
+        }
+
+        // Initialize the rest of vector w
+        while t < 80 {
+            let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
+            w[t] = circular_shift(1u32, val);
+            t += 1;
+        }
+        let a = st.h[0];
+        let b = st.h[1];
+        let c = st.h[2];
+        let d = st.h[3];
+        let e = st.h[4];
+        let temp: u32;
+        t = 0;
+        while t < 20 {
+            temp = circular_shift(5u32, a) + (b & c | !b & d) + e + w[t] + k0;
+            e = d;
+            d = c;
+            c = circular_shift(30u32, b);
+            b = a;
+            a = temp;
+            t += 1;
+        }
+        while t < 40 {
+            temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k1;
+            e = d;
+            d = c;
+            c = circular_shift(30u32, b);
+            b = a;
+            a = temp;
+            t += 1;
+        }
+        while t < 60 {
+            temp =
+                circular_shift(5u32, a) + (b & c | b & d | c & d) + e + w[t] +
+                    k2;
+            e = d;
+            d = c;
+            c = circular_shift(30u32, b);
+            b = a;
+            a = temp;
+            t += 1;
+        }
+        while t < 80 {
+            temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k3;
+            e = d;
+            d = c;
+            c = circular_shift(30u32, b);
+            b = a;
+            a = temp;
+            t += 1;
+        }
+        st.h[0] = st.h[0] + a;
+        st.h[1] = st.h[1] + b;
+        st.h[2] = st.h[2] + c;
+        st.h[3] = st.h[3] + d;
+        st.h[4] = st.h[4] + e;
+        st.msg_block_idx = 0u;
+    }
+    fn circular_shift(bits: u32, word: u32) -> u32 {
+        ret word << bits | word >> 32u32 - bits;
+    }
+    fn mk_result(st: sha1state) -> [u8] {
+        if !st.computed { pad_msg(st); st.computed = true; }
+        let rs: [u8] = [];
+        for hpart: u32 in st.h {
+            let a = hpart >> 24u32 & 0xFFu32 as u8;
+            let b = hpart >> 16u32 & 0xFFu32 as u8;
+            let c = hpart >> 8u32 & 0xFFu32 as u8;
+            let d = hpart & 0xFFu32 as u8;
+            rs += [a, b, c, d];
+        }
+        ret rs;
+    }
+
+    /*
+     * According to the standard, the message must be padded to an even
+     * 512 bits.  The first padding bit must be a '1'.  The last 64 bits
+     * represent the length of the original message.  All bits in between
+     * should be 0.  This function will pad the message according to those
+     * rules by filling the msg_block vector accordingly.  It will also
+     * call process_msg_block() appropriately.  When it returns, it
+     * can be assumed that the message digest has been computed.
+     */
+    fn pad_msg(st: sha1state) {
+        // FIXME: Should be a precondition
+        assert (vec::len(st.msg_block) == msg_block_len);
+
+        /*
+         * Check to see if the current message block is too small to hold
+         * the initial padding bits and length.  If so, we will pad the
+         * block, process it, and then continue padding into a second block.
+         */
+        if st.msg_block_idx > 55u {
+            st.msg_block[st.msg_block_idx] = 0x80u8;
+            st.msg_block_idx += 1u;
+            while st.msg_block_idx < msg_block_len {
+                st.msg_block[st.msg_block_idx] = 0u8;
+                st.msg_block_idx += 1u;
+            }
+            process_msg_block(st);
+        } else {
+            st.msg_block[st.msg_block_idx] = 0x80u8;
+            st.msg_block_idx += 1u;
+        }
+        while st.msg_block_idx < 56u {
+            st.msg_block[st.msg_block_idx] = 0u8;
+            st.msg_block_idx += 1u;
+        }
+
+        // Store the message length as the last 8 octets
+        st.msg_block[56] = st.len_high >> 24u32 & 0xFFu32 as u8;
+        st.msg_block[57] = st.len_high >> 16u32 & 0xFFu32 as u8;
+        st.msg_block[58] = st.len_high >> 8u32 & 0xFFu32 as u8;
+        st.msg_block[59] = st.len_high & 0xFFu32 as u8;
+        st.msg_block[60] = st.len_low >> 24u32 & 0xFFu32 as u8;
+        st.msg_block[61] = st.len_low >> 16u32 & 0xFFu32 as u8;
+        st.msg_block[62] = st.len_low >> 8u32 & 0xFFu32 as u8;
+        st.msg_block[63] = st.len_low & 0xFFu32 as u8;
+        process_msg_block(st);
+    }
+    obj sha1(st: sha1state) {
+        fn reset() {
+            // FIXME: Should be typestate precondition
+            assert (vec::len(st.h) == digest_buf_len);
+            st.len_low = 0u32;
+            st.len_high = 0u32;
+            st.msg_block_idx = 0u;
+            st.h[0] = 0x67452301u32;
+            st.h[1] = 0xEFCDAB89u32;
+            st.h[2] = 0x98BADCFEu32;
+            st.h[3] = 0x10325476u32;
+            st.h[4] = 0xC3D2E1F0u32;
+            st.computed = false;
+        }
+        fn input(msg: [u8]) { add_input(st, msg); }
+        fn input_str(msg: str) { add_input(st, str::bytes(msg)); }
+        fn result() -> [u8] { ret mk_result(st); }
+        fn result_str() -> str {
+            let r = mk_result(st);
+            let s = "";
+            for b: u8 in r { s += uint::to_str(b as uint, 16u); }
+            ret s;
+        }
+    }
+    let st =
+        {h: vec::init_elt_mut::<u32>(0u32, digest_buf_len),
+         mutable len_low: 0u32,
+         mutable len_high: 0u32,
+         msg_block: vec::init_elt_mut::<u8>(0u8, msg_block_len),
+         mutable msg_block_idx: 0u,
+         mutable computed: false,
+         work_buf: vec::init_elt_mut::<u32>(0u32, work_buf_len)};
+    let sh = sha1(st);
+    sh.reset();
+    ret sh;
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs
new file mode 100644
index 00000000000..4702a2adab4
--- /dev/null
+++ b/src/libstd/smallintmap.rs
@@ -0,0 +1,81 @@
+/*
+Module: smallintmap
+
+A simple map based on a vector for small integer keys. Space requirements
+are O(highest integer key).
+*/
+import option::{some, none};
+
+// FIXME: Should not be @; there's a bug somewhere in rustc that requires this
+// to be.
+/*
+Type: smallintmap
+*/
+type smallintmap<T> = @{mutable v: [mutable option::t<T>]};
+
+/*
+Function: mk
+
+Create a smallintmap
+*/
+fn mk<T>() -> smallintmap<T> {
+    let v: [mutable option::t<T>] = [mutable];
+    ret @{mutable v: v};
+}
+
+/*
+Function: insert
+
+Add a value to the map. If the map already contains a value for
+the specified key then the original value is replaced.
+*/
+fn insert<copy T>(m: smallintmap<T>, key: uint, val: T) {
+    vec::grow_set::<option::t<T>>(m.v, key, none::<T>, some::<T>(val));
+}
+
+/*
+Function: find
+
+Get the value for the specified key. If the key does not exist
+in the map then returns none.
+*/
+fn find<copy T>(m: smallintmap<T>, key: uint) -> option::t<T> {
+    if key < vec::len::<option::t<T>>(m.v) { ret m.v[key]; }
+    ret none::<T>;
+}
+
+/*
+Method: get
+
+Get the value for the specified key
+
+Failure:
+
+If the key does not exist in the map
+*/
+fn get<copy T>(m: smallintmap<T>, key: uint) -> T {
+    alt find(m, key) {
+      none. { log_err "smallintmap::get(): key not present"; fail; }
+      some(v) { ret v; }
+    }
+}
+
+/*
+Method: contains_key
+
+Returns true if the map contains a value for the specified key
+*/
+fn contains_key<copy T>(m: smallintmap<T>, key: uint) -> bool {
+    ret !option::is_none(find::<T>(m, key));
+}
+
+// FIXME: Are these really useful?
+
+fn truncate<copy T>(m: smallintmap<T>, len: uint) {
+    m.v = vec::slice_mut::<option::t<T>>(m.v, 0u, len);
+}
+
+fn max_key<T>(m: smallintmap<T>) -> uint {
+    ret vec::len::<option::t<T>>(m.v);
+}
+
diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs
new file mode 100644
index 00000000000..38ab4f3cfb1
--- /dev/null
+++ b/src/libstd/sort.rs
@@ -0,0 +1,166 @@
+/*
+Module: sort
+
+Sorting methods
+*/
+import vec::{len, slice};
+
+export merge_sort;
+export quick_sort;
+export quick_sort3;
+
+/* Type: lteq */
+type lteq<T> = block(T, T) -> bool;
+
+/*
+Function: merge_sort
+
+Merge sort. Returns a new vector containing the sorted list.
+
+Has worst case O(n log n) performance, best case O(n), but
+is not space efficient. This is a stable sort.
+*/
+fn merge_sort<copy T>(le: lteq<T>, v: [const T]) -> [T] {
+    fn merge<copy T>(le: lteq<T>, a: [T], b: [T]) -> [T] {
+        let rs: [T] = [];
+        let a_len: uint = len::<T>(a);
+        let a_ix: uint = 0u;
+        let b_len: uint = len::<T>(b);
+        let b_ix: uint = 0u;
+        while a_ix < a_len && b_ix < b_len {
+            if le(a[a_ix], b[b_ix]) {
+                rs += [a[a_ix]];
+                a_ix += 1u;
+            } else { rs += [b[b_ix]]; b_ix += 1u; }
+        }
+        rs += slice::<T>(a, a_ix, a_len);
+        rs += slice::<T>(b, b_ix, b_len);
+        ret rs;
+    }
+    let v_len: uint = len::<T>(v);
+    if v_len == 0u { ret []; }
+    if v_len == 1u { ret [v[0]]; }
+    let mid: uint = v_len / 2u;
+    let a: [T] = slice::<T>(v, 0u, mid);
+    let b: [T] = slice::<T>(v, mid, v_len);
+    ret merge::<T>(le, merge_sort::<T>(le, a), merge_sort::<T>(le, b));
+}
+
+fn part<copy T>(compare_func: lteq<T>, arr: [mutable T], left: uint,
+                right: uint, pivot: uint) -> uint {
+    let pivot_value = arr[pivot];
+    arr[pivot] <-> arr[right];
+    let storage_index: uint = left;
+    let i: uint = left;
+    while i < right {
+        if compare_func(copy arr[i], pivot_value) {
+            arr[i] <-> arr[storage_index];
+            storage_index += 1u;
+        }
+        i += 1u;
+    }
+    arr[storage_index] <-> arr[right];
+    ret storage_index;
+}
+
+fn qsort<copy T>(compare_func: lteq<T>, arr: [mutable T], left: uint,
+             right: uint) {
+    if right > left {
+        let pivot = (left + right) / 2u;
+        let new_pivot = part::<T>(compare_func, arr, left, right, pivot);
+        if new_pivot != 0u {
+            // Need to do this check before recursing due to overflow
+            qsort::<T>(compare_func, arr, left, new_pivot - 1u);
+        }
+        qsort::<T>(compare_func, arr, new_pivot + 1u, right);
+    }
+}
+
+/*
+Function: quick_sort
+
+Quicksort. Sorts a mutable vector in place.
+
+Has worst case O(n^2) performance, average case O(n log n).
+This is an unstable sort.
+*/
+fn quick_sort<copy T>(compare_func: lteq<T>, arr: [mutable T]) {
+    if len::<T>(arr) == 0u { ret; }
+    qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
+}
+
+fn qsort3<copy T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
+                  arr: [mutable T], left: int, right: int) {
+    if right <= left { ret; }
+    let v: T = arr[right];
+    let i: int = left - 1;
+    let j: int = right;
+    let p: int = i;
+    let q: int = j;
+    while true {
+        i += 1;
+        while compare_func_lt(copy arr[i], v) { i += 1; }
+        j -= 1;
+        while compare_func_lt(v, copy arr[j]) {
+            if j == left { break; }
+            j -= 1;
+        }
+        if i >= j { break; }
+        arr[i] <-> arr[j];
+        if compare_func_eq(copy arr[i], v) {
+            p += 1;
+            arr[p] <-> arr[i];
+        }
+        if compare_func_eq(v, copy arr[j]) {
+            q -= 1;
+            arr[j] <-> arr[q];
+        }
+    }
+    arr[i] <-> arr[right];
+    j = i - 1;
+    i += 1;
+    let k: int = left;
+    while k < p {
+        arr[k] <-> arr[j];
+        k += 1;
+        j -= 1;
+        if k == len::<T>(arr) as int { break; }
+    }
+    k = right - 1;
+    while k > q {
+        arr[i] <-> arr[k];
+        k -= 1;
+        i += 1;
+        if k == 0 { break; }
+    }
+    qsort3::<T>(compare_func_lt, compare_func_eq, arr, left, j);
+    qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
+}
+
+// FIXME: This should take lt and eq types
+/*
+Function: quick_sort3
+
+Fancy quicksort. Sorts a mutable vector in place.
+
+Based on algorithm presented by Sedgewick and Bentley
+<http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf>.
+According to these slides this is the algorithm of choice for
+'randomly ordered keys, abstract compare' & 'small number of key values'.
+
+This is an unstable sort.
+*/
+fn quick_sort3<copy T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
+                       arr: [mutable T]) {
+    if len::<T>(arr) == 0u { ret; }
+    qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
+                (len::<T>(arr) as int) - 1);
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/std.rc b/src/libstd/std.rc
new file mode 100644
index 00000000000..1f0d1b06093
--- /dev/null
+++ b/src/libstd/std.rc
@@ -0,0 +1,138 @@
+#[link(name = "std",
+       vers = "0.1",
+       uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",
+       url = "http://rust-lang.org/src/std")];
+
+#[comment = "The Rust standard library"];
+#[license = "BSD"];
+
+
+export box, char, float, int, str, ptr;
+export uint, u8, u32, u64, vec, bool;
+export comm, fs, io, net, run, sys, task, uv;
+export c_vec, ctypes, either, option, result, four, tri, util;
+export bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind;
+export rope;
+export math, math_f32, math_f64;
+export ebml, dbg, getopts, json, rand, sha1, term, time, unsafe;
+export extfmt, test, tempfile;
+// FIXME: generic_os and os_fs shouldn't be exported
+export generic_os, os, os_fs;
+
+
+// Built-in types support modules
+
+mod box;
+mod char;
+mod float;
+mod int;
+mod str;
+mod ptr;
+mod uint;
+mod u8;
+mod u32;
+mod u64;
+mod bool;
+mod vec;
+
+
+// General io and system-services modules
+
+mod comm;
+mod fs;
+mod io;
+mod net;
+#[path =  "run_program.rs"]
+mod run;
+mod sys;
+mod task;
+mod uv;
+
+
+// Utility modules
+
+mod c_vec;
+mod ctypes;
+mod cmath; /* unexported */
+mod either;
+mod option;
+mod result;
+mod four;
+mod tri;
+mod util;
+
+
+// Collections
+
+mod bitv;
+mod deque;
+mod fun_treemap;
+mod list;
+mod map;
+mod rope;
+mod smallintmap;
+mod sort;
+mod treemap;
+mod ufind;
+
+
+// And ... other stuff
+
+mod ebml;
+mod dbg;
+mod getopts;
+mod json;
+mod math;
+mod math_f32;
+mod math_f64;
+mod rand;
+mod sha1;
+mod tempfile;
+mod term;
+mod time;
+mod unsafe;
+
+#[cfg(unicode)]
+mod unicode;
+
+
+// Compiler support modules
+
+mod extfmt;
+mod test;
+
+
+// Target-os module.
+
+// TODO: Have each os module re-export everything from genericos.
+mod generic_os;
+
+#[cfg(target_os = "win32")]
+#[path = "win32_os.rs"]
+mod os;
+#[cfg(target_os = "win32")]
+#[path = "win32_fs.rs"]
+mod os_fs;
+
+#[cfg(target_os = "macos")]
+#[path = "macos_os.rs"]
+mod os;
+#[cfg(target_os = "macos")]
+#[path = "posix_fs.rs"]
+mod os_fs;
+
+#[cfg(target_os = "linux")]
+#[path = "linux_os.rs"]
+mod os;
+#[cfg(target_os = "linux")]
+#[path = "posix_fs.rs"]
+mod os_fs;
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+// End:
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
new file mode 100644
index 00000000000..fb24c59f62f
--- /dev/null
+++ b/src/libstd/str.rs
@@ -0,0 +1,961 @@
+/*
+Module: str
+
+String manipulation.
+*/
+
+export eq, lteq, hash, is_empty, is_not_empty, is_whitespace, byte_len,
+       byte_len_range, index,
+       rindex, find, starts_with, ends_with, substr, slice, split, concat,
+       connect, to_upper, replace, char_slice, trim_left, trim_right, trim,
+       unshift_char, shift_char, pop_char, push_char, is_utf8, from_chars,
+       to_chars, char_len, char_len_range, char_at, bytes, is_ascii,
+       shift_byte, pop_byte,
+       unsafe_from_byte, unsafe_from_bytes, from_char, char_range_at,
+       str_from_cstr, sbuf, as_buf, push_byte, utf8_char_width, safe_slice,
+       contains, iter_chars, loop_chars, loop_chars_sub,
+       escape;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_str_push(&s: str, ch: u8);
+}
+
+/*
+Function: eq
+
+Bytewise string equality
+*/
+fn eq(&&a: str, &&b: str) -> bool { a == b }
+
+/*
+Function: lteq
+
+Bytewise less than or equal
+*/
+fn lteq(&&a: str, &&b: str) -> bool { a <= b }
+
+/*
+Function: hash
+
+String hash function
+*/
+fn hash(&&s: str) -> uint {
+    // djb hash.
+    // FIXME: replace with murmur.
+
+    let u: uint = 5381u;
+    for c: u8 in s { u *= 33u; u += c as uint; }
+    ret u;
+}
+
+// UTF-8 tags and ranges
+const tag_cont_u8: u8 = 128u8;
+const tag_cont: uint = 128u;
+const max_one_b: uint = 128u;
+const tag_two_b: uint = 192u;
+const max_two_b: uint = 2048u;
+const tag_three_b: uint = 224u;
+const max_three_b: uint = 65536u;
+const tag_four_b: uint = 240u;
+const max_four_b: uint = 2097152u;
+const tag_five_b: uint = 248u;
+const max_five_b: uint = 67108864u;
+const tag_six_b: uint = 252u;
+
+/*
+Function: is_utf8
+
+Determines if a vector uf bytes contains valid UTF-8
+*/
+fn is_utf8(v: [u8]) -> bool {
+    let i = 0u;
+    let total = vec::len::<u8>(v);
+    while i < total {
+        let chsize = utf8_char_width(v[i]);
+        if chsize == 0u { ret false; }
+        if i + chsize > total { ret false; }
+        i += 1u;
+        while chsize > 1u {
+            if v[i] & 192u8 != tag_cont_u8 { ret false; }
+            i += 1u;
+            chsize -= 1u;
+        }
+    }
+    ret true;
+}
+
+/*
+Function: is_ascii
+
+Determines if a string contains only ASCII characters
+*/
+fn is_ascii(s: str) -> bool {
+    let i: uint = byte_len(s);
+    while i > 0u { i -= 1u; if s[i] & 128u8 != 0u8 { ret false; } }
+    ret true;
+}
+
+/*
+Predicate: is_empty
+
+Returns true if the string has length 0
+*/
+pure fn is_empty(s: str) -> bool { for c: u8 in s { ret false; } ret true; }
+
+/*
+Predicate: is_not_empty
+
+Returns true if the string has length greater than 0
+*/
+pure fn is_not_empty(s: str) -> bool { !is_empty(s) }
+
+/*
+Function: is_whitespace
+
+Returns true if the string contains only whitespace
+*/
+fn is_whitespace(s: str) -> bool {
+    let i = 0u;
+    let len = char_len(s);
+    while i < len {
+        // FIXME: This is not how char_at works
+        if !char::is_whitespace(char_at(s, i)) { ret false; }
+        i += 1u;
+    }
+    ret true;
+}
+
+/*
+Function: byte_len
+
+Returns the length in bytes of a string
+*/
+fn byte_len(s: str) -> uint unsafe {
+    let v: [u8] = unsafe::reinterpret_cast(s);
+    let vlen = vec::len(v);
+    unsafe::leak(v);
+    // There should always be a null terminator
+    assert (vlen > 0u);
+    ret vlen - 1u;
+}
+
+/*
+Function: byte_len_range
+
+As byte_len but for a substring
+
+Parameters:
+s - A string
+byte_offset - The byte offset at which to start in the string
+char_len    - The number of chars (not bytes!) in the range
+
+Returns:
+The number of bytes in the substring starting at `byte_offset` and
+containing `char_len` chars.
+
+Safety note:
+
+This function fails if `byte_offset` or `char_len` do not represent
+valid positions in `s`
+*/
+fn byte_len_range(s: str, byte_offset: uint, char_len: uint) -> uint {
+    let i = byte_offset;
+    let chars = 0u;
+    while chars < char_len {
+        let chsize = utf8_char_width(s[i]);
+        assert (chsize > 0u);
+        i += chsize;
+        chars += 1u;
+    }
+    ret i - byte_offset;
+}
+
+/*
+Function: bytes
+
+Converts a string to a vector of bytes
+*/
+fn bytes(s: str) -> [u8] unsafe {
+    let v = unsafe::reinterpret_cast(s);
+    let vcopy = vec::slice(v, 0u, vec::len(v) - 1u);
+    unsafe::leak(v);
+    ret vcopy;
+}
+
+/*
+Function: unsafe_from_bytes
+
+Converts a vector of bytes to a string. Does not verify that the
+vector contains valid UTF-8.
+*/
+fn unsafe_from_bytes(v: [const u8]) -> str unsafe {
+    let vcopy: [u8] = v + [0u8];
+    let scopy: str = unsafe::reinterpret_cast(vcopy);
+    unsafe::leak(vcopy);
+    ret scopy;
+}
+
+/*
+Function: unsafe_from_byte
+
+Converts a byte to a string. Does not verify that the byte is
+valid UTF-8.
+*/
+fn unsafe_from_byte(u: u8) -> str { unsafe_from_bytes([u]) }
+
+fn push_utf8_bytes(&s: str, ch: char) {
+    let code = ch as uint;
+    let bytes =
+        if code < max_one_b {
+            [code as u8]
+        } else if code < max_two_b {
+            [code >> 6u & 31u | tag_two_b as u8, code & 63u | tag_cont as u8]
+        } else if code < max_three_b {
+            [code >> 12u & 15u | tag_three_b as u8,
+             code >> 6u & 63u | tag_cont as u8, code & 63u | tag_cont as u8]
+        } else if code < max_four_b {
+            [code >> 18u & 7u | tag_four_b as u8,
+             code >> 12u & 63u | tag_cont as u8,
+             code >> 6u & 63u | tag_cont as u8, code & 63u | tag_cont as u8]
+        } else if code < max_five_b {
+            [code >> 24u & 3u | tag_five_b as u8,
+             code >> 18u & 63u | tag_cont as u8,
+             code >> 12u & 63u | tag_cont as u8,
+             code >> 6u & 63u | tag_cont as u8, code & 63u | tag_cont as u8]
+        } else {
+            [code >> 30u & 1u | tag_six_b as u8,
+             code >> 24u & 63u | tag_cont as u8,
+             code >> 18u & 63u | tag_cont as u8,
+             code >> 12u & 63u | tag_cont as u8,
+             code >> 6u & 63u | tag_cont as u8, code & 63u | tag_cont as u8]
+        };
+    push_bytes(s, bytes);
+}
+
+/*
+Function: from_char
+
+Convert a char to a string
+*/
+fn from_char(ch: char) -> str {
+    let buf = "";
+    push_utf8_bytes(buf, ch);
+    ret buf;
+}
+
+/*
+Function: from_chars
+
+Convert a vector of chars to a string
+*/
+fn from_chars(chs: [char]) -> str {
+    let buf = "";
+    for ch: char in chs { push_utf8_bytes(buf, ch); }
+    ret buf;
+}
+
+/*
+Function: utf8_char_width
+
+FIXME: What does this function do?
+*/
+fn utf8_char_width(b: u8) -> uint {
+    let byte: uint = b as uint;
+    if byte < 128u { ret 1u; }
+    if byte < 192u {
+        ret 0u; // Not a valid start byte
+
+    }
+    if byte < 224u { ret 2u; }
+    if byte < 240u { ret 3u; }
+    if byte < 248u { ret 4u; }
+    if byte < 252u { ret 5u; }
+    ret 6u;
+}
+
+/*
+Function: char_range_at
+
+Pluck a character out of a string and return the index of the next character.
+This function can be used to iterate over the unicode characters of a string.
+
+Example:
+
+> let s = "Clam chowder, hot sauce, pork rinds";
+> let i = 0;
+> while i < len(s) {
+>   let {ch, next} = char_range_at(s, i);
+>   log ch;
+>   i = next;
+> }
+
+Parameters:
+
+s - The string
+i - The byte offset of the char to extract
+
+Returns:
+
+A record {ch: char, next: uint} containing the char value and the byte
+index of the next unicode character.
+
+Failure:
+
+If `i` is greater than or equal to the length of the string.
+If `i` is not the index of the beginning of a valid UTF-8 character.
+*/
+fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} {
+    let b0 = s[i];
+    let w = utf8_char_width(b0);
+    assert (w != 0u);
+    if w == 1u { ret {ch: b0 as char, next: i + 1u}; }
+    let val = 0u;
+    let end = i + w;
+    let i = i + 1u;
+    while i < end {
+        let byte = s[i];
+        assert (byte & 192u8 == tag_cont_u8);
+        val <<= 6u;
+        val += byte & 63u8 as uint;
+        i += 1u;
+    }
+    // Clunky way to get the right bits from the first byte. Uses two shifts,
+    // the first to clip off the marker bits at the left of the byte, and then
+    // a second (as uint) to get it to the right position.
+    val += (b0 << (w + 1u as u8) as uint) << (w - 1u) * 6u - w - 1u;
+    ret {ch: val as char, next: i};
+}
+
+/*
+Function: char_at
+
+Pluck a character out of a string
+*/
+fn char_at(s: str, i: uint) -> char { ret char_range_at(s, i).ch; }
+
+/*
+Function: iter_chars
+
+Iterate over the characters in a string
+*/
+
+fn iter_chars(s: str, it: block(char)) {
+    let pos = 0u, len = byte_len(s);
+    while (pos < len) {
+        let {ch, next} = char_range_at(s, pos);
+        pos = next;
+        it(ch);
+    }
+}
+
+/*
+Function: loop_chars
+
+Loop through a string, char by char
+
+Parameters:
+s  - A string to traverse. It may be empty.
+it - A block to execute with each consecutive character of `s`.
+Return `true` to continue, `false` to stop.
+
+Returns:
+
+`true` If execution proceeded correctly, `false` if it was interrupted,
+that is if `it` returned `false` at any point.
+ */
+fn loop_chars(s: str, it: block(char) -> bool) -> bool{
+    ret loop_chars_sub(s, 0u, byte_len(s), it);
+}
+
+/*
+Function: loop_chars_sub
+
+Loop through a substring, char by char
+
+Parameters:
+s           - A string to traverse. It may be empty.
+byte_offset - The byte offset at which to start in the string.
+byte_len    - The number of bytes to traverse in the string
+it          - A block to execute with each consecutive character of `s`.
+Return `true` to continue, `false` to stop.
+
+Returns:
+
+`true` If execution proceeded correctly, `false` if it was interrupted,
+that is if `it` returned `false` at any point.
+
+Safety note:
+- This function does not check whether the substring is valid.
+- This function fails if `byte_offset` or `byte_len` do not
+ represent valid positions inside `s`
+ */
+fn loop_chars_sub(s: str, byte_offset: uint, byte_len: uint,
+              it: block(char) -> bool) -> bool {
+   let i = byte_offset;
+   let result = true;
+   while i < byte_len {
+      let {ch, next} = char_range_at(s, i);
+      if !it(ch) {result = false; break;}
+      i = next;
+   }
+   ret result;
+}
+
+
+/*
+Function: char_len
+
+Count the number of unicode characters in a string
+*/
+fn char_len(s: str) -> uint {
+    ret char_len_range(s, 0u, byte_len(s));
+}
+
+/*
+Function: char_len_range
+
+As char_len but for a slice of a string
+
+Parameters:
+ s           - A valid string
+ byte_start  - The position inside `s` where to start counting in bytes.
+ byte_len    - The number of bytes of `s` to take into account.
+
+Returns:
+ The number of Unicode characters in `s` in
+segment [byte_start, byte_start+len( .
+
+Safety note:
+- This function does not check whether the substring is valid.
+- This function fails if `byte_offset` or `byte_len` do not
+ represent valid positions inside `s`
+*/
+fn char_len_range(s: str, byte_start: uint, byte_len: uint) -> uint {
+    let i     = byte_start;
+    let len   = 0u;
+    while i < byte_len {
+        let chsize = utf8_char_width(s[i]);
+        assert (chsize > 0u);
+        len += 1u;
+        i += chsize;
+    }
+    assert (i == byte_len);
+    ret len;
+}
+
+/*
+Function: to_chars
+
+Convert a string to a vector of characters
+*/
+fn to_chars(s: str) -> [char] {
+    let buf: [char] = [];
+    let i = 0u;
+    let len = byte_len(s);
+    while i < len {
+        let cur = char_range_at(s, i);
+        buf += [cur.ch];
+        i = cur.next;
+    }
+    ret buf;
+}
+
+/*
+Function: push_char
+
+Append a character to a string
+*/
+fn push_char(&s: str, ch: char) { s += from_char(ch); }
+
+/*
+Function: pop_char
+
+Remove the final character from a string and return it.
+
+Failure:
+
+If the string does not contain any characters.
+*/
+fn pop_char(&s: str) -> char {
+    let end = byte_len(s);
+    while end > 0u && s[end - 1u] & 192u8 == tag_cont_u8 { end -= 1u; }
+    assert (end > 0u);
+    let ch = char_at(s, end - 1u);
+    s = substr(s, 0u, end - 1u);
+    ret ch;
+}
+
+/*
+Function: shift_char
+
+Remove the first character from a string and return it.
+
+Failure:
+
+If the string does not contain any characters.
+*/
+fn shift_char(&s: str) -> char {
+    let r = char_range_at(s, 0u);
+    s = substr(s, r.next, byte_len(s) - r.next);
+    ret r.ch;
+}
+
+/*
+Function: unshift_char
+
+Prepend a char to a string
+*/
+fn unshift_char(&s: str, ch: char) { s = from_char(ch) + s; }
+
+/*
+Function: index
+
+Returns the index of the first matching byte. Returns -1 if
+no match is found.
+*/
+fn index(s: str, c: u8) -> int {
+    let i: int = 0;
+    for k: u8 in s { if k == c { ret i; } i += 1; }
+    ret -1;
+}
+
+/*
+Function: rindex
+
+Returns the index of the last matching byte. Returns -1
+if no match is found.
+*/
+fn rindex(s: str, c: u8) -> int {
+    let n: int = byte_len(s) as int;
+    while n >= 0 { if s[n] == c { ret n; } n -= 1; }
+    ret n;
+}
+
+/*
+Function: find
+
+Finds the index of the first matching substring.
+Returns -1 if `haystack` does not contain `needle`.
+
+Parameters:
+
+haystack - The string to look in
+needle - The string to look for
+
+Returns:
+
+The index of the first occurance of `needle`, or -1 if not found.
+*/
+fn find(haystack: str, needle: str) -> int {
+    let haystack_len: int = byte_len(haystack) as int;
+    let needle_len: int = byte_len(needle) as int;
+    if needle_len == 0 { ret 0; }
+    fn match_at(haystack: str, needle: str, i: int) -> bool {
+        let j: int = i;
+        for c: u8 in needle { if haystack[j] != c { ret false; } j += 1; }
+        ret true;
+    }
+    let i: int = 0;
+    while i <= haystack_len - needle_len {
+        if match_at(haystack, needle, i) { ret i; }
+        i += 1;
+    }
+    ret -1;
+}
+
+/*
+Function: contains
+
+Returns true if one string contains another
+
+Parameters:
+
+haystack - The string to look in
+needle - The string to look for
+*/
+fn contains(haystack: str, needle: str) -> bool {
+    0 <= find(haystack, needle)
+}
+
+/*
+Function: starts_with
+
+Returns true if one string starts with another
+
+Parameters:
+
+haystack - The string to look in
+needle - The string to look for
+*/
+fn starts_with(haystack: str, needle: str) -> bool {
+    let haystack_len: uint = byte_len(haystack);
+    let needle_len: uint = byte_len(needle);
+    if needle_len == 0u { ret true; }
+    if needle_len > haystack_len { ret false; }
+    ret eq(substr(haystack, 0u, needle_len), needle);
+}
+
+/*
+Function: ends_with
+
+Returns true if one string ends with another
+
+haystack - The string to look in
+needle - The string to look for
+*/
+fn ends_with(haystack: str, needle: str) -> bool {
+    let haystack_len: uint = byte_len(haystack);
+    let needle_len: uint = byte_len(needle);
+    ret if needle_len == 0u {
+            true
+        } else if needle_len > haystack_len {
+            false
+        } else {
+            eq(substr(haystack, haystack_len - needle_len, needle_len),
+               needle)
+        };
+}
+
+/*
+Function: substr
+
+Take a substring of another. Returns a string containing `len` bytes
+starting at byte offset `begin`.
+
+This function is not unicode-safe.
+
+Failure:
+
+If `begin` + `len` is is greater than the byte length of the string
+*/
+fn substr(s: str, begin: uint, len: uint) -> str {
+    ret slice(s, begin, begin + len);
+}
+
+/*
+Function: slice
+
+Takes a bytewise slice from a string. Returns the substring from
+[`begin`..`end`).
+
+This function is not unicode-safe.
+
+Failure:
+
+- If begin is greater than end.
+- If end is greater than the length of the string.
+*/
+fn slice(s: str, begin: uint, end: uint) -> str unsafe {
+    // FIXME: Typestate precondition
+    assert (begin <= end);
+    assert (end <= byte_len(s));
+
+    let v: [u8] = unsafe::reinterpret_cast(s);
+    let v2 = vec::slice(v, begin, end);
+    unsafe::leak(v);
+    v2 += [0u8];
+    let s2: str = unsafe::reinterpret_cast(v2);
+    unsafe::leak(v2);
+    ret s2;
+}
+
+/*
+Function: safe_slice
+*/
+fn safe_slice(s: str, begin: uint, end: uint) : uint::le(begin, end) -> str {
+    // would need some magic to make this a precondition
+    assert (end <= byte_len(s));
+    ret slice(s, begin, end);
+}
+
+/*
+Function: shift_byte
+
+Removes the first byte from a string and returns it.
+
+This function is not unicode-safe.
+*/
+fn shift_byte(&s: str) -> u8 {
+    let len = byte_len(s);
+    assert (len > 0u);
+    let b = s[0];
+    s = substr(s, 1u, len - 1u);
+    ret b;
+}
+
+/*
+Function: pop_byte
+
+Removes the last byte from a string and returns it.
+
+This function is not unicode-safe.
+*/
+fn pop_byte(&s: str) -> u8 {
+    let len = byte_len(s);
+    assert (len > 0u);
+    let b = s[len - 1u];
+    s = substr(s, 0u, len - 1u);
+    ret b;
+}
+
+/*
+Function: push_byte
+
+Appends a byte to a string.
+
+This function is not unicode-safe.
+*/
+fn push_byte(&s: str, b: u8) { rustrt::rust_str_push(s, b); }
+
+/*
+Function: push_bytes
+
+Appends a vector of bytes to a string.
+
+This function is not unicode-safe.
+*/
+fn push_bytes(&s: str, bytes: [u8]) {
+    for byte in bytes { rustrt::rust_str_push(s, byte); }
+}
+
+/*
+Function: split
+
+Split a string at each occurance of a given separator
+
+Returns:
+
+A vector containing all the strings between each occurance of the separator
+*/
+fn split(s: str, sep: u8) -> [str] {
+    let v: [str] = [];
+    let accum: str = "";
+    let ends_with_sep: bool = false;
+    for c: u8 in s {
+        if c == sep {
+            v += [accum];
+            accum = "";
+            ends_with_sep = true;
+        } else { accum += unsafe_from_byte(c); ends_with_sep = false; }
+    }
+    if byte_len(accum) != 0u || ends_with_sep { v += [accum]; }
+    ret v;
+}
+
+/*
+Function: concat
+
+Concatenate a vector of strings
+*/
+fn concat(v: [str]) -> str {
+    let s: str = "";
+    for ss: str in v { s += ss; }
+    ret s;
+}
+
+/*
+Function: connect
+
+Concatenate a vector of strings, placing a given separator between each
+*/
+fn connect(v: [str], sep: str) -> str {
+    let s: str = "";
+    let first: bool = true;
+    for ss: str in v {
+        if first { first = false; } else { s += sep; }
+        s += ss;
+    }
+    ret s;
+}
+
+// FIXME: This only handles ASCII
+/*
+Function: to_upper
+
+Convert a string to uppercase
+*/
+fn to_upper(s: str) -> str {
+    let outstr = "";
+    let ascii_a = 'a' as u8;
+    let ascii_z = 'z' as u8;
+    let diff = 32u8;
+    for byte: u8 in s {
+        let next;
+        if ascii_a <= byte && byte <= ascii_z {
+            next = byte - diff;
+        } else { next = byte; }
+        push_byte(outstr, next);
+    }
+    ret outstr;
+}
+
+// FIXME: This is super-inefficient
+/*
+Function: replace
+
+Replace all occurances of one string with another
+
+Parameters:
+
+s - The string containing substrings to replace
+from - The string to replace
+to - The replacement string
+
+Returns:
+
+The original string with all occurances of `from` replaced with `to`
+*/
+fn replace(s: str, from: str, to: str) : is_not_empty(from) -> str {
+    // FIXME (694): Shouldn't have to check this
+    check (is_not_empty(from));
+    if byte_len(s) == 0u {
+        ret "";
+    } else if starts_with(s, from) {
+        ret to + replace(slice(s, byte_len(from), byte_len(s)), from, to);
+    } else {
+        ret unsafe_from_byte(s[0]) +
+                replace(slice(s, 1u, byte_len(s)), from, to);
+    }
+}
+
+// FIXME: Also not efficient
+/*
+Function: char_slice
+
+Unicode-safe slice. Returns a slice of the given string containing
+the characters in the range [`begin`..`end`). `begin` and `end` are
+character indexes, not byte indexes.
+
+Failure:
+
+- If begin is greater than end
+- If end is greater than the character length of the string
+*/
+fn char_slice(s: str, begin: uint, end: uint) -> str {
+    from_chars(vec::slice(to_chars(s), begin, end))
+}
+
+/*
+Function: trim_left
+
+Returns a string with leading whitespace removed.
+*/
+fn trim_left(s: str) -> str {
+    fn count_whities(s: [char]) -> uint {
+        let i = 0u;
+        while i < vec::len(s) {
+            if !char::is_whitespace(s[i]) { break; }
+            i += 1u;
+        }
+        ret i;
+    }
+    let chars = to_chars(s);
+    let whities = count_whities(chars);
+    ret from_chars(vec::slice(chars, whities, vec::len(chars)));
+}
+
+/*
+Function: trim_right
+
+Returns a string with trailing whitespace removed.
+*/
+fn trim_right(s: str) -> str {
+    fn count_whities(s: [char]) -> uint {
+        let i = vec::len(s);
+        while 0u < i {
+            if !char::is_whitespace(s[i - 1u]) { break; }
+            i -= 1u;
+        }
+        ret i;
+    }
+    let chars = to_chars(s);
+    let whities = count_whities(chars);
+    ret from_chars(vec::slice(chars, 0u, whities));
+}
+
+/*
+Function: trim
+
+Returns a string with leading and trailing whitespace removed
+*/
+fn trim(s: str) -> str { trim_left(trim_right(s)) }
+
+/*
+Type: sbuf
+
+An unsafe buffer of bytes. Corresponds to a C char pointer.
+*/
+type sbuf = *u8;
+
+// NB: This is intentionally unexported because it's easy to misuse (there's
+// no guarantee that the string is rooted). Instead, use as_buf below.
+unsafe fn buf(s: str) -> sbuf {
+    let saddr = ptr::addr_of(s);
+    let vaddr: *[u8] = unsafe::reinterpret_cast(saddr);
+    let buf = vec::to_ptr(*vaddr);
+    ret buf;
+}
+
+/*
+Function: as_buf
+
+Work with the byte buffer of a string. Allows for unsafe manipulation
+of strings, which is useful for native interop.
+
+Example:
+
+> let s = str::as_buf("PATH", { |path_buf| libc::getenv(path_buf) });
+
+*/
+fn as_buf<T>(s: str, f: block(sbuf) -> T) -> T unsafe {
+    let buf = buf(s); f(buf)
+}
+
+/*
+Function: str_from_cstr
+
+Create a Rust string from a null-terminated C string
+*/
+unsafe fn str_from_cstr(cstr: sbuf) -> str {
+    let res = "";
+    let start = cstr;
+    let curr = start;
+    let i = 0u;
+    while *curr != 0u8 {
+        push_byte(res, *curr);
+        i += 1u;
+        curr = ptr::offset(start, i);
+    }
+    ret res;
+}
+
+/*
+Function: escape_char
+
+Escapes a single character.
+*/
+fn escape_char(c: char) -> str {
+    alt c {
+        '"' { "\\\"" }
+        '\\' { "\\\\" }
+// TODO: uncomment these when https://github.com/graydon/rust/issues/1170 is
+// fixed.
+//        '\n' { "\\n" }
+//        '\t' { "\\t" }
+//        '\r' { "\\r" }
+        '\x00' to '\x1f' { #fmt["\\x%02x", c as uint] }
+        v { from_char(c) }
+    }
+}
+
+/*
+Function: escape
+
+Escapes special characters inside the string, making it safe for transfer.
+*/
+fn escape(s: str) -> str {
+    let r = "";
+    loop_chars(s, { |c| r += escape_char(c); true });
+    r
+}
diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs
new file mode 100644
index 00000000000..3b4a3b8c643
--- /dev/null
+++ b/src/libstd/sys.rs
@@ -0,0 +1,96 @@
+/*
+Module: sys
+
+Misc low level stuff
+*/
+tag type_desc = {
+    first_param: **ctypes::c_int,
+    size: ctypes::size_t,
+    align: ctypes::size_t
+    // Remaining fields not listed
+};
+
+#[abi = "cdecl"]
+native mod rustrt {
+    // Explicitly re-export native stuff we want to be made
+    // available outside this crate. Otherwise it's
+    // visible-in-crate, but not re-exported.
+    fn last_os_error() -> str;
+    fn refcount<T>(t: @T) -> uint;
+    fn do_gc();
+    fn unsupervise();
+}
+
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn get_type_desc<T>() -> *type_desc;
+}
+
+/*
+Function: get_type_desc
+
+Returns a pointer to a type descriptor. Useful for calling certain
+function in the Rust runtime or otherwise performing dark magick.
+*/
+fn get_type_desc<T>() -> *type_desc {
+    ret rusti::get_type_desc::<T>();
+}
+
+/*
+Function: last_os_error
+
+Get a string representing the platform-dependent last error
+*/
+fn last_os_error() -> str {
+    ret rustrt::last_os_error();
+}
+
+/*
+Function: size_of
+
+Returns the size of a type
+*/
+fn size_of<T>() -> uint unsafe {
+    ret (*get_type_desc::<T>()).size;
+}
+
+/*
+Function: align_of
+
+Returns the alignment of a type
+*/
+fn align_of<T>() -> uint unsafe {
+    ret (*get_type_desc::<T>()).align;
+}
+
+/*
+Function: refcount
+
+Returns the refcount of a shared box
+*/
+fn refcount<T>(t: @T) -> uint {
+    ret rustrt::refcount::<T>(t);
+}
+
+/*
+Function: do_gc
+
+Force a garbage collection
+*/
+fn do_gc() -> () {
+    ret rustrt::do_gc();
+}
+
+// FIXME: There's a wrapper for this in the task module and this really
+// just belongs there
+fn unsupervise() -> () {
+    ret rustrt::unsupervise();
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/task.rs b/src/libstd/task.rs
new file mode 100644
index 00000000000..a8765407f3a
--- /dev/null
+++ b/src/libstd/task.rs
@@ -0,0 +1,350 @@
+/*
+Module: task
+
+Task management.
+
+An executing Rust program consists of a tree of tasks, each with their own
+stack, and sole ownership of their allocated heap data. Tasks communicate
+with each other using ports and channels.
+
+When a task fails, that failure will propagate to its parent (the task
+that spawned it) and the parent will fail as well. The reverse is not
+true: when a parent task fails its children will continue executing. When
+the root (main) task fails, all tasks fail, and then so does the entire
+process.
+
+A task may remove itself from this failure propagation mechanism by
+calling the <unsupervise> function, after which failure will only
+result in the termination of that task.
+
+Tasks may execute in parallel and are scheduled automatically by the runtime.
+
+Example:
+
+> spawn("Hello, World", fn (&&msg: str) {
+>   log msg;
+> });
+
+*/
+import cast = unsafe::reinterpret_cast;
+import comm;
+import option::{some, none};
+import option = option::t;
+import ptr;
+
+export task;
+export joinable_task;
+export sleep;
+export yield;
+export task_notification;
+export join;
+export unsupervise;
+export pin;
+export unpin;
+export set_min_stack;
+export task_result;
+export tr_success;
+export tr_failure;
+export get_task;
+export spawn;
+export spawn_notify;
+export spawn_joinable;
+
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    // these must run on the Rust stack so that they can swap stacks etc:
+    fn task_sleep(task: *rust_task, time_in_us: uint, &killed: bool);
+}
+
+#[link_name = "rustrt"]
+#[abi = "cdecl"]
+native mod rustrt {
+    // these can run on the C stack:
+    fn pin_task();
+    fn unpin_task();
+    fn get_task_id() -> task_id;
+    fn rust_get_task() -> *rust_task;
+
+    fn set_min_stack(stack_size: uint);
+
+    fn new_task() -> task_id;
+    fn drop_task(task_id: *rust_task);
+    fn get_task_pointer(id: task_id) -> *rust_task;
+
+    fn migrate_alloc(alloc: *u8, target: task_id);
+
+    fn start_task(id: task, closure: *u8);
+
+}
+
+/* Section: Types */
+
+type rust_task =
+    {id: task,
+     mutable notify_enabled: int,
+     mutable notify_chan: comm::chan<task_notification>,
+     mutable stack_ptr: *u8};
+
+resource rust_task_ptr(task: *rust_task) { rustrt::drop_task(task); }
+
+type task_id = int;
+
+/*
+Type: task
+
+A handle to a task
+*/
+type task = task_id;
+
+/*
+Type: joinable_task
+
+A task that sends notification upon termination
+*/
+type joinable_task = (task, comm::port<task_notification>);
+
+/*
+Tag: task_result
+
+Indicates the manner in which a task exited
+*/
+tag task_result {
+    /* Variant: tr_success */
+    tr_success;
+    /* Variant: tr_failure */
+    tr_failure;
+}
+
+/*
+Tag: task_notification
+
+Message sent upon task exit to indicate normal or abnormal termination
+*/
+tag task_notification {
+    /* Variant: exit */
+    exit(task, task_result);
+}
+
+/* Section: Operations */
+
+/*
+Type: get_task
+
+Retreives a handle to the currently executing task
+*/
+fn get_task() -> task { rustrt::get_task_id() }
+
+/*
+Function: sleep
+
+Hints the scheduler to yield this task for a specified ammount of time.
+
+Parameters:
+
+time_in_us - maximum number of microseconds to yield control for
+*/
+fn sleep(time_in_us: uint) {
+    let task = rustrt::rust_get_task();
+    let killed = false;
+    log #fmt("yielding for %u us", time_in_us);
+    rusti::task_sleep(task, time_in_us, killed);
+    if killed {
+        fail "killed";
+    }
+}
+
+/*
+Function: yield
+
+Yield control to the task scheduler
+
+The scheduler may schedule another task to execute.
+*/
+fn yield() { sleep(1u) }
+
+/*
+Function: join
+
+Wait for a child task to exit
+
+The child task must have been spawned with <spawn_joinable>, which
+produces a notification port that the child uses to communicate its
+exit status.
+
+Returns:
+
+A task_result indicating whether the task terminated normally or failed
+*/
+fn join(task_port: joinable_task) -> task_result {
+    let (id, port) = task_port;
+    alt comm::recv::<task_notification>(port) {
+      exit(_id, res) {
+        if _id == id {
+            ret res
+        } else { fail #fmt["join received id %d, expected %d", _id, id] }
+      }
+    }
+}
+
+/*
+Function: unsupervise
+
+Detaches this task from its parent in the task tree
+
+An unsupervised task will not propagate its failure up the task tree
+*/
+fn unsupervise() { ret sys::unsupervise(); }
+
+/*
+Function: pin
+
+Pins the current task and future child tasks to a single scheduler thread
+*/
+fn pin() { rustrt::pin_task(); }
+
+/*
+Function: unpin
+
+Unpin the current task and future child tasks
+*/
+fn unpin() { rustrt::unpin_task(); }
+
+/*
+Function: set_min_stack
+
+Set the minimum stack size (in bytes) for tasks spawned in the future.
+
+This function has global effect and should probably not be used.
+*/
+fn set_min_stack(stack_size: uint) { rustrt::set_min_stack(stack_size); }
+
+/*
+Function: spawn
+
+Creates and executes a new child task
+
+Sets up a new task with its own call stack and schedules it to be executed.
+Upon execution the new task will call function `f` with the provided
+argument `data`.
+
+Function `f` is a bare function, meaning it may not close over any data, as do
+shared functions (fn@) and lambda blocks. `data` must be a uniquely owned
+type; it is moved into the new task and thus can no longer be accessed
+locally.
+
+Parameters:
+
+data - A unique-type value to pass to the new task
+f - A function to execute in the new task
+
+Returns:
+
+A handle to the new task
+*/
+fn spawn<send T>(-data: T, f: fn(T)) -> task {
+    spawn_inner(data, f, none)
+}
+
+/*
+Function: spawn_notify
+
+Create and execute a new child task, requesting notification upon its
+termination
+
+Immediately before termination, either on success or failure, the spawned
+task will send a <task_notification> message on the provided channel.
+*/
+fn spawn_notify<send T>(-data: T, f: fn(T),
+                         notify: comm::chan<task_notification>) -> task {
+    spawn_inner(data, f, some(notify))
+}
+
+/*
+Function: spawn_joinable
+
+Create and execute a task which can later be joined with the <join> function
+
+This is a convenience wrapper around spawn_notify which, when paired
+with <join> can be easily used to spawn a task then wait for it to
+complete.
+*/
+fn spawn_joinable<send T>(-data: T, f: fn(T)) -> joinable_task {
+    let p = comm::port::<task_notification>();
+    let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
+    ret (id, p);
+}
+
+// FIXME: To transition from the unsafe spawn that spawns a shared closure to
+// the safe spawn that spawns a bare function we're going to write
+// barefunc-spawn on top of unsafe-spawn.  Sadly, bind does not work reliably
+// enough to suite our needs (#1034, probably others yet to be discovered), so
+// we're going to copy the bootstrap data into a unique pointer, cast it to an
+// unsafe pointer then wrap up the bare function and the unsafe pointer in a
+// shared closure to spawn.
+//
+// After the transition this should all be rewritten.
+
+fn spawn_inner<send T>(-data: T, f: fn(T),
+                          notify: option<comm::chan<task_notification>>)
+    -> task unsafe {
+
+    fn wrapper<send T>(-data: *u8, f: fn(T)) unsafe {
+        let data: ~T = unsafe::reinterpret_cast(data);
+        f(*data);
+    }
+
+    let data = ~data;
+    let dataptr: *u8 = unsafe::reinterpret_cast(data);
+    unsafe::leak(data);
+    let wrapped = bind wrapper(dataptr, f);
+    ret unsafe_spawn_inner(wrapped, notify);
+}
+
+// FIXME: This is the old spawn function that spawns a shared closure.
+// It is a hack and needs to be rewritten.
+fn unsafe_spawn_inner(-thunk: fn@(),
+                      notify: option<comm::chan<task_notification>>) ->
+   task unsafe {
+    let id = rustrt::new_task();
+
+    let raw_thunk: {code: uint, env: uint} = cast(thunk);
+
+    // set up the task pointer
+    let task_ptr <- rust_task_ptr(rustrt::get_task_pointer(id));
+
+    assert (ptr::null() != (**task_ptr).stack_ptr);
+
+    // copy the thunk from our stack to the new stack
+    let sp: uint = cast((**task_ptr).stack_ptr);
+    let ptrsize = sys::size_of::<*u8>();
+    let thunkfn: *mutable uint = cast(sp - ptrsize * 2u);
+    let thunkenv: *mutable uint = cast(sp - ptrsize);
+    *thunkfn = cast(raw_thunk.code);;
+    *thunkenv = cast(raw_thunk.env);;
+    // align the stack to 16 bytes
+    (**task_ptr).stack_ptr = cast(sp - ptrsize * 4u);
+
+    // set up notifications if they are enabled.
+    alt notify {
+      some(c) {
+        (**task_ptr).notify_enabled = 1;
+        (**task_ptr).notify_chan = c;
+      }
+      none { }
+    }
+
+    // give the thunk environment's allocation to the new task
+    rustrt::migrate_alloc(cast(raw_thunk.env), id);
+    rustrt::start_task(id, cast(thunkfn));
+    // don't cleanup the thunk in this task
+    unsafe::leak(thunk);
+    ret id;
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs
new file mode 100644
index 00000000000..5f504ba2349
--- /dev/null
+++ b/src/libstd/tempfile.rs
@@ -0,0 +1,23 @@
+/*
+Module: tempfile
+
+Temporary files and directories
+*/
+
+import fs;
+import option;
+import option::{none, some};
+import rand;
+
+fn mkdtemp(prefix: str, suffix: str) -> option::t<str> {
+    let r = rand::mk_rng();
+    let i = 0u;
+    while (i < 1000u) {
+        let s = prefix + r.gen_str(16u) + suffix;
+        if fs::make_dir(s, 0x1c0i32) {  // FIXME: u+rwx
+            ret some(s);
+        }
+        i += 1u;
+    }
+    ret none;
+}
diff --git a/src/libstd/term.rs b/src/libstd/term.rs
new file mode 100644
index 00000000000..75c35aabd54
--- /dev/null
+++ b/src/libstd/term.rs
@@ -0,0 +1,107 @@
+/*
+Module: term
+
+Simple ANSI color library
+*/
+
+// TODO: Windows support.
+
+/* Const: color_black */
+const color_black: u8 = 0u8;
+/* Const: color_red */
+const color_red: u8 = 1u8;
+/* Const: color_green */
+const color_green: u8 = 2u8;
+/* Const: color_yellow */
+const color_yellow: u8 = 3u8;
+/* Const: color_blue */
+const color_blue: u8 = 4u8;
+/* Const: color_magenta */
+const color_magenta: u8 = 5u8;
+/* Const: color_cyan */
+const color_cyan: u8 = 6u8;
+/* Const: color_light_gray */
+const color_light_gray: u8 = 7u8;
+/* Const: color_light_grey */
+const color_light_grey: u8 = 7u8;
+/* Const: color_dark_gray */
+const color_dark_gray: u8 = 8u8;
+/* Const: color_dark_grey */
+const color_dark_grey: u8 = 8u8;
+/* Const: color_bright_red */
+const color_bright_red: u8 = 9u8;
+/* Const: color_bright_green */
+const color_bright_green: u8 = 10u8;
+/* Const: color_bright_yellow */
+const color_bright_yellow: u8 = 11u8;
+/* Const: color_bright_blue */
+const color_bright_blue: u8 = 12u8;
+/* Const: color_bright_magenta */
+const color_bright_magenta: u8 = 13u8;
+/* Const: color_bright_cyan */
+const color_bright_cyan: u8 = 14u8;
+/* Const: color_bright_white */
+const color_bright_white: u8 = 15u8;
+
+fn esc(writer: io::buf_writer) { writer.write([0x1bu8, '[' as u8]); }
+
+/*
+Function: reset
+
+Reset the foreground and background colors to default
+*/
+fn reset(writer: io::buf_writer) {
+    esc(writer);
+    writer.write(['0' as u8, 'm' as u8]);
+}
+
+/*
+Function: color_supported
+
+Returns true if the terminal supports color
+*/
+fn color_supported() -> bool {
+    let supported_terms = ["xterm-color", "xterm", "screen-bce"];
+    ret alt generic_os::getenv("TERM") {
+          option::some(env) {
+            for term: str in supported_terms {
+                if str::eq(term, env) { ret true; }
+            }
+            false
+          }
+          option::none. { false }
+        };
+}
+
+fn set_color(writer: io::buf_writer, first_char: u8, color: u8) {
+    assert (color < 16u8);
+    esc(writer);
+    let color = color;
+    if color >= 8u8 { writer.write(['1' as u8, ';' as u8]); color -= 8u8; }
+    writer.write([first_char, ('0' as u8) + color, 'm' as u8]);
+}
+
+/*
+Function: fg
+
+Set the foreground color
+*/
+fn fg(writer: io::buf_writer, color: u8) {
+    ret set_color(writer, '3' as u8, color);
+}
+
+/*
+Function: fg
+
+Set the background color
+*/
+fn bg(writer: io::buf_writer, color: u8) {
+    ret set_color(writer, '4' as u8, color);
+}
+
+// Local Variables:
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/test.rs b/src/libstd/test.rs
new file mode 100644
index 00000000000..d827d775831
--- /dev/null
+++ b/src/libstd/test.rs
@@ -0,0 +1,353 @@
+// Support code for rustc's built in test runner generator. Currently,
+// none of this is meant for users. It is intended to support the
+// simplest interface possible for representing and running tests
+// while providing a base that other test frameworks may build off of.
+
+import task::task;
+
+export test_name;
+export test_fn;
+export default_test_fn;
+export test_desc;
+export test_main;
+export test_result;
+export test_opts;
+export tr_ok;
+export tr_failed;
+export tr_ignored;
+export run_tests_console;
+export run_tests_console_;
+export run_test;
+export filter_tests;
+export parse_opts;
+export test_to_task;
+export default_test_to_task;
+export configure_test_task;
+export joinable;
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn sched_threads() -> uint;
+}
+
+
+// The name of a test. By convention this follows the rules for rust
+// paths; i.e. it should be a series of identifiers seperated by double
+// colons. This way if some test runner wants to arrange the tests
+// hierarchically it may.
+type test_name = str;
+
+// A function that runs a test. If the function returns successfully,
+// the test succeeds; if the function fails then the test fails. We
+// may need to come up with a more clever definition of test in order
+// to support isolation of tests into tasks.
+type test_fn<T> = T;
+
+type default_test_fn = test_fn<fn()>;
+
+// The definition of a single test. A test runner will run a list of
+// these.
+type test_desc<T> = {
+    name: test_name,
+    fn: test_fn<T>,
+    ignore: bool,
+    should_fail: bool
+};
+
+// The default console test runner. It accepts the command line
+// arguments and a vector of test_descs (generated at compile time).
+fn test_main(args: [str], tests: [test_desc<default_test_fn>]) {
+    check (vec::is_not_empty(args));
+    let opts =
+        alt parse_opts(args) {
+          either::left(o) { o }
+          either::right(m) { fail m }
+        };
+    if !run_tests_console(opts, tests) { fail "Some tests failed"; }
+}
+
+type test_opts = {filter: option::t<str>, run_ignored: bool};
+
+type opt_res = either::t<test_opts, str>;
+
+// Parses command line arguments into test options
+fn parse_opts(args: [str]) : vec::is_not_empty(args) -> opt_res {
+
+    let args_ = vec::tail(args);
+    let opts = [getopts::optflag("ignored")];
+    let match =
+        alt getopts::getopts(args_, opts) {
+          getopts::success(m) { m }
+          getopts::failure(f) { ret either::right(getopts::fail_str(f)) }
+        };
+
+    let filter =
+        if vec::len(match.free) > 0u {
+            option::some(match.free[0])
+        } else { option::none };
+
+    let run_ignored = getopts::opt_present(match, "ignored");
+
+    let test_opts = {filter: filter, run_ignored: run_ignored};
+
+    ret either::left(test_opts);
+}
+
+tag test_result { tr_ok; tr_failed; tr_ignored; }
+
+type joinable = (task, comm::port<task::task_notification>);
+
+// To get isolation and concurrency tests have to be run in their own tasks.
+// In cases where test functions are closures it is not ok to just dump them
+// into a task and run them, so this transformation gives the caller a chance
+// to create the test task.
+type test_to_task<T> = fn@(test_fn<T>) -> joinable;
+
+// A simple console test runner
+fn run_tests_console(opts: test_opts,
+                         tests: [test_desc<default_test_fn>]) -> bool {
+    run_tests_console_(opts, tests, default_test_to_task)
+}
+
+fn run_tests_console_<copy T>(opts: test_opts, tests: [test_desc<T>],
+                              to_task: test_to_task<T>) -> bool {
+
+    type test_state =
+        @{out: io::writer,
+          use_color: bool,
+          mutable total: uint,
+          mutable passed: uint,
+          mutable failed: uint,
+          mutable ignored: uint,
+          mutable failures: [test_desc<T>]};
+
+    fn callback<copy T>(event: testevent<T>, st: test_state) {
+        alt event {
+          te_filtered(filtered_tests) {
+            st.total = vec::len(filtered_tests);
+            st.out.write_line(#fmt["\nrunning %u tests", st.total]);
+          }
+          te_wait(test) { st.out.write_str(#fmt["test %s ... ", test.name]); }
+          te_result(test, result) {
+            alt result {
+              tr_ok. {
+                st.passed += 1u;
+                write_ok(st.out, st.use_color);
+                st.out.write_line("");
+              }
+              tr_failed. {
+                st.failed += 1u;
+                write_failed(st.out, st.use_color);
+                st.out.write_line("");
+                st.failures += [test];
+              }
+              tr_ignored. {
+                st.ignored += 1u;
+                write_ignored(st.out, st.use_color);
+                st.out.write_line("");
+              }
+            }
+          }
+        }
+    }
+
+    let st =
+        @{out: io::stdout(),
+          use_color: use_color(),
+          mutable total: 0u,
+          mutable passed: 0u,
+          mutable failed: 0u,
+          mutable ignored: 0u,
+          mutable failures: []};
+
+    run_tests(opts, tests, to_task, bind callback(_, st));
+
+    assert (st.passed + st.failed + st.ignored == st.total);
+    let success = st.failed == 0u;
+
+    if !success {
+        st.out.write_line("\nfailures:");
+        for test: test_desc<T> in st.failures {
+            let testname = test.name; // Satisfy alias analysis
+            st.out.write_line(#fmt["    %s", testname]);
+        }
+    }
+
+    st.out.write_str(#fmt["\nresult: "]);
+    if success {
+        // There's no parallelism at this point so it's safe to use color
+        write_ok(st.out, true);
+    } else { write_failed(st.out, true); }
+    st.out.write_str(#fmt[". %u passed; %u failed; %u ignored\n\n", st.passed,
+                          st.failed, st.ignored]);
+
+    ret success;
+
+    fn write_ok(out: io::writer, use_color: bool) {
+        write_pretty(out, "ok", term::color_green, use_color);
+    }
+
+    fn write_failed(out: io::writer, use_color: bool) {
+        write_pretty(out, "FAILED", term::color_red, use_color);
+    }
+
+    fn write_ignored(out: io::writer, use_color: bool) {
+        write_pretty(out, "ignored", term::color_yellow, use_color);
+    }
+
+    fn write_pretty(out: io::writer, word: str, color: u8, use_color: bool) {
+        if use_color && term::color_supported() {
+            term::fg(out.get_buf_writer(), color);
+        }
+        out.write_str(word);
+        if use_color && term::color_supported() {
+            term::reset(out.get_buf_writer());
+        }
+    }
+}
+
+fn use_color() -> bool { ret get_concurrency() == 1u; }
+
+tag testevent<T> {
+    te_filtered([test_desc<T>]);
+    te_wait(test_desc<T>);
+    te_result(test_desc<T>, test_result);
+}
+
+fn run_tests<copy T>(opts: test_opts, tests: [test_desc<T>],
+                     to_task: test_to_task<T>,
+                     callback: fn@(testevent<T>)) {
+
+    let filtered_tests = filter_tests(opts, tests);
+    callback(te_filtered(filtered_tests));
+
+    // It's tempting to just spawn all the tests at once but that doesn't
+    // provide a great user experience because you might sit waiting for the
+    // result of a particular test for an unusually long amount of time.
+    let concurrency = get_concurrency();
+    log #fmt["using %u test tasks", concurrency];
+    let total = vec::len(filtered_tests);
+    let run_idx = 0u;
+    let wait_idx = 0u;
+    let futures = [];
+
+    while wait_idx < total {
+        while vec::len(futures) < concurrency && run_idx < total {
+            futures += [run_test(filtered_tests[run_idx], to_task)];
+            run_idx += 1u;
+        }
+
+        let future = futures[0];
+        callback(te_wait(future.test));
+        let result = future.wait();
+        callback(te_result(future.test, result));
+        futures = vec::slice(futures, 1u, vec::len(futures));
+        wait_idx += 1u;
+    }
+}
+
+fn get_concurrency() -> uint { rustrt::sched_threads() }
+
+fn filter_tests<copy T>(opts: test_opts,
+                        tests: [test_desc<T>]) -> [test_desc<T>] {
+    let filtered = tests;
+
+    // Remove tests that don't match the test filter
+    filtered = if option::is_none(opts.filter) {
+        filtered
+    } else {
+        let filter_str =
+            alt opts.filter {
+          option::some(f) { f }
+          option::none. { "" }
+        };
+
+        fn filter_fn<copy T>(test: test_desc<T>, filter_str: str) ->
+            option::t<test_desc<T>> {
+            if str::find(test.name, filter_str) >= 0 {
+                ret option::some(test);
+            } else { ret option::none; }
+        }
+
+        let filter = bind filter_fn(_, filter_str);
+
+        vec::filter_map(filter, filtered)
+    };
+
+    // Maybe pull out the ignored test and unignore them
+    filtered = if !opts.run_ignored {
+        filtered
+    } else {
+        fn filter<copy T>(test: test_desc<T>) -> option::t<test_desc<T>> {
+            if test.ignore {
+                ret option::some({name: test.name,
+                                  fn: test.fn,
+                                  ignore: false,
+                                  should_fail: test.should_fail});
+            } else { ret option::none; }
+        };
+
+        vec::filter_map(bind filter(_), filtered)
+    };
+
+    // Sort the tests alphabetically
+    filtered =
+        {
+            fn lteq<T>(t1: test_desc<T>, t2: test_desc<T>) -> bool {
+                str::lteq(t1.name, t2.name)
+            }
+            sort::merge_sort(bind lteq(_, _), filtered)
+        };
+
+    ret filtered;
+}
+
+type test_future<T> = {test: test_desc<T>, wait: fn@() -> test_result};
+
+fn run_test<copy T>(test: test_desc<T>,
+                    to_task: test_to_task<T>) -> test_future<T> {
+    if test.ignore {
+        ret {test: test, wait: fn () -> test_result { tr_ignored }};
+    }
+
+    let test_task = to_task(test.fn);
+    ret {test: test,
+         wait:
+             bind fn (test_task: joinable, should_fail: bool) -> test_result {
+                  alt task::join(test_task) {
+                    task::tr_success. {
+                      if should_fail { tr_failed }
+                      else { tr_ok }
+                    }
+                    task::tr_failure. {
+                      if should_fail { tr_ok }
+                      else { tr_failed }
+                    }
+                  }
+              }(test_task, test.should_fail)};
+}
+
+// We need to run our tests in another task in order to trap test failures.
+// This function only works with functions that don't contain closures.
+fn default_test_to_task(&&f: default_test_fn) -> joinable {
+    fn run_task(f: default_test_fn) {
+        configure_test_task();
+        f();
+    }
+    ret task::spawn_joinable(copy f, run_task);
+}
+
+// Call from within a test task to make sure it's set up correctly
+fn configure_test_task() {
+    // If this task fails we don't want that failure to propagate to the
+    // test runner or else we couldn't keep running tests
+    task::unsupervise();
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/time.rs b/src/libstd/time.rs
new file mode 100644
index 00000000000..2865666fdc8
--- /dev/null
+++ b/src/libstd/time.rs
@@ -0,0 +1,30 @@
+/*
+Module: time
+*/
+
+// FIXME: Document what these functions do
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn get_time(&sec: u32, &usec: u32);
+    fn nano_time(&ns: u64);
+}
+
+/* Type: timeval */
+type timeval = {sec: u32, usec: u32};
+
+/* Function: get_time */
+fn get_time() -> timeval {
+    let sec = 0u32;
+    let usec = 0u32;
+    rustrt::get_time(sec, usec);
+    ret {sec: sec, usec: usec};
+}
+
+/* Function: precise_time_ns */
+fn precise_time_ns() -> u64 { let ns = 0u64; rustrt::nano_time(ns); ret ns; }
+
+/* Function: precise_time_s */
+fn precise_time_s() -> float {
+    ret (precise_time_ns() as float) / 1000000000.;
+}
diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs
new file mode 100644
index 00000000000..35d87cd518f
--- /dev/null
+++ b/src/libstd/treemap.rs
@@ -0,0 +1,96 @@
+/*
+Module: treemap
+
+A key,value store that works on anything.
+
+This works using a binary search tree. In the first version, it's a
+very naive algorithm, but it will probably be updated to be a
+red-black tree or something else.
+
+*/
+
+import option::{some, none};
+import option = option::t;
+
+export treemap;
+export init;
+export insert;
+export find;
+export traverse;
+
+/* Section: Types */
+
+/*
+Type: treemap
+*/
+type treemap<K, V> = @mutable tree_node<K, V>;
+
+/*
+Tag: tree_node
+*/
+tag tree_node<K, V> { empty; node(@K, @V, treemap<K, V>, treemap<K, V>); }
+
+/* Section: Operations */
+
+/*
+Function: init
+
+Create a treemap
+*/
+fn init<K, V>() -> treemap<K, V> { @mutable empty }
+
+/*
+Function: insert
+
+Insert a value into the map
+*/
+fn insert<copy K, copy V>(m: treemap<K, V>, k: K, v: V) {
+    alt m {
+      @empty. { *m = node(@k, @v, @mutable empty, @mutable empty); }
+      @node(@kk, _, _, _) {
+
+        // We have to name left and right individually, because
+        // otherwise the alias checker complains.
+        if k < kk {
+            alt m { @node(_, _, left, _) { insert(left, k, v); } }
+        } else { alt m { @node(_, _, _, right) { insert(right, k, v); } } }
+      }
+    }
+}
+
+/*
+Function: find
+
+Find a value based on the key
+*/
+fn find<copy K, copy V>(m: treemap<K, V>, k: K) -> option<V> {
+    alt *m {
+      empty. { none }
+      node(@kk, @v, _, _) {
+        if k == kk {
+            some(v)
+        } else if k < kk {
+
+            // Again, ugliness to unpack left and right individually.
+            alt *m { node(_, _, left, _) { find(left, k) } }
+        } else { alt *m { node(_, _, _, right) { find(right, k) } } }
+      }
+    }
+}
+
+/*
+Function: traverse
+
+Visit all pairs in the map in order.
+*/
+fn traverse<K, V>(m: treemap<K, V>, f: block(K, V)) {
+    alt *m {
+      empty. { }
+      node(k, v, _, _) {
+        let k1 = k, v1 = v;
+        alt *m { node(_, _, left, _) { traverse(left, f); } }
+        f(*k1, *v1);
+        alt *m { node(_, _, _, right) { traverse(right, f); } }
+      }
+    }
+}
diff --git a/src/libstd/tri.rs b/src/libstd/tri.rs
new file mode 100644
index 00000000000..fd4456cfde3
--- /dev/null
+++ b/src/libstd/tri.rs
@@ -0,0 +1,188 @@
+// -*- rust -*-
+
+/*
+Module: tri
+
+ADT for the ternary Kleene logic K3
+
+This allows reasoning with three logic values (true, false, unknown).
+
+Implementation: Truth values are represented using a single u8 and
+all operations are done using bit operations which is fast
+on current cpus.
+*/
+
+export t, true, false, unknown;
+export not, and, or, xor, implies, eq, ne, is_true, is_false;
+export from_str, to_str, all_values, to_bit;
+
+/*
+Type: t
+
+The type of ternary logic values
+*/
+type t = u8;
+
+const b0: u8  = 1u8;
+const b1: u8  = 2u8;
+const b01: u8 = 3u8;
+
+/*
+Constant: unknown
+
+Logic value for unknown (maybe true xor maybe false)
+*/
+const unknown: t = 0u8;
+
+/*
+Constant: true
+
+Logic value for truth
+*/
+const true: t = 1u8;
+
+/*
+Constant: false
+
+Logic value for falsehood
+*/
+const false: t = 2u8;
+
+/* Function: not
+
+Negation/Inverse
+*/
+pure fn not(v: t) -> t { ((v << 1u8) | (v >> 1u8)) & b01 }
+
+/* Function: and
+
+Conjunction
+*/
+pure fn and(a: t, b: t) -> t { ((a | b) & b1) | ((a & b) & b0) }
+
+/* Function: or
+
+Disjunction
+*/
+pure fn or(a: t, b: t) -> t { ((a & b) & b1) | ((a | b) & b0) }
+
+/*
+Function: xor
+
+Exclusive or
+*/
+pure fn xor(a: t, b: t) -> t {
+    let anb = a & b;
+    let aob = a & not(b);
+    ret ((anb & b1) | (anb << 1u8) | (aob >> 1u8) | (aob & b0)) & b01;
+}
+
+/*
+Function: implies
+
+Classic implication, i.e. from `a` follows `b`
+*/
+pure fn implies(a: t, b: t) -> t {
+    ret ((a & b1) >> 1u8) | (b & b0) | ((a << 1u8) & b & b1);
+}
+
+/*
+Predicate: eq
+
+Returns:
+
+true if truth values `a` and `b` are indistinguishable in the logic
+*/
+pure fn eq(a: t, b: t) -> bool {  a == b }
+
+/*
+Predicate: ne
+
+Returns:
+
+true if truth values `a` and `b` are distinguishable in the logic
+*/
+pure fn ne(a: t, b: t) -> bool { a != b }
+
+/*
+Predicate: is_true
+
+Returns:
+
+true if `v` represents truth in the logic
+*/
+pure fn is_true(v: t) -> bool { v == tri::true }
+
+/*
+Predicate: is_false
+
+Returns:
+
+true if `v` represents false in the logic
+*/
+pure fn is_false(v: t) -> bool { v == tri::false }
+
+/*
+Predicate: is_unknown
+
+Returns:
+
+true if `v` represents the unknown state in the logic
+*/
+pure fn is_unknown(v: t) -> bool { v == unknown }
+
+/*
+Function: from_str
+
+Parse logic value from `s`
+*/
+pure fn from_str(s: str) -> t {
+    alt s {
+      "unknown" { unknown }
+      "true" { tri::true }
+      "false" { tri::false }
+    }
+}
+
+/*
+Function: to_str
+
+Convert `v` into a string
+*/
+pure fn to_str(v: t) -> str {
+    // FIXME replace with consts as soon as that works
+    alt v {
+      0u8 { "unknown" }
+      1u8 { "true" }
+      2u8 { "false" }
+    }
+}
+
+/*
+Function: all_values
+
+Iterates over all truth values by passing them to `blk`
+in an unspecified order
+*/
+fn all_values(blk: block(v: t)) {
+    blk(tri::false);
+    blk(unknown);
+    blk(tri::true);
+}
+
+/*
+Function: to_bit
+
+Returns:
+
+An u8 whose first bit is set if `if_true(v)` holds
+*/
+fn to_bit(v: t) -> u8 { v & b0 }
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/u32.rs b/src/libstd/u32.rs
new file mode 100644
index 00000000000..be6f649a979
--- /dev/null
+++ b/src/libstd/u32.rs
@@ -0,0 +1,27 @@
+/*
+Module: u32
+*/
+
+/*
+Const: min_value
+
+Return the minimal value for a u32
+*/
+const min_value: u32 = 0u32;
+
+/*
+Const: max_value
+
+Return the maximal value for a u32
+*/
+const max_value: u32 = 4294967296u32;
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/libstd/u64.rs b/src/libstd/u64.rs
new file mode 100644
index 00000000000..aacc35a827d
--- /dev/null
+++ b/src/libstd/u64.rs
@@ -0,0 +1,65 @@
+/*
+Module: u64
+*/
+
+/*
+Const: min_value
+
+Return the minimal value for a u64
+*/
+const min_value: u64 = 0u64;
+
+/*
+Const: max_value
+
+Return the maximal value for a u64
+*/
+const max_value: u64 = 18446744073709551615u64;
+
+/*
+Function: to_str
+
+Convert to a string in a given base
+*/
+fn to_str(n: u64, radix: uint) -> str {
+    assert (0u < radix && radix <= 16u);
+
+    let r64 = radix as u64;
+
+    fn digit(n: u64) -> str {
+        ret alt n {
+              0u64 { "0" }
+              1u64 { "1" }
+              2u64 { "2" }
+              3u64 { "3" }
+              4u64 { "4" }
+              5u64 { "5" }
+              6u64 { "6" }
+              7u64 { "7" }
+              8u64 { "8" }
+              9u64 { "9" }
+              10u64 { "a" }
+              11u64 { "b" }
+              12u64 { "c" }
+              13u64 { "d" }
+              14u64 { "e" }
+              15u64 { "f" }
+              _ { fail }
+            };
+    }
+
+    if n == 0u64 { ret "0"; }
+
+    let s = "";
+
+    let n = n;
+    while n > 0u64 { s = digit(n % r64) + s; n /= r64; }
+    ret s;
+}
+
+/*
+Function: str
+
+Convert to a string
+*/
+fn str(n: u64) -> str { ret to_str(n, 10u); }
diff --git a/src/libstd/u8.rs b/src/libstd/u8.rs
new file mode 100644
index 00000000000..eadfcadda4a
--- /dev/null
+++ b/src/libstd/u8.rs
@@ -0,0 +1,68 @@
+/*
+Module: u8
+*/
+
+/*
+Const: max_value
+
+The maximum value of a u8.
+*/
+const max_value: u8 = 255u8;
+
+/*
+Const: min_value
+
+The minumum value of a u8.
+*/
+const min_value: u8 = 0u8;
+
+/* Function: add */
+pure fn add(x: u8, y: u8) -> u8 { ret x + y; }
+
+/* Function: sub */
+pure fn sub(x: u8, y: u8) -> u8 { ret x - y; }
+
+/* Function: mul */
+pure fn mul(x: u8, y: u8) -> u8 { ret x * y; }
+
+/* Function: div */
+pure fn div(x: u8, y: u8) -> u8 { ret x / y; }
+
+/* Function: rem */
+pure fn rem(x: u8, y: u8) -> u8 { ret x % y; }
+
+/* Predicate: lt */
+pure fn lt(x: u8, y: u8) -> bool { ret x < y; }
+
+/* Predicate: le */
+pure fn le(x: u8, y: u8) -> bool { ret x <= y; }
+
+/* Predicate: eq */
+pure fn eq(x: u8, y: u8) -> bool { ret x == y; }
+
+/* Predicate: ne */
+pure fn ne(x: u8, y: u8) -> bool { ret x != y; }
+
+/* Predicate: ge */
+pure fn ge(x: u8, y: u8) -> bool { ret x >= y; }
+
+/* Predicate: gt */
+pure fn gt(x: u8, y: u8) -> bool { ret x > y; }
+
+/*
+Function: range
+
+Iterate over the range [`lo`..`hi`)
+*/
+fn range(lo: u8, hi: u8, it: block(u8)) {
+    let i = lo;
+    while i < hi { it(i); i += 1u8; }
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/ufind.rs b/src/libstd/ufind.rs
new file mode 100644
index 00000000000..7de70526a7f
--- /dev/null
+++ b/src/libstd/ufind.rs
@@ -0,0 +1,51 @@
+
+import option::{some, none};
+
+
+// A very naive implementation of union-find with unsigned integer nodes.
+// Maintains the invariant that the root of a node is always equal to or less
+// than the node itself.
+type node = option::t<uint>;
+
+type ufind = {mutable nodes: [mutable node]};
+
+fn make() -> ufind { ret {mutable nodes: [mutable]}; }
+
+fn make_set(ufnd: ufind) -> uint {
+    let idx = vec::len(ufnd.nodes);
+    ufnd.nodes += [mutable none::<uint>];
+    ret idx;
+}
+
+
+/// Creates sets as necessary to ensure that least `n` sets are present in the
+/// data structure.
+fn grow(ufnd: ufind, n: uint) {
+    while set_count(ufnd) < n { make_set(ufnd); }
+}
+
+fn find(ufnd: ufind, n: uint) -> uint {
+    alt ufnd.nodes[n] {
+      none. { ret n; }
+      some(m) { let m_ = m; be find(ufnd, m_); }
+    }
+}
+
+fn union(ufnd: ufind, m: uint, n: uint) {
+    let m_root = find(ufnd, m);
+    let n_root = find(ufnd, n);
+    if m_root < n_root {
+        ufnd.nodes[n_root] = some::<uint>(m_root);
+    } else if m_root > n_root { ufnd.nodes[m_root] = some::<uint>(n_root); }
+}
+
+fn set_count(ufnd: ufind) -> uint { ret vec::len::<node>(ufnd.nodes); }
+
+
+// Removes all sets with IDs greater than or equal to the given value.
+fn prune(ufnd: ufind, n: uint) {
+    // TODO: Use "slice" once we get rid of "const"
+
+    let len = vec::len::<node>(ufnd.nodes);
+    while len != n { vec::pop::<node>(ufnd.nodes); len -= 1u; }
+}
diff --git a/src/libstd/uint.rs b/src/libstd/uint.rs
new file mode 100644
index 00000000000..ae1ba628aa6
--- /dev/null
+++ b/src/libstd/uint.rs
@@ -0,0 +1,254 @@
+/*
+Module: uint
+*/
+
+/*
+Const: min_value
+
+Return the minimal value for an uint.
+
+This is always 0
+*/
+const min_value: uint = 0u;
+
+/*
+Const: max_value
+
+Return the maximal value for an uint.
+
+This is 2^wordsize - 1
+*/
+const max_value: uint = 0u - 1u;
+
+/* Function: add */
+pure fn add(x: uint, y: uint) -> uint { ret x + y; }
+
+/* Function: sub */
+pure fn sub(x: uint, y: uint) -> uint { ret x - y; }
+
+/* Function: mul */
+pure fn mul(x: uint, y: uint) -> uint { ret x * y; }
+
+/* Function: div */
+pure fn div(x: uint, y: uint) -> uint { ret x / y; }
+
+/* Function: div_ceil
+
+   Divide two numbers, return the result, rounded up.
+
+   Parameters:
+   x - an integer
+   y - an integer distinct from 0u
+
+   Return:
+    The smallest integer `q` such that `x/y <= q`.
+*/
+pure fn div_ceil(x: uint, y: uint) -> uint {
+    let div = div(x, y);
+    if x % y == 0u { ret div;}
+    else { ret div + 1u; }
+}
+
+/* Function: div_ceil
+
+   Divide two numbers, return the result, rounded to the closest integer.
+
+   Parameters:
+   x - an integer
+   y - an integer distinct from 0u
+
+   Return:
+    The integer `q` closest to `x/y`.
+*/
+pure fn div_round(x: uint, y: uint) -> uint {
+    let div = div(x, y);
+    if x % y * 2u  < y { ret div;}
+    else { ret div + 1u; }
+}
+
+/* Function: div_ceil
+
+   Divide two numbers, return the result, rounded down.
+
+   Parameters:
+   x - an integer
+   y - an integer distinct from 0u
+
+   Note: This is the same function as `div`.
+
+   Return:
+    The smallest integer `q` such that `x/y <= q`. This
+   is either `x/y` or `x/y + 1`.
+*/
+pure fn div_floor(x: uint, y: uint) -> uint { ret x / y; }
+
+/* Function: rem */
+pure fn rem(x: uint, y: uint) -> uint { ret x % y; }
+
+/* Predicate: lt */
+pure fn lt(x: uint, y: uint) -> bool { ret x < y; }
+
+/* Predicate: le */
+pure fn le(x: uint, y: uint) -> bool { ret x <= y; }
+
+/* Predicate: eq */
+pure fn eq(x: uint, y: uint) -> bool { ret x == y; }
+
+/* Predicate: ne */
+pure fn ne(x: uint, y: uint) -> bool { ret x != y; }
+
+/* Predicate: ge */
+pure fn ge(x: uint, y: uint) -> bool { ret x >= y; }
+
+/* Predicate: gt */
+pure fn gt(x: uint, y: uint) -> bool { ret x > y; }
+
+/*
+Function: range
+
+Iterate over the range [`lo`..`hi`)
+*/
+fn range(lo: uint, hi: uint, it: block(uint)) {
+    let i = lo;
+    while i < hi { it(i); i += 1u; }
+}
+
+/*
+Function: loop
+
+Iterate over the range [`lo`..`hi`), or stop when requested
+
+Parameters:
+lo - The integer at which to start the loop (included)
+hi - The integer at which to stop the loop (excluded)
+it - A block to execute with each consecutive integer of the range.
+Return `true` to continue, `false` to stop.
+
+Returns:
+
+`true` If execution proceeded correctly, `false` if it was interrupted,
+that is if `it` returned `false` at any point.
+*/
+fn loop(lo: uint, hi: uint, it: block(uint) -> bool) -> bool {
+    let i = lo;
+    while i < hi {
+        if (!it(i)) { ret false; }
+        i += 1u;
+    }
+    ret true;
+}
+
+/*
+Function: next_power_of_two
+
+Returns the smallest power of 2 greater than or equal to `n`
+*/
+fn next_power_of_two(n: uint) -> uint {
+    let halfbits: uint = sys::size_of::<uint>() * 4u;
+    let tmp: uint = n - 1u;
+    let shift: uint = 1u;
+    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
+    ret tmp + 1u;
+}
+
+/*
+Function: parse_buf
+
+Parse a buffer of bytes
+
+Parameters:
+
+buf - A byte buffer
+radix - The base of the number
+
+Failure:
+
+buf must not be empty
+*/
+fn parse_buf(buf: [u8], radix: uint) -> uint {
+    if vec::len::<u8>(buf) == 0u {
+        log_err "parse_buf(): buf is empty";
+        fail;
+    }
+    let i = vec::len::<u8>(buf) - 1u;
+    let power = 1u;
+    let n = 0u;
+    while true {
+        let digit = char::to_digit(buf[i] as char);
+        if (digit as uint) >= radix {
+            fail;
+        }
+        n += (digit as uint) * power;
+        power *= radix;
+        if i == 0u { ret n; }
+        i -= 1u;
+    }
+    fail;
+}
+
+/*
+Function: from_str
+
+Parse a string to an int
+
+Failure:
+
+s must not be empty
+*/
+fn from_str(s: str) -> uint { parse_buf(str::bytes(s), 10u) }
+
+/*
+Function: to_str
+
+Convert to a string in a given base
+*/
+fn to_str(num: uint, radix: uint) -> str {
+    let n = num;
+    assert (0u < radix && radix <= 16u);
+    fn digit(n: uint) -> char {
+        ret alt n {
+              0u { '0' }
+              1u { '1' }
+              2u { '2' }
+              3u { '3' }
+              4u { '4' }
+              5u { '5' }
+              6u { '6' }
+              7u { '7' }
+              8u { '8' }
+              9u { '9' }
+              10u { 'a' }
+              11u { 'b' }
+              12u { 'c' }
+              13u { 'd' }
+              14u { 'e' }
+              15u { 'f' }
+              _ { fail }
+            };
+    }
+    if n == 0u { ret "0"; }
+    let s: str = "";
+    while n != 0u {
+        s += str::unsafe_from_byte(digit(n % radix) as u8);
+        n /= radix;
+    }
+    let s1: str = "";
+    let len: uint = str::byte_len(s);
+    while len != 0u { len -= 1u; s1 += str::unsafe_from_byte(s[len]); }
+    ret s1;
+}
+
+/*
+Function: str
+
+Convert to a string
+*/
+fn str(i: uint) -> str { ret to_str(i, 10u); }
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/unicode.rs b/src/libstd/unicode.rs
new file mode 100644
index 00000000000..5038721d26e
--- /dev/null
+++ b/src/libstd/unicode.rs
@@ -0,0 +1,166 @@
+
+mod icu {
+    type UBool = u8;
+    type UProperty = int;
+    type UChar32 = char;
+
+    const TRUE : u8 = 1u8;
+    const FALSE : u8 = 1u8;
+
+    const UCHAR_ALPHABETIC : UProperty = 0;
+    const UCHAR_BINARY_START : UProperty = 0; // = UCHAR_ALPHABETIC
+    const UCHAR_ASCII_HEX_DIGIT : UProperty = 1;
+    const UCHAR_BIDI_CONTROL : UProperty = 2;
+
+    const UCHAR_BIDI_MIRRORED : UProperty = 3;
+    const UCHAR_DASH : UProperty = 4;
+    const UCHAR_DEFAULT_IGNORABLE_CODE_POINT : UProperty = 5;
+    const UCHAR_DEPRECATED : UProperty = 6;
+
+    const UCHAR_DIACRITIC : UProperty = 7;
+    const UCHAR_EXTENDER : UProperty = 8;
+    const UCHAR_FULL_COMPOSITION_EXCLUSION : UProperty = 9;
+    const UCHAR_GRAPHEME_BASE : UProperty = 10;
+
+    const UCHAR_GRAPHEME_EXTEND : UProperty = 11;
+    const UCHAR_GRAPHEME_LINK : UProperty = 12;
+    const UCHAR_HEX_DIGIT : UProperty = 13;
+    const UCHAR_HYPHEN : UProperty = 14;
+
+    const UCHAR_ID_CONTINUE : UProperty = 15;
+    const UCHAR_ID_START : UProperty = 16;
+    const UCHAR_IDEOGRAPHIC : UProperty = 17;
+    const UCHAR_IDS_BINARY_OPERATOR : UProperty = 18;
+
+    const UCHAR_IDS_TRINARY_OPERATOR : UProperty = 19;
+    const UCHAR_JOIN_CONTROL : UProperty = 20;
+    const UCHAR_LOGICAL_ORDER_EXCEPTION : UProperty = 21;
+    const UCHAR_LOWERCASE : UProperty = 22;
+
+    const UCHAR_MATH : UProperty = 23;
+    const UCHAR_NONCHARACTER_CODE_POINT : UProperty = 24;
+    const UCHAR_QUOTATION_MARK : UProperty = 25;
+    const UCHAR_RADICAL : UProperty = 26;
+
+    const UCHAR_SOFT_DOTTED : UProperty = 27;
+    const UCHAR_TERMINAL_PUNCTUATION : UProperty = 28;
+    const UCHAR_UNIFIED_IDEOGRAPH : UProperty = 29;
+    const UCHAR_UPPERCASE : UProperty = 30;
+
+    const UCHAR_WHITE_SPACE : UProperty = 31;
+    const UCHAR_XID_CONTINUE : UProperty = 32;
+    const UCHAR_XID_START : UProperty = 33;
+    const UCHAR_CASE_SENSITIVE : UProperty = 34;
+
+    const UCHAR_S_TERM : UProperty = 35;
+    const UCHAR_VARIATION_SELECTOR : UProperty = 36;
+    const UCHAR_NFD_INERT : UProperty = 37;
+    const UCHAR_NFKD_INERT : UProperty = 38;
+
+    const UCHAR_NFC_INERT : UProperty = 39;
+    const UCHAR_NFKC_INERT : UProperty = 40;
+    const UCHAR_SEGMENT_STARTER : UProperty = 41;
+    const UCHAR_PATTERN_SYNTAX : UProperty = 42;
+
+    const UCHAR_PATTERN_WHITE_SPACE : UProperty = 43;
+    const UCHAR_POSIX_ALNUM : UProperty = 44;
+    const UCHAR_POSIX_BLANK : UProperty = 45;
+    const UCHAR_POSIX_GRAPH : UProperty = 46;
+
+    const UCHAR_POSIX_PRINT : UProperty = 47;
+    const UCHAR_POSIX_XDIGIT : UProperty = 48;
+    const UCHAR_CASED : UProperty = 49;
+    const UCHAR_CASE_IGNORABLE : UProperty = 50;
+
+    const UCHAR_CHANGES_WHEN_LOWERCASED : UProperty = 51;
+    const UCHAR_CHANGES_WHEN_UPPERCASED : UProperty = 52;
+    const UCHAR_CHANGES_WHEN_TITLECASED : UProperty = 53;
+    const UCHAR_CHANGES_WHEN_CASEFOLDED : UProperty = 54;
+
+    const UCHAR_CHANGES_WHEN_CASEMAPPED : UProperty = 55;
+    const UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED : UProperty = 56;
+    const UCHAR_BINARY_LIMIT : UProperty = 57;
+    const UCHAR_BIDI_CLASS : UProperty = 0x1000;
+
+    const UCHAR_INT_START : UProperty = 0x1000; // UCHAR_BIDI_CLASS
+    const UCHAR_BLOCK : UProperty = 0x1001;
+    const UCHAR_CANONICAL_COMBINING_CLASS : UProperty = 0x1002;
+    const UCHAR_DECOMPOSITION_TYPE : UProperty = 0x1003;
+
+    const UCHAR_EAST_ASIAN_WIDTH : UProperty = 0x1004;
+    const UCHAR_GENERAL_CATEGORY : UProperty = 0x1005;
+    const UCHAR_JOINING_GROUP : UProperty = 0x1006;
+    const UCHAR_JOINING_TYPE : UProperty = 0x1007;
+
+    const UCHAR_LINE_BREAK : UProperty = 0x1008;
+    const UCHAR_NUMERIC_TYPE : UProperty = 0x1009;
+    const UCHAR_SCRIPT : UProperty = 0x100A;
+    const UCHAR_HANGUL_SYLLABLE_TYPE : UProperty = 0x100B;
+
+    const UCHAR_NFD_QUICK_CHECK : UProperty = 0x100C;
+    const UCHAR_NFKD_QUICK_CHECK : UProperty = 0x100D;
+    const UCHAR_NFC_QUICK_CHECK : UProperty = 0x100E;
+    const UCHAR_NFKC_QUICK_CHECK : UProperty = 0x100F;
+
+    const UCHAR_LEAD_CANONICAL_COMBINING_CLASS : UProperty = 0x1010;
+    const UCHAR_TRAIL_CANONICAL_COMBINING_CLASS : UProperty = 0x1011;
+    const UCHAR_GRAPHEME_CLUSTER_BREAK : UProperty = 0x1012;
+    const UCHAR_SENTENCE_BREAK : UProperty = 0x1013;
+
+    const UCHAR_WORD_BREAK : UProperty = 0x1014;
+    const UCHAR_INT_LIMIT : UProperty = 0x1015;
+
+    const UCHAR_GENERAL_CATEGORY_MASK : UProperty = 0x2000;
+    const UCHAR_MASK_START : UProperty = 0x2000;
+    // = UCHAR_GENERAL_CATEGORY_MASK
+    const UCHAR_MASK_LIMIT : UProperty = 0x2001;
+
+    const UCHAR_NUMERIC_VALUE : UProperty = 0x3000;
+    const UCHAR_DOUBLE_START : UProperty = 0x3000;
+    // = UCHAR_NUMERIC_VALUE
+    const UCHAR_DOUBLE_LIMIT : UProperty = 0x3001;
+
+    const UCHAR_AGE : UProperty = 0x4000;
+    const UCHAR_STRING_START : UProperty = 0x4000; // = UCHAR_AGE
+    const UCHAR_BIDI_MIRRORING_GLYPH : UProperty = 0x4001;
+    const UCHAR_CASE_FOLDING : UProperty = 0x4002;
+
+    const UCHAR_ISO_COMMENT : UProperty = 0x4003;
+    const UCHAR_LOWERCASE_MAPPING : UProperty = 0x4004;
+    const UCHAR_NAME : UProperty = 0x4005;
+    const UCHAR_SIMPLE_CASE_FOLDING : UProperty = 0x4006;
+
+    const UCHAR_SIMPLE_LOWERCASE_MAPPING : UProperty = 0x4007;
+    const UCHAR_SIMPLE_TITLECASE_MAPPING : UProperty = 0x4008;
+    const UCHAR_SIMPLE_UPPERCASE_MAPPING : UProperty = 0x4009;
+    const UCHAR_TITLECASE_MAPPING : UProperty = 0x400A;
+
+    const UCHAR_UNICODE_1_NAME : UProperty = 0x400B;
+    const UCHAR_UPPERCASE_MAPPING : UProperty = 0x400C;
+    const UCHAR_STRING_LIMIT : UProperty = 0x400D;
+
+    const UCHAR_SCRIPT_EXTENSIONS : UProperty = 0x7000;
+    const UCHAR_OTHER_PROPERTY_START : UProperty = 0x7000;
+    // = UCHAR_SCRIPT_EXTENSIONS;
+    const UCHAR_OTHER_PROPERTY_LIMIT : UProperty = 0x7001;
+
+    const UCHAR_INVALID_CODE : UProperty = 0xffffffff;
+    // FIXME: should be -1, change when compiler supports negative
+    // constants
+
+    #[link_name = "icuuc"]
+    #[abi = "cdecl"]
+    native mod libicu {
+        fn u_hasBinaryProperty(c: UChar32, which: UProperty) -> UBool;
+    }
+}
+
+fn is_XID_start(c: char) -> bool {
+    ret icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
+        == icu::TRUE;
+}
+
+fn is_XID_continue(c: char) -> bool {
+    ret icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
+        == icu::TRUE;
+}
diff --git a/src/libstd/unsafe.rs b/src/libstd/unsafe.rs
new file mode 100644
index 00000000000..22cce495649
--- /dev/null
+++ b/src/libstd/unsafe.rs
@@ -0,0 +1,41 @@
+/*
+Module: unsafe
+
+Unsafe operations
+*/
+
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn cast<T, U>(src: T) -> U;
+}
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn leak<T>(-thing: T);
+}
+
+/*
+Function: reinterpret_cast
+
+Casts the value at `src` to U. The two types must have the same length.
+*/
+unsafe fn reinterpret_cast<T, U>(src: T) -> U {
+    let t1 = sys::get_type_desc::<T>();
+    let t2 = sys::get_type_desc::<U>();
+    if (*t1).size != (*t2).size {
+        fail "attempt to cast values of differing sizes";
+    }
+    ret rusti::cast(src);
+}
+
+/*
+Function: leak
+
+Move `thing` into the void.
+
+The leak function will take ownership of the provided value but neglect
+to run any required cleanup or memory-management operations on it. This
+can be used for various acts of magick, particularly when using
+reinterpret_cast on managed pointer types.
+*/
+unsafe fn leak<T>(-thing: T) { rustrt::leak(thing); }
diff --git a/src/libstd/util.rs b/src/libstd/util.rs
new file mode 100644
index 00000000000..a15b5291546
--- /dev/null
+++ b/src/libstd/util.rs
@@ -0,0 +1,57 @@
+/*
+Module: util
+*/
+
+/*
+Function: id
+
+The identity function
+*/
+pure fn id<T>(x: T) -> T { x }
+
+/*
+Function: unreachable
+
+A standard function to use to indicate unreachable code. Because the
+function is guaranteed to fail typestate will correctly identify
+any code paths following the appearance of this function as unreachable.
+*/
+fn unreachable() -> ! {
+    fail "Internal error: entered unreachable code";
+}
+
+/* FIXME (issue #141):  See test/run-pass/constrained-type.rs.  Uncomment
+ * the constraint once fixed. */
+/*
+Function: rational
+
+A rational number
+*/
+type rational = {num: int, den: int}; // : int::positive(*.den);
+
+/*
+Function: rational_leq
+*/
+pure fn rational_leq(x: rational, y: rational) -> bool {
+    // NB: Uses the fact that rationals have positive denominators WLOG:
+
+    x.num * y.den <= y.num * x.den
+}
+
+/*
+Function: orb
+*/
+pure fn orb(a: bool, b: bool) -> bool { a || b }
+
+// FIXME: Document what this is for or delete it
+tag void {
+    void(@void);
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/uv.rs b/src/libstd/uv.rs
new file mode 100644
index 00000000000..17916b844e3
--- /dev/null
+++ b/src/libstd/uv.rs
@@ -0,0 +1,150 @@
+/*
+This is intended to be a low-level binding to libuv that very closely mimics
+the C libuv API. Does very little right now pending scheduler improvements.
+*/
+
+#[cfg(target_os = "linux")];
+#[cfg(target_os = "macos")];
+
+export sanity_check;
+export loop_t, idle_t;
+export loop_new, loop_delete, default_loop, run, unref;
+export idle_init, idle_start;
+export idle_new;
+
+#[link_name = "rustrt"]
+native mod uv {
+    fn rust_uv_loop_new() -> *loop_t;
+    fn rust_uv_loop_delete(loop: *loop_t);
+    fn rust_uv_default_loop() -> *loop_t;
+    fn rust_uv_run(loop: *loop_t) -> ctypes::c_int;
+    fn rust_uv_unref(loop: *loop_t);
+    fn rust_uv_idle_init(loop: *loop_t, idle: *idle_t) -> ctypes::c_int;
+    fn rust_uv_idle_start(idle: *idle_t, cb: idle_cb) -> ctypes::c_int;
+}
+
+#[link_name = "rustrt"]
+native mod helpers {
+    fn rust_uv_size_of_idle_t() -> ctypes::size_t;
+}
+
+type opaque_cb = *ctypes::void;
+
+type handle_type = ctypes::enum;
+
+type close_cb = opaque_cb;
+type idle_cb = opaque_cb;
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "macos")]
+type handle_private_fields = {
+    a00: ctypes::c_int,
+    a01: ctypes::c_int,
+    a02: ctypes::c_int,
+    a03: ctypes::c_int,
+    a04: ctypes::c_int,
+    a05: ctypes::c_int,
+    a06: int,
+    a07: int,
+    a08: int,
+    a09: int,
+    a10: int,
+    a11: int,
+    a12: int
+};
+
+type handle_fields = {
+    loop: *loop_t,
+    type_: handle_type,
+    close_cb: close_cb,
+    data: *ctypes::void,
+    private: handle_private_fields
+};
+
+type handle_t = {
+    fields: handle_fields
+};
+
+type loop_t = int;
+
+
+
+
+type idle_t = {
+    fields: handle_fields
+    /* private: idle_private_fields */
+};
+
+fn idle_init(loop: *loop_t, idle: *idle_t) -> ctypes::c_int {
+    uv::rust_uv_idle_init(loop, idle)
+}
+
+fn idle_start(idle: *idle_t, cb: idle_cb) -> ctypes::c_int {
+    uv::rust_uv_idle_start(idle, cb)
+}
+
+
+
+
+fn default_loop() -> *loop_t {
+    uv::rust_uv_default_loop()
+}
+
+fn loop_new() -> *loop_t {
+    uv::rust_uv_loop_new()
+}
+
+fn loop_delete(loop: *loop_t) {
+    uv::rust_uv_loop_delete(loop)
+}
+
+fn run(loop: *loop_t) -> ctypes::c_int {
+    uv::rust_uv_run(loop)
+}
+
+fn unref(loop: *loop_t) {
+    uv::rust_uv_unref(loop)
+}
+
+
+fn sanity_check() {
+    fn check_size(t: str, uv: ctypes::size_t, rust: ctypes::size_t) {
+        log #fmt("size of %s: uv: %u, rust: %u", t, uv, rust);
+        assert uv == rust;
+    }
+    check_size("idle_t",
+               helpers::rust_uv_size_of_idle_t(),
+               sys::size_of::<idle_t>());
+}
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "macos")]
+fn handle_fields_new() -> handle_fields {
+    {
+        loop: ptr::null(),
+        type_: 0u32,
+        close_cb: ptr::null(),
+        data: ptr::null(),
+        private: {
+            a00: 0i32,
+            a01: 0i32,
+            a02: 0i32,
+            a03: 0i32,
+            a04: 0i32,
+            a05: 0i32,
+            a06: 0,
+            a07: 0,
+            a08: 0,
+            a09: 0,
+            a10: 0,
+            a11: 0,
+            a12: 0
+        }
+    }
+}
+
+fn idle_new() -> idle_t {
+    {
+        fields: handle_fields_new()
+    }
+}
\ No newline at end of file
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
new file mode 100644
index 00000000000..d8f89b3b27b
--- /dev/null
+++ b/src/libstd/vec.rs
@@ -0,0 +1,835 @@
+/*
+Module: vec
+*/
+
+import option::{some, none};
+import uint::next_power_of_two;
+import ptr::addr_of;
+
+#[abi = "rust-intrinsic"]
+native mod rusti {
+    fn vec_len<T>(&&v: [const T]) -> uint;
+}
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn vec_reserve_shared<T>(t: *sys::type_desc,
+                             &v: [const T],
+                             n: uint);
+    fn vec_from_buf_shared<T>(t: *sys::type_desc,
+                              ptr: *T,
+                              count: uint) -> [T];
+}
+
+/*
+Type: init_op
+
+A function used to initialize the elements of a vector.
+*/
+type init_op<T> = block(uint) -> T;
+
+
+/*
+Predicate: is_empty
+
+Returns true if a vector contains no elements.
+*/
+pure fn is_empty<T>(v: [const T]) -> bool {
+    // FIXME: This would be easier if we could just call len
+    for t: T in v { ret false; }
+    ret true;
+}
+
+/*
+Predicate: is_not_empty
+
+Returns true if a vector contains some elements.
+*/
+pure fn is_not_empty<T>(v: [const T]) -> bool { ret !is_empty(v); }
+
+/*
+Predicate: same_length
+
+Returns true if two vectors have the same length
+*/
+pure fn same_length<T, U>(xs: [T], ys: [U]) -> bool {
+    vec::len(xs) == vec::len(ys)
+}
+
+/*
+Function: reserve
+
+Reserves capacity for `n` elements in the given vector.
+
+If the capacity for `v` is already equal to or greater than the requested
+capacity, then no action is taken.
+
+Parameters:
+
+v - A vector
+n - The number of elements to reserve space for
+*/
+fn reserve<T>(&v: [const T], n: uint) {
+    rustrt::vec_reserve_shared(sys::get_type_desc::<T>(), v, n);
+}
+
+/*
+Function: len
+
+Returns the length of a vector
+*/
+pure fn len<T>(v: [const T]) -> uint { unchecked { rusti::vec_len(v) } }
+
+/*
+Function: init_fn
+
+Creates and initializes an immutable vector.
+
+Creates an immutable vector of size `n_elts` and initializes the elements
+to the value returned by the function `op`.
+*/
+fn init_fn<T>(op: init_op<T>, n_elts: uint) -> [T] {
+    let v = [];
+    reserve(v, n_elts);
+    let i: uint = 0u;
+    while i < n_elts { v += [op(i)]; i += 1u; }
+    ret v;
+}
+
+// TODO: Remove me once we have slots.
+/*
+Function: init_fn_mut
+
+Creates and initializes a mutable vector.
+
+Creates a mutable vector of size `n_elts` and initializes the elements to
+the value returned by the function `op`.
+*/
+fn init_fn_mut<T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
+    let v = [mutable];
+    reserve(v, n_elts);
+    let i: uint = 0u;
+    while i < n_elts { v += [mutable op(i)]; i += 1u; }
+    ret v;
+}
+
+/*
+Function: init_elt
+
+Creates and initializes an immutable vector.
+
+Creates an immutable vector of size `n_elts` and initializes the elements
+to the value `t`.
+*/
+fn init_elt<copy T>(t: T, n_elts: uint) -> [T] {
+    let v = [];
+    reserve(v, n_elts);
+    let i: uint = 0u;
+    while i < n_elts { v += [t]; i += 1u; }
+    ret v;
+}
+
+// TODO: Remove me once we have slots.
+/*
+Function: init_elt_mut
+
+Creates and initializes a mutable vector.
+
+Creates a mutable vector of size `n_elts` and initializes the elements
+to the value `t`.
+*/
+fn init_elt_mut<copy T>(t: T, n_elts: uint) -> [mutable T] {
+    let v = [mutable];
+    reserve(v, n_elts);
+    let i: uint = 0u;
+    while i < n_elts { v += [mutable t]; i += 1u; }
+    ret v;
+}
+
+// FIXME: Possible typestate postcondition:
+// len(result) == len(v) (needs issue #586)
+/*
+Function: to_mut
+
+Produces a mutable vector from an immutable vector.
+*/
+fn to_mut<copy T>(v: [T]) -> [mutable T] {
+    let vres = [mutable];
+    for t: T in v { vres += [mutable t]; }
+    ret vres;
+}
+
+// Same comment as from_mut
+/*
+Function: from_mut
+
+Produces an immutable vector from a mutable vector.
+*/
+fn from_mut<copy T>(v: [mutable T]) -> [T] {
+    let vres = [];
+    for t: T in v { vres += [t]; }
+    ret vres;
+}
+
+// Accessors
+
+/*
+Function: head
+
+Returns the first element of a vector
+
+Predicates:
+<is_not_empty> (v)
+*/
+fn head<copy T>(v: [const T]) : is_not_empty(v) -> T { ret v[0]; }
+
+/*
+Function: tail
+
+Returns all but the first element of a vector
+
+Predicates:
+<is_not_empty> (v)
+*/
+fn tail<copy T>(v: [const T]) : is_not_empty(v) -> [T] {
+    ret slice(v, 1u, len(v));
+}
+
+// FIXME: This name is sort of confusing next to init_fn, etc
+// but this is the name haskell uses for this function,
+// along with head/tail/last.
+/*
+Function: init
+
+Returns all but the last elemnt of a vector
+
+Preconditions:
+`v` is not empty
+*/
+fn init<copy T>(v: [const T]) -> [T] {
+    assert len(v) != 0u;
+    slice(v, 0u, len(v) - 1u)
+}
+
+/*
+Function: last
+
+Returns the last element of a vector
+
+Returns:
+
+An option containing the last element of `v` if `v` is not empty, or
+none if `v` is empty.
+*/
+fn last<copy T>(v: [const T]) -> option::t<T> {
+    if len(v) == 0u { ret none; }
+    ret some(v[len(v) - 1u]);
+}
+
+/*
+Function: last_total
+
+Returns the last element of a non-empty vector `v`
+
+Predicates:
+<is_not_empty> (v)
+*/
+fn last_total<copy T>(v: [const T]) : is_not_empty(v) -> T {
+    ret v[len(v) - 1u];
+}
+
+/*
+Function: slice
+
+Returns a copy of the elements from [`start`..`end`) from `v`.
+*/
+fn slice<copy T>(v: [const T], start: uint, end: uint) -> [T] {
+    assert (start <= end);
+    assert (end <= len(v));
+    let result = [];
+    reserve(result, end - start);
+    let i = start;
+    while i < end { result += [v[i]]; i += 1u; }
+    ret result;
+}
+
+// TODO: Remove me once we have slots.
+/*
+Function: slice_mut
+
+Returns a copy of the elements from [`start`..`end`) from `v`.
+*/
+fn slice_mut<copy T>(v: [const T], start: uint, end: uint) -> [mutable T] {
+    assert (start <= end);
+    assert (end <= len(v));
+    let result = [mutable];
+    reserve(result, end - start);
+    let i = start;
+    while i < end { result += [mutable v[i]]; i += 1u; }
+    ret result;
+}
+
+
+// Mutators
+
+/*
+Function: shift
+
+Removes the first element from a vector and return it
+*/
+fn shift<copy T>(&v: [const T]) -> T {
+    let ln = len::<T>(v);
+    assert (ln > 0u);
+    let e = v[0];
+    v = slice::<T>(v, 1u, ln);
+    ret e;
+}
+
+// TODO: Write this, unsafely, in a way that's not O(n).
+/*
+Function: pop
+
+Remove the last element from a vector and return it
+*/
+fn pop<copy T>(&v: [const T]) -> T {
+    let ln = len(v);
+    assert (ln > 0u);
+    ln -= 1u;
+    let e = v[ln];
+    v = slice(v, 0u, ln);
+    ret e;
+}
+
+// TODO: More.
+
+
+// Appending
+
+/*
+Function: grow
+
+Expands a vector in place, initializing the new elements to a given value
+
+Parameters:
+
+v - The vector to grow
+n - The number of elements to add
+initval - The value for the new elements
+*/
+fn grow<copy T>(&v: [T], n: uint, initval: T) {
+    reserve(v, next_power_of_two(len(v) + n));
+    let i: uint = 0u;
+    while i < n { v += [initval]; i += 1u; }
+}
+
+// TODO: Remove me once we have slots.
+// FIXME: Can't grow take a [const T]
+/*
+Function: grow_mut
+
+Expands a vector in place, initializing the new elements to a given value
+
+Parameters:
+
+v - The vector to grow
+n - The number of elements to add
+initval - The value for the new elements
+*/
+fn grow_mut<copy T>(&v: [mutable T], n: uint, initval: T) {
+    reserve(v, next_power_of_two(len(v) + n));
+    let i: uint = 0u;
+    while i < n { v += [mutable initval]; i += 1u; }
+}
+
+/*
+Function: grow_fn
+
+Expands a vector in place, initializing the new elements to the result of a
+function
+
+Function `init_fn` is called `n` times with the values [0..`n`)
+
+Parameters:
+
+v - The vector to grow
+n - The number of elements to add
+init_fn - A function to call to retreive each appended element's value
+*/
+fn grow_fn<T>(&v: [T], n: uint, op: init_op<T>) {
+    reserve(v, next_power_of_two(len(v) + n));
+    let i: uint = 0u;
+    while i < n { v += [op(i)]; i += 1u; }
+}
+
+/*
+Function: grow_set
+
+Sets the value of a vector element at a given index, growing the vector as
+needed
+
+Sets the element at position `index` to `val`. If `index` is past the end
+of the vector, expands the vector by replicating `initval` to fill the
+intervening space.
+*/
+fn grow_set<copy T>(&v: [mutable T], index: uint, initval: T, val: T) {
+    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
+    v[index] = val;
+}
+
+
+// Functional utilities
+
+/*
+Function: map
+
+Apply a function to each element of a vector and return the results
+*/
+fn map<T, U>(f: block(T) -> U, v: [T]) -> [U] {
+    let result = [];
+    reserve(result, len(v));
+    for elem: T in v { result += [f(elem)]; }
+    ret result;
+}
+
+/*
+Function: map_mut
+
+Apply a function to each element of a mutable vector and return the results
+*/
+fn map_mut<copy T, U>(f: block(T) -> U, v: [const T]) -> [U] {
+    let result = [];
+    reserve(result, len(v));
+    for elem: T in v {
+        // copy satisfies alias checker
+        result += [f(copy elem)];
+    }
+    ret result;
+}
+
+/*
+Function: map2
+
+Apply a function to each pair of elements and return the results
+*/
+fn map2<copy T, copy U, V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
+    let v0_len = len(v0);
+    if v0_len != len(v1) { fail; }
+    let u: [V] = [];
+    let i = 0u;
+    while i < v0_len { u += [f(copy v0[i], copy v1[i])]; i += 1u; }
+    ret u;
+}
+
+/*
+Function: filter_map
+
+Apply a function to each element of a vector and return the results
+
+If function `f` returns `none` then that element is excluded from
+the resulting vector.
+*/
+fn filter_map<copy T, copy U>(f: block(T) -> option::t<U>, v: [const T])
+    -> [U] {
+    let result = [];
+    for elem: T in v {
+        alt f(copy elem) {
+          none. {/* no-op */ }
+          some(result_elem) { result += [result_elem]; }
+        }
+    }
+    ret result;
+}
+
+/*
+Function: filter
+
+Construct a new vector from the elements of a vector for which some predicate
+holds.
+
+Apply function `f` to each element of `v` and return a vector containing
+only those elements for which `f` returned true.
+*/
+fn filter<copy T>(f: block(T) -> bool, v: [T]) -> [T] {
+    let result = [];
+    for elem: T in v {
+        if f(elem) { result += [elem]; }
+    }
+    ret result;
+}
+
+/*
+Function: concat
+
+Concatenate a vector of vectors. Flattens a vector of vectors of T into
+a single vector of T.
+*/
+fn concat<copy T>(v: [const [const T]]) -> [T] {
+    let new: [T] = [];
+    for inner: [T] in v { new += inner; }
+    ret new;
+}
+
+/*
+Function: foldl
+
+Reduce a vector from left to right
+*/
+fn foldl<copy T, U>(p: block(T, U) -> T, z: T, v: [const U]) -> T {
+    let accum = z;
+    iter(v) { |elt|
+        accum = p(accum, elt);
+    }
+    ret accum;
+}
+
+/*
+Function: foldr
+
+Reduce a vector from right to left
+*/
+fn foldr<T, copy U>(p: block(T, U) -> U, z: U, v: [const T]) -> U {
+    let accum = z;
+    riter(v) { |elt|
+        accum = p(elt, accum);
+    }
+    ret accum;
+}
+
+/*
+Function: any
+
+Return true if a predicate matches any elements
+
+If the vector contains no elements then false is returned.
+*/
+fn any<T>(f: block(T) -> bool, v: [T]) -> bool {
+    for elem: T in v { if f(elem) { ret true; } }
+    ret false;
+}
+
+/*
+Function: all
+
+Return true if a predicate matches all elements
+
+If the vector contains no elements then true is returned.
+*/
+fn all<T>(f: block(T) -> bool, v: [T]) -> bool {
+    for elem: T in v { if !f(elem) { ret false; } }
+    ret true;
+}
+
+/*
+Function: member
+
+Return true if a vector contains an element with the given value
+*/
+fn member<T>(x: T, v: [T]) -> bool {
+    for elt: T in v { if x == elt { ret true; } }
+    ret false;
+}
+
+/*
+Function: count
+
+Returns the number of elements that are equal to a given value
+*/
+fn count<T>(x: T, v: [const T]) -> uint {
+    let cnt = 0u;
+    for elt: T in v { if x == elt { cnt += 1u; } }
+    ret cnt;
+}
+
+/*
+Function: find
+
+Search for an element that matches a given predicate
+
+Apply function `f` to each element of `v`, starting from the first.
+When function `f` returns true then an option containing the element
+is returned. If `f` matches no elements then none is returned.
+*/
+fn find<copy T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
+    for elt: T in v { if f(elt) { ret some(elt); } }
+    ret none;
+}
+
+/*
+Function: position
+
+Find the first index containing a matching value
+
+Returns:
+
+option::some(uint) - The first index containing a matching value
+option::none - No elements matched
+*/
+fn position<T>(x: T, v: [T]) -> option::t<uint> {
+    let i: uint = 0u;
+    while i < len(v) { if x == v[i] { ret some::<uint>(i); } i += 1u; }
+    ret none;
+}
+
+/*
+Function: position_pred
+
+Find the first index for which the value matches some predicate
+*/
+fn position_pred<T>(f: block(T) -> bool, v: [T]) -> option::t<uint> {
+    let i: uint = 0u;
+    while i < len(v) { if f(v[i]) { ret some::<uint>(i); } i += 1u; }
+    ret none;
+}
+
+// FIXME: if issue #586 gets implemented, could have a postcondition
+// saying the two result lists have the same length -- or, could
+// return a nominal record with a constraint saying that, instead of
+// returning a tuple (contingent on issue #869)
+/*
+Function: unzip
+
+Convert a vector of pairs into a pair of vectors
+
+Returns a tuple containing two vectors where the i-th element of the first
+vector contains the first element of the i-th tuple of the input vector,
+and the i-th element of the second vector contains the second element
+of the i-th tuple of the input vector.
+*/
+fn unzip<copy T, copy U>(v: [(T, U)]) -> ([T], [U]) {
+    let as = [], bs = [];
+    for (a, b) in v { as += [a]; bs += [b]; }
+    ret (as, bs);
+}
+
+/*
+Function: zip
+
+Convert two vectors to a vector of pairs
+
+Returns a vector of tuples, where the i-th tuple contains contains the
+i-th elements from each of the input vectors.
+
+Preconditions:
+
+<same_length> (v, u)
+*/
+fn zip<copy T, copy U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
+    let zipped = [];
+    let sz = len(v), i = 0u;
+    assert (sz == len(u));
+    while i < sz { zipped += [(v[i], u[i])]; i += 1u; }
+    ret zipped;
+}
+
+/*
+Function: swap
+
+Swaps two elements in a vector
+
+Parameters:
+v - The input vector
+a - The index of the first element
+b - The index of the second element
+*/
+fn swap<T>(v: [mutable T], a: uint, b: uint) {
+    v[a] <-> v[b];
+}
+
+/*
+Function: reverse
+
+Reverse the order of elements in a vector, in place
+*/
+fn reverse<T>(v: [mutable T]) {
+    let i: uint = 0u;
+    let ln = len::<T>(v);
+    while i < ln / 2u { v[i] <-> v[ln - i - 1u]; i += 1u; }
+}
+
+
+/*
+Function: reversed
+
+Returns a vector with the order of elements reversed
+*/
+fn reversed<copy T>(v: [const T]) -> [T] {
+    let rs: [T] = [];
+    let i = len::<T>(v);
+    if i == 0u { ret rs; } else { i -= 1u; }
+    while i != 0u { rs += [v[i]]; i -= 1u; }
+    rs += [v[0]];
+    ret rs;
+}
+
+// FIXME: Seems like this should take char params. Maybe belongs in char
+/*
+Function: enum_chars
+
+Returns a vector containing a range of chars
+*/
+fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] {
+    let i = start;
+    let r = [];
+    while i <= end { r += [i as char]; i += 1u as u8; }
+    ret r;
+}
+
+// FIXME: Probably belongs in uint. Compare to uint::range
+/*
+Function: enum_uints
+
+Returns a vector containing a range of uints
+*/
+fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] {
+    let i = start;
+    let r = [];
+    while i <= end { r += [i]; i += 1u; }
+    ret r;
+}
+
+/*
+Function: iter
+
+Iterates over a vector
+
+Iterates over vector `v` and, for each element, calls function `f` with the
+element's value.
+
+*/
+fn iter<T>(v: [const T], f: block(T)) {
+    iter2(v) { |_i, v| f(v) }
+}
+
+/*
+Function: iter2
+
+Iterates over a vector's elements and indexes
+
+Iterates over vector `v` and, for each element, calls function `f` with the
+element's value and index.
+*/
+fn iter2<T>(v: [const T], f: block(uint, T)) {
+    let i = 0u, l = len(v);
+    while i < l { f(i, v[i]); i += 1u; }
+}
+
+/*
+Function: riter
+
+Iterates over a vector in reverse
+
+Iterates over vector `v` and, for each element, calls function `f` with the
+element's value.
+
+*/
+fn riter<T>(v: [const T], f: block(T)) {
+    riter2(v) { |_i, v| f(v) }
+}
+
+/*
+Function: riter2
+
+Iterates over a vector's elements and indexes in reverse
+
+Iterates over vector `v` and, for each element, calls function `f` with the
+element's value and index.
+*/
+fn riter2<T>(v: [const T], f: block(uint, T)) {
+    let i = len(v);
+    while 0u < i {
+        i -= 1u;
+        f(i, v[i]);
+    };
+}
+
+/*
+Function: permute
+
+Iterate over all permutations of vector `v`.  Permutations are produced in
+lexicographic order with respect to the order of elements in `v` (so if `v`
+is sorted then the permutations are lexicographically sorted).
+
+The total number of permutations produced is `len(v)!`.  If `v` contains
+repeated elements, then some permutations are repeated.
+*/
+fn permute<copy T>(v: [const T], put: block([T])) {
+  let ln = len(v);
+  if ln == 0u {
+    put([]);
+  } else {
+    let i = 0u;
+    while i < ln {
+      let elt = v[i];
+      let rest = slice(v, 0u, i) + slice(v, i+1u, ln);
+      permute(rest) {|permutation| put([elt] + permutation)}
+      i += 1u;
+    }
+  }
+}
+
+/*
+Function: to_ptr
+
+FIXME: We don't need this wrapper
+*/
+unsafe fn to_ptr<T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }
+
+/*
+Module: unsafe
+*/
+mod unsafe {
+    type vec_repr = {mutable fill: uint, mutable alloc: uint, data: u8};
+
+    /*
+    Function: from_buf
+
+    Constructs a vector from an unsafe pointer to a buffer
+
+    Parameters:
+
+    ptr - An unsafe pointer to a buffer of `T`
+    elts - The number of elements in the buffer
+    */
+    unsafe fn from_buf<T>(ptr: *T, elts: uint) -> [T] {
+        ret rustrt::vec_from_buf_shared(sys::get_type_desc::<T>(),
+                                        ptr, elts);
+    }
+
+    /*
+    Function: set_len
+
+    Sets the length of a vector
+
+    This well explicitly set the size of the vector, without actually
+    modifing its buffers, so it is up to the caller to ensure that
+    the vector is actually the specified size.
+    */
+    unsafe fn set_len<T>(&v: [const T], new_len: uint) {
+        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
+        (**repr).fill = new_len * sys::size_of::<T>();
+    }
+
+    /*
+    Function: to_ptr
+
+    Returns an unsafe pointer to the vector's buffer
+
+    The caller must ensure that the vector outlives the pointer this
+    function returns, or else it will end up pointing to garbage.
+
+    Modifying the vector may cause its buffer to be reallocated, which
+    would also make any pointers to it invalid.
+    */
+    unsafe fn to_ptr<T>(v: [const T]) -> *T {
+        let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
+        ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
+    }
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/win32_fs.rs b/src/libstd/win32_fs.rs
new file mode 100644
index 00000000000..87c97fe35c9
--- /dev/null
+++ b/src/libstd/win32_fs.rs
@@ -0,0 +1,35 @@
+
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_list_files(path: str) -> [str];
+}
+
+fn list_dir(path: str) -> [str] {
+    let path = path + "*";
+    ret rustrt::rust_list_files(path);
+}
+
+fn path_is_absolute(p: str) -> bool {
+    ret str::char_at(p, 0u) == '/' ||
+            str::char_at(p, 1u) == ':'
+            && (str::char_at(p, 2u) == path_sep
+            || str::char_at(p, 2u) == alt_path_sep);
+}
+
+/* FIXME: win32 path handling actually accepts '/' or '\' and has subtly
+ * different semantics for each. Since we build on mingw, we are usually
+ * dealing with /-separated paths. But the whole interface to splitting and
+ * joining pathnames needs a bit more abstraction on win32. Possibly a vec or
+ * tag type.
+ */
+const path_sep: char = '/';
+
+const alt_path_sep: char = '\\';
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/libstd/win32_os.rs b/src/libstd/win32_os.rs
new file mode 100644
index 00000000000..9f648ac9721
--- /dev/null
+++ b/src/libstd/win32_os.rs
@@ -0,0 +1,133 @@
+import ctypes::*;
+
+#[abi = "cdecl"]
+#[link_name = ""]
+native mod libc {
+    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
+    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
+    #[link_name = "_open"]
+    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> c_int;
+    #[link_name = "_close"]
+    fn close(fd: fd_t) -> c_int;
+    type FILE;
+    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
+    fn _fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
+    fn fclose(f: FILE);
+    fn fflush(f: FILE) -> c_int;
+    fn fileno(f: FILE) -> fd_t;
+    fn fgetc(f: FILE) -> c_int;
+    fn ungetc(c: c_int, f: FILE);
+    fn feof(f: FILE) -> c_int;
+    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
+    fn ftell(f: FILE) -> long;
+    fn _pipe(fds: *mutable fd_t, size: unsigned, mode: c_int) -> c_int;
+}
+
+mod libc_constants {
+    const O_RDONLY: c_int    = 0i32;
+    const O_WRONLY: c_int    = 1i32;
+    const O_RDWR: c_int      = 2i32;
+    const O_APPEND: c_int    = 8i32;
+    const O_CREAT: c_int     = 256i32;
+    const O_EXCL: c_int      = 1024i32;
+    const O_TRUNC: c_int     = 512i32;
+    const O_TEXT: c_int      = 16384i32;
+    const O_BINARY: c_int    = 32768i32;
+    const O_NOINHERIT: c_int = 128i32;
+    const S_IRUSR: unsigned  = 256u32; // really _S_IREAD  in win32
+    const S_IWUSR: unsigned  = 128u32; // really _S_IWRITE in win32
+}
+
+type DWORD = u32;
+type HMODULE = uint;
+type LPTSTR = str::sbuf;
+type LPCTSTR = str::sbuf;
+
+#[abi = "stdcall"]
+native mod kernel32 {
+    type LPSECURITY_ATTRIBUTES;
+    fn GetEnvironmentVariableA(n: str::sbuf, v: str::sbuf, nsize: uint) ->
+       uint;
+    fn SetEnvironmentVariableA(n: str::sbuf, v: str::sbuf) -> int;
+    fn GetModuleFileNameA(hModule: HMODULE,
+                          lpFilename: LPTSTR,
+                          nSize: DWORD) -> DWORD;
+    fn CreateDirectoryA(lpPathName: LPCTSTR,
+                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES) -> bool;
+    fn RemoveDirectoryA(lpPathName: LPCTSTR) -> bool;
+    fn SetCurrentDirectoryA(lpPathName: LPCTSTR) -> bool;
+}
+
+// FIXME turn into constants
+fn exec_suffix() -> str { ret ".exe"; }
+fn target_os() -> str { ret "win32"; }
+
+fn dylib_filename(base: str) -> str { ret base + ".dll"; }
+
+fn pipe() -> {in: fd_t, out: fd_t} {
+    // Windows pipes work subtly differently than unix pipes, and their
+    // inheritance has to be handled in a different way that I don't fully
+    // understand. Here we explicitly make the pipe non-inheritable,
+    // which means to pass it to a subprocess they need to be duplicated
+    // first, as in rust_run_program.
+    let fds = {mutable in: 0i32, mutable out: 0i32};
+    let res =
+        os::libc::_pipe(ptr::mut_addr_of(fds.in), 1024u32,
+                        libc_constants::O_BINARY |
+                            libc_constants::O_NOINHERIT);
+    assert (res == 0i32);
+    assert (fds.in != -1i32 && fds.in != 0i32);
+    assert (fds.out != -1i32 && fds.in != 0i32);
+    ret {in: fds.in, out: fds.out};
+}
+
+fn fd_FILE(fd: fd_t) -> libc::FILE {
+    ret str::as_buf("r", {|modebuf| libc::_fdopen(fd, modebuf) });
+}
+
+fn close(fd: fd_t) -> c_int {
+    libc::close(fd)
+}
+
+fn fclose(file: libc::FILE) {
+    libc::fclose(file)
+}
+
+fn fsync_fd(fd: fd_t, level: io::fsync::level) -> c_int {
+    // FIXME (1253)
+    fail;
+}
+
+#[abi = "cdecl"]
+native mod rustrt {
+    fn rust_process_wait(handle: c_int) -> c_int;
+    fn rust_getcwd() -> str;
+}
+
+fn waitpid(pid: pid_t) -> i32 { ret rustrt::rust_process_wait(pid); }
+
+fn getcwd() -> str { ret rustrt::rust_getcwd(); }
+
+fn get_exe_path() -> option::t<fs::path> {
+    // FIXME: This doesn't handle the case where the buffer is too small
+    let bufsize = 1023u;
+    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize));
+    ret str::as_buf(path, { |path_buf|
+        if kernel32::GetModuleFileNameA(0u, path_buf,
+                                        bufsize as u32) != 0u32 {
+            option::some(fs::dirname(path) + fs::path_sep())
+        } else {
+            option::none
+        }
+    });
+}
+
+// Local Variables:
+// mode: rust;
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End: