diff --git a/doc/Topics.txt b/doc/Topics.txt index 24557eea9f0..32e39f85abc 100644 --- a/doc/Topics.txt +++ b/doc/Topics.txt @@ -145,10 +145,10 @@ Topic Type: Variant Keywords: variant, variants -#Alter Topic Type: Type +Alter Topic Type: Type -# Keywords: -# tag, tags + Keywords: + resource, resources Topic Type: Predicate diff --git a/src/lib/linux_os.rs b/src/lib/linux_os.rs index 0ef636ac5fe..49f029052d6 100644 --- a/src/lib/linux_os.rs +++ b/src/lib/linux_os.rs @@ -1,3 +1,9 @@ +/* +Module: os + +TODO: Restructure and document +*/ + // FIXME Somehow merge stuff duplicated here and macosx_os.rs. Made difficult // by https://github.com/graydon/rust/issues#issue/268 native "cdecl" mod libc = "" { diff --git a/src/lib/math.rs b/src/lib/math.rs index c9a27f0eca9..5f35d0d06d7 100644 --- a/src/lib/math.rs +++ b/src/lib/math.rs @@ -10,15 +10,72 @@ native "llvm" mod llvm { fn atan(n: float) -> float = "atan.f64"; } +/* +Function: sqrt + +Returns the square root +*/ fn sqrt(x: float) -> float { llvm::sqrt(x) } + +/* +Function: sin + +Returns the sine of an angle +*/ fn sin(x: float) -> float { llvm::sin(x) } + +/* +Function: cos + +Returns the cosine of an angle +*/ fn cos(x: float) -> float { llvm::cos(x) } + +/* +Function: tan + +Returns the tangent of an angle +*/ fn tan(x: float) -> float { llvm::tan(x) } + +/* +Function: asin + +Returns the arcsine of an angle +*/ fn asin(x: float) -> float { llvm::asin(x) } + +/* +Function: acos + +Returns the arccosine of an angle +*/ fn acos(x: float) -> float { llvm::acos(x) } + +/* +Function: atan + +Returns the arctangent of an angle +*/ fn atan(x: float) -> float { llvm::atan(x) } +/* +Const: pi + +Archimedes' constant +*/ const pi: float = 3.141592653589793; +/* +Function: min + +Returns the minimum of two values +*/ fn min(x: T, y: T) -> T { x < y ? x : y } + +/* +Function: max + +Returns the maximum of two values +*/ fn max(x: T, y: T) -> T { x < y ? y : x } diff --git a/src/lib/net.rs b/src/lib/net.rs index c7c042a54a9..5ee7cfa602c 100644 --- a/src/lib/net.rs +++ b/src/lib/net.rs @@ -1,8 +1,33 @@ +/* +Module: net +*/ + import vec; import uint; -tag ip_addr { ipv4(u8, u8, u8, u8); } +/* 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 to a str +*/ fn format_addr(ip: ip_addr) -> str { alt ip { ipv4(a, b, c, d) { @@ -12,6 +37,17 @@ fn format_addr(ip: ip_addr) -> str { } } +/* +Function: parse_addr + +Convert a str to + +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"; } diff --git a/src/lib/posix_fs.rs b/src/lib/posix_fs.rs index b1e08538aca..2980113b6c8 100644 --- a/src/lib/posix_fs.rs +++ b/src/lib/posix_fs.rs @@ -1,4 +1,3 @@ - native "c-stack-cdecl" mod rustrt { fn rust_list_files(path: str) -> [str]; } diff --git a/src/lib/ptr.rs b/src/lib/ptr.rs index 8d730732c3c..35644ab840b 100644 --- a/src/lib/ptr.rs +++ b/src/lib/ptr.rs @@ -1,13 +1,32 @@ -// Unsafe pointer utility functions. +/* +Module: ptr +Unsafe pointer utility functions +*/ native "rust-intrinsic" mod rusti { fn addr_of(val: T) -> *mutable T; fn ptr_offset(ptr: *T, count: uint) -> *T; } +/* +Function: addr_of + +Get an unsafe pointer to a value +*/ fn addr_of(val: T) -> *mutable T { ret rusti::addr_of(val); } + +/* +Function: offset + +Calculate the offset from a pointer +*/ fn offset(ptr: *T, count: uint) -> *T { ret rusti::ptr_offset(ptr, count); } +/* +Function: null + +Create an unsafe null pointer +*/ fn null() -> *T { ret unsafe::reinterpret_cast(0u); } diff --git a/src/lib/rand.rs b/src/lib/rand.rs index 11fda074c1c..df265a0c7ef 100644 --- a/src/lib/rand.rs +++ b/src/lib/rand.rs @@ -1,9 +1,8 @@ +/* +Module: rand - - -/** - * Bindings the runtime's random number generator (ISAAC). - */ +Random number generation +*/ native "c-stack-cdecl" mod rustrt { type rctx; fn rand_new() -> rctx; @@ -11,14 +10,38 @@ native "c-stack-cdecl" mod rustrt { fn rand_free(c: rctx); } -type rng = - obj { - fn next() -> u32; - fn next_float() -> float; - }; +/* 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; +}; 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); } diff --git a/src/lib/run_program.rs b/src/lib/run_program.rs index 3fd590dc9e4..e4913b54184 100644 --- a/src/lib/run_program.rs +++ b/src/lib/run_program.rs @@ -1,4 +1,8 @@ +/* +Module: run +Process spawning +*/ import str::sbuf; export program; @@ -13,6 +17,78 @@ native "c-stack-cdecl" mod rustrt { int; } +/* Section: Types */ + +/* +Resource: program_res + +A resource that manages the destruction of a 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() -> int; + + /* + 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] }); } @@ -20,6 +96,23 @@ fn arg_vec(prog: str, args: [@str]) -> [sbuf] { 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: int, out_fd: int, err_fd: int) -> int unsafe { // Note: we have to hold on to these vector references while we hold a @@ -33,23 +126,42 @@ fn spawn_process(prog: str, args: [str], in_fd: int, out_fd: int, err_fd: int) 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, 0, 0, 0)); } -type program = - obj { - fn get_id() -> int; - fn input() -> io::writer; - fn output() -> io::reader; - fn err() -> io::reader; - fn close_input(); - fn finish() -> int; - fn destroy(); - }; +/* +Function: start_program -resource program_res(p: program) { p.destroy(); } +Spawns a process and returns a boxed +The returned value is a boxed resource containing a 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 +*/ fn start_program(prog: str, args: [str]) -> @program_res { let pipe_input = os::pipe(); let pipe_output = os::pipe(); @@ -110,6 +222,22 @@ fn read_all(rd: io::reader) -> str { 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); @@ -119,41 +247,49 @@ fn program_output(prog: str, args: [str]) -> ret {status: pr.finish(), out: out, err: err}; } -/* Returns an exit status */ -#[cfg(target_os = "win32")] -fn waitpid(pid: int) -> int { - os::waitpid(pid) -} +/* +Function: waitpid -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] +Waits for a process to exit and returns the exit code +*/ fn waitpid(pid: int) -> int { - #[cfg(target_os = "linux")] - fn WIFEXITED(status: int) -> bool { - (status & 0xff) == 0 - } + ret waitpid_os(pid); - #[cfg(target_os = "macos")] - fn WIFEXITED(status: int) -> bool { - (status & 0x7f) == 0 + #[cfg(target_os = "win32")] + fn waitpid_os(pid: int) -> int { + os::waitpid(pid) } #[cfg(target_os = "linux")] - fn WEXITSTATUS(status: int) -> int { - (status >> 8) & 0xff - } - #[cfg(target_os = "macos")] - fn WEXITSTATUS(status: int) -> int { - status >> 8 - } + fn waitpid_os(pid: int) -> int { + #[cfg(target_os = "linux")] + fn WIFEXITED(status: int) -> bool { + (status & 0xff) == 0 + } - let status = os::waitpid(pid); - ret if WIFEXITED(status) { - WEXITSTATUS(status) - } else { - 1 - }; + #[cfg(target_os = "macos")] + fn WIFEXITED(status: int) -> bool { + (status & 0x7f) == 0 + } + + #[cfg(target_os = "linux")] + fn WEXITSTATUS(status: int) -> int { + (status >> 8) & 0xff + } + + #[cfg(target_os = "macos")] + fn WEXITSTATUS(status: int) -> int { + status >> 8 + } + + let status = os::waitpid(pid); + ret if WIFEXITED(status) { + WEXITSTATUS(status) + } else { + 1 + }; + } } // Local Variables: diff --git a/src/lib/sha1.rs b/src/lib/sha1.rs index 313ec407e26..323f37f4a4a 100644 --- a/src/lib/sha1.rs +++ b/src/lib/sha1.rs @@ -1,3 +1,19 @@ +/* +Module: sha1 + +An implementation of the SHA-1 cryptographic hash. + +First create a object using the constructor, then +feed it input using the or methods, which may be +called any number of times. + +After the entire input has been fed to the hash read the result using +the or methods. + +The object may be reused to create multiple hashes by calling +the method. +*/ + /* * A SHA-1 implementation derived from Paul E. Jones's reference * implementation, which is written for clarity, not speed. At some @@ -6,22 +22,49 @@ export sha1; export mk_sha1; -type sha1 = - // Provide message input as bytes - // Provide message input as string - // Read the digest as a vector of 20 bytes. After calling this no further - // input may provided until reset is called - // Same as above, just a hex-string version. - // Reset the sha1 state for reuse. This is called - // automatically during construction - obj { - fn input([u8]); - fn input_str(str); - fn result() -> [u8]; - fn result_str() -> str; - fn reset(); - }; +/* 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; @@ -33,7 +76,11 @@ const k2: u32 = 0x8F1BBCDCu32; const k3: u32 = 0xCA62C1D6u32; -// Builds a sha1 object +/* +Function: mk_sha1 + +Construct a object +*/ fn mk_sha1() -> sha1 { type sha1state = {h: [mutable u32], diff --git a/src/lib/smallintmap.rs b/src/lib/smallintmap.rs index b70c03ad1d5..f9e59820294 100644 --- a/src/lib/smallintmap.rs +++ b/src/lib/smallintmap.rs @@ -1,27 +1,58 @@ +/* +Module: smallintmap - -/// A simple map based on a vector for small integer keys. Space requirements -/// are O(highest integer key). +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 = @{mutable v: [mutable option::t]}; +/* +Function: mk + +Create a smallintmap +*/ fn mk() -> smallintmap { let v: [mutable option::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(m: smallintmap, key: uint, val: T) { vec::grow_set::>(m.v, key, none::, some::(val)); } +/* +Function: find + +Get the value for the specified key. If the key does not exist +in the map then returns none. +*/ fn find(m: smallintmap, key: uint) -> option::t { if key < vec::len::>(m.v) { ret m.v[key]; } ret none::; } +/* +Method: get + +Get the value for the specified key + +Failure: + +If the key does not exist in the map +*/ fn get(m: smallintmap, key: uint) -> T { alt find::(m, key) { none::. { log_err "smallintmap::get(): key not present"; fail; } @@ -29,10 +60,17 @@ fn get(m: smallintmap, key: uint) -> T { } } +/* +Method: contains_key + +Returns true if the map contains a value for the specified key +*/ fn contains_key(m: smallintmap, key: uint) -> bool { ret !option::is_none(find::(m, key)); } +// FIXME: Are these really useful? + fn truncate(m: smallintmap, len: uint) { m.v = vec::slice_mut::>(m.v, 0u, len); } diff --git a/src/lib/sort.rs b/src/lib/sort.rs index a70505e4847..6d4ead4c429 100644 --- a/src/lib/sort.rs +++ b/src/lib/sort.rs @@ -1,12 +1,25 @@ +/* +Module: sort +Sorting methods +*/ import vec::{len, slice}; export merge_sort; export quick_sort; export quick_sort3; +/* Type: lteq */ type lteq = 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(le: lteq, v: [T]) -> [T] { fn merge(le: lteq, a: [T], b: [T]) -> [T] { let rs: [T] = []; @@ -68,16 +81,19 @@ fn qsort(compare_func: lteq, arr: [mutable T], left: uint, } } +/* +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(compare_func: lteq, arr: [mutable T]) { if len::(arr) == 0u { ret; } qsort::(compare_func, arr, 0u, len::(arr) - 1u); } - -// Based on algorithm presented by Sedgewick and Bentley here: -// 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' fn qsort3(compare_func_lt: lteq, compare_func_eq: lteq, arr: [mutable T], left: int, right: int) { if right <= left { ret; } @@ -126,6 +142,19 @@ fn qsort3(compare_func_lt: lteq, compare_func_eq: lteq, qsort3::(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 +. +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(compare_func_lt: lteq, compare_func_eq: lteq, arr: [mutable T]) { if len::(arr) == 0u { ret; } diff --git a/src/lib/str.rs b/src/lib/str.rs index af401664000..1b759ffb8cf 100644 --- a/src/lib/str.rs +++ b/src/lib/str.rs @@ -1,3 +1,9 @@ +/* +Module: str + +String manipulation. +*/ + export eq, lteq, hash, is_empty, is_not_empty, is_whitespace, byte_len, index, rindex, find, starts_with, ends_with, substr, slice, split, concat, connect, to_upper, replace, char_slice, trim_left, trim_right, trim, @@ -11,10 +17,25 @@ native "c-stack-cdecl" 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. @@ -38,6 +59,11 @@ 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::(v); @@ -55,28 +81,52 @@ fn is_utf8(v: [u8]) -> bool { 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; } -/// Returns true if the string has length 0 +/* +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; } -/// Returns true if the string has length greater than 0 +/* +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 { let v: [u8] = unsafe::reinterpret_cast(s); let vlen = vec::len(v); @@ -86,6 +136,11 @@ fn byte_len(s: str) -> uint { ret vlen - 1u; } +/* +Function: bytes + +Converts a string to a vector of bytes +*/ fn bytes(s: str) -> [u8] { let v = unsafe::reinterpret_cast(s); let vcopy = vec::slice(v, 0u, vec::len(v) - 1u); @@ -93,6 +148,12 @@ fn bytes(s: str) -> [u8] { 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: [mutable? u8]) -> str { let vcopy: [u8] = v + [0u8]; let scopy: str = unsafe::reinterpret_cast(vcopy); @@ -100,6 +161,12 @@ fn unsafe_from_bytes(v: [mutable? u8]) -> str { 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) { @@ -131,18 +198,33 @@ fn push_utf8_bytes(&s: str, ch: char) { 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; } @@ -157,6 +239,37 @@ fn utf8_char_width(b: u8) -> uint { 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); @@ -179,8 +292,18 @@ fn char_range_at(s: str, i: uint) -> {ch: char, next: uint} { 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: char_len + +Count the number of unicode characters in a string +*/ fn char_len(s: str) -> uint { let i = 0u; let len = 0u; @@ -195,6 +318,11 @@ fn char_len(s: str) -> uint { 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; @@ -207,8 +335,22 @@ fn to_chars(s: str) -> [char] { 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; } @@ -218,26 +360,67 @@ fn pop_char(&s: str) -> char { 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; @@ -255,10 +438,30 @@ fn find(haystack: str, needle: str) -> int { 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); @@ -267,6 +470,14 @@ fn starts_with(haystack: str, needle: str) -> bool { 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); @@ -280,10 +491,35 @@ fn ends_with(haystack: str, needle: str) -> bool { }; } +/* +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 { // FIXME: Typestate precondition assert (begin <= end); @@ -298,12 +534,22 @@ fn slice(s: str, begin: uint, end: uint) -> str { 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); @@ -312,6 +558,13 @@ fn shift_byte(&s: str) -> u8 { 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); @@ -320,12 +573,35 @@ fn pop_byte(&s: str) -> u8 { 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 = ""; @@ -341,12 +617,22 @@ fn split(s: str, sep: u8) -> [str] { 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; @@ -358,6 +644,11 @@ fn connect(v: [str], sep: str) -> str { } // 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; @@ -374,6 +665,21 @@ fn to_upper(s: str) -> str { } // 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)); @@ -388,10 +694,27 @@ fn replace(s: str, from: str, to: str) : is_not_empty(from) -> str { } // 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; @@ -406,6 +729,11 @@ fn trim_left(s: str) -> str { 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); @@ -420,8 +748,18 @@ fn trim_right(s: str) -> str { 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 @@ -433,10 +771,26 @@ unsafe fn buf(s: str) -> sbuf { 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(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; diff --git a/src/lib/sys.rs b/src/lib/sys.rs index 5c1a6044082..874694d37c5 100644 --- a/src/lib/sys.rs +++ b/src/lib/sys.rs @@ -1,7 +1,8 @@ +/* +Module: sys -//export rustrt; -//export size_of; - +Misc low level stuff +*/ tag type_desc { type_desc(@type_desc); } @@ -22,30 +23,63 @@ native "rust-intrinsic" mod rusti { fn get_type_desc() -> *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() -> *type_desc { ret rusti::get_type_desc::(); } +/* +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() -> uint { ret rustrt::size_of(get_type_desc::()); } +/* +Function: align_of + +Returns the alignment of a type +*/ fn align_of() -> uint { ret rustrt::align_of(get_type_desc::()); } +/* +Function: refcount + +Returns the refcount of a shared box +*/ fn refcount(t: @T) -> uint { ret rustrt::refcount::(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(); }