1
Fork 0

Remove some duplicated unused parts of std now that they're present in core.

This commit is contained in:
Graydon Hoare 2011-12-14 18:04:45 -08:00
parent f7540b165c
commit dde5860380
19 changed files with 3 additions and 3936 deletions

View file

@ -1,134 +0,0 @@
// -*- 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:

View file

@ -1,20 +0,0 @@
/*
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;
}
}

View file

@ -1,150 +0,0 @@
/*
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 unsafe {
alt maybe_digit(c) {
option::some(x) { x }
option::none. { fail; }
}
}
/*
Function: to_digit
Convert a char to the corresponding digit. Returns none when the
character is not a valid hexadecimal digit.
*/
fn maybe_digit(c: char) -> option::t<u8> {
alt c {
'0' to '9' { option::some(c as u8 - ('0' as u8)) }
'a' to 'z' { option::some(c as u8 + 10u8 - ('a' as u8)) }
'A' to 'Z' { option::some(c as u8 + 10u8 - ('A' as u8)) }
_ { option::none }
}
}
/*
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 }
}

View file

@ -1,89 +0,0 @@
/*
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:
//

View file

@ -1,343 +0,0 @@
/*
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;
}
/* Const: NaN */
const NaN: float = 0./0.;
/* Const: infinity */
const infinity: float = 1./0.;
/* Const: neg_infinity */
const neg_infinity: float = -1./0.;
/* Predicate: isNaN */
pure fn isNaN(f: float) -> bool { f != f }
/* 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:
//

View file

@ -1,189 +0,0 @@
/*
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:

View file

@ -1,93 +0,0 @@
/*
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, opt: t<T>, f: block(T) -> U) -> 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>(opt: t<T>, f: block(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:

View file

@ -1,52 +0,0 @@
/*
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); }

View file

@ -1,112 +0,0 @@
/*
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) }
}
}

View file

@ -7,35 +7,17 @@
#[license = "BSD"]; #[license = "BSD"];
#[crate_type = "lib"]; #[crate_type = "lib"];
export box, char, float, int, str, ptr; export comm, fs, io, net, run, uv;
export uint, u8, u32, u64, vec, bool; export c_vec, ctypes, four, tri, util;
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 bitv, deque, fun_treemap, list, map, smallintmap, sort, treemap, ufind;
export rope; export rope;
export math; export math;
export ebml, dbg, getopts, json, rand, sha1, term, time, unsafe; export ebml, dbg, getopts, json, rand, sha1, term, time;
export extfmt, test, tempfile; export extfmt, test, tempfile;
// FIXME: generic_os and os_fs shouldn't be exported // FIXME: generic_os and os_fs shouldn't be exported
export generic_os, os, os_fs; 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 // General io and system-services modules
mod comm; mod comm;
@ -44,8 +26,6 @@ mod io;
mod net; mod net;
#[path = "run_program.rs"] #[path = "run_program.rs"]
mod run; mod run;
mod sys;
mod task;
mod uv; mod uv;
@ -56,9 +36,6 @@ mod ctypes;
mod cmath; /* unexported */ mod cmath; /* unexported */
mod math_f32; mod math_f32;
mod math_f64; mod math_f64;
mod either;
mod option;
mod result;
mod four; mod four;
mod tri; mod tri;
mod util; mod util;
@ -90,7 +67,6 @@ mod sha1;
mod tempfile; mod tempfile;
mod term; mod term;
mod time; mod time;
mod unsafe;
#[cfg(unicode)] #[cfg(unicode)]
mod unicode; mod unicode;

View file

@ -1,960 +0,0 @@
/*
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 of 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. The result vector is not
null-terminated.
*/
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 occurrence 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 occurrence of a given separator
Returns:
A vector containing all the strings between each occurrence 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 occurrences 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 occurrences 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 {
'"' { "\\\"" }
'\\' { "\\\\" }
'\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
}

View file

@ -1,96 +0,0 @@
/*
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:

View file

@ -1,357 +0,0 @@
/*
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;
// FIXME: uncomment this when extfmt is moved to core
// in a snapshot.
// 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 {
// FIXME: uncomment this when extfmt is moved to core
// in a snapshot.
// fail #fmt["join received id %d, expected %d", _id, id]
fail;
}
}
}
}
/*
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:

View file

@ -1,27 +0,0 @@
/*
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 = 0xffff_ffffu32;
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

View file

@ -1,88 +0,0 @@
/*
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); }
/*
Function: parse_buf
Parse a string as an unsigned integer.
*/
fn from_str(buf: str, radix: u64) -> u64 {
if str::byte_len(buf) == 0u {
log_err "parse_buf(): buf is empty";
fail;
}
let i = str::byte_len(buf) - 1u;
let power = 1u64, n = 0u64;
while true {
let digit = char::to_digit(buf[i] as char) as u64;
if digit >= radix { fail; }
n += digit * power;
power *= radix;
if i == 0u { ret n; }
i -= 1u;
}
fail;
}

View file

@ -1,68 +0,0 @@
/*
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:

View file

@ -1,254 +0,0 @@
/*
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:

View file

@ -1,41 +0,0 @@
/*
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); }

View file

@ -1,836 +0,0 @@
/*
Module: vec
*/
import core::option;
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: