diff --git a/configure b/configure index 7158a832e09b..a27aa9b7ecc0 100755 --- a/configure +++ b/configure @@ -387,7 +387,8 @@ rm -f config.mk.bak step_msg "making directories" for i in \ - doc \ + doc doc/std \ + nd nd/std \ rt rt/isaac rt/bigint rt/sync rt/test rt/arch/i386 \ rt/libuv rt/libuv/src/ares rt/libuv/src/eio rt/libuv/src/ev \ rustllvm dl \ diff --git a/doc/Languages.txt b/doc/Languages.txt new file mode 100644 index 000000000000..b1453d4488bf --- /dev/null +++ b/doc/Languages.txt @@ -0,0 +1,124 @@ +Format: 1.51 + +# This is the Natural Docs languages file for this project. If you change +# anything here, it will apply to THIS PROJECT ONLY. If you'd like to change +# something for all your projects, edit the Languages.txt in Natural Docs' +# Config directory instead. + + +# You can prevent certain file extensions from being scanned like this: +# Ignore Extensions: [extension] [extension] ... + + +#------------------------------------------------------------------------------- +# SYNTAX: +# +# Unlike other Natural Docs configuration files, in this file all comments +# MUST be alone on a line. Some languages deal with the # character, so you +# cannot put comments on the same line as content. +# +# Also, all lists are separated with spaces, not commas, again because some +# languages may need to use them. +# +# Language: [name] +# Alter Language: [name] +# Defines a new language or alters an existing one. Its name can use any +# characters. If any of the properties below have an add/replace form, you +# must use that when using Alter Language. +# +# The language Shebang Script is special. It's entry is only used for +# extensions, and files with those extensions have their shebang (#!) lines +# read to determine the real language of the file. Extensionless files are +# always treated this way. +# +# The language Text File is also special. It's treated as one big comment +# so you can put Natural Docs content in them without special symbols. Also, +# if you don't specify a package separator, ignored prefixes, or enum value +# behavior, it will copy those settings from the language that is used most +# in the source tree. +# +# Extensions: [extension] [extension] ... +# [Add/Replace] Extensions: [extension] [extension] ... +# Defines the file extensions of the language's source files. You can +# redefine extensions found in the main languages file. You can use * to +# mean any undefined extension. +# +# Shebang Strings: [string] [string] ... +# [Add/Replace] Shebang Strings: [string] [string] ... +# Defines a list of strings that can appear in the shebang (#!) line to +# designate that it's part of the language. You can redefine strings found +# in the main languages file. +# +# Ignore Prefixes in Index: [prefix] [prefix] ... +# [Add/Replace] Ignored Prefixes in Index: [prefix] [prefix] ... +# +# Ignore [Topic Type] Prefixes in Index: [prefix] [prefix] ... +# [Add/Replace] Ignored [Topic Type] Prefixes in Index: [prefix] [prefix] ... +# Specifies prefixes that should be ignored when sorting symbols in an +# index. Can be specified in general or for a specific topic type. +# +#------------------------------------------------------------------------------ +# For basic language support only: +# +# Line Comments: [symbol] [symbol] ... +# Defines a space-separated list of symbols that are used for line comments, +# if any. +# +# Block Comments: [opening sym] [closing sym] [opening sym] [closing sym] ... +# Defines a space-separated list of symbol pairs that are used for block +# comments, if any. +# +# Package Separator: [symbol] +# Defines the default package separator symbol. The default is a dot. +# +# [Topic Type] Prototype Enders: [symbol] [symbol] ... +# When defined, Natural Docs will attempt to get a prototype from the code +# immediately following the topic type. It stops when it reaches one of +# these symbols. Use \n for line breaks. +# +# Line Extender: [symbol] +# Defines the symbol that allows a prototype to span multiple lines if +# normally a line break would end it. +# +# Enum Values: [global|under type|under parent] +# Defines how enum values are referenced. The default is global. +# global - Values are always global, referenced as 'value'. +# under type - Values are under the enum type, referenced as +# 'package.enum.value'. +# under parent - Values are under the enum's parent, referenced as +# 'package.value'. +# +# Perl Package: [perl package] +# Specifies the Perl package used to fine-tune the language behavior in ways +# too complex to do in this file. +# +#------------------------------------------------------------------------------ +# For full language support only: +# +# Full Language Support: [perl package] +# Specifies the Perl package that has the parsing routines necessary for full +# language support. +# +#------------------------------------------------------------------------------- + +# The following languages are defined in the main file, if you'd like to alter +# them: +# +# Text File, Shebang Script, C/C++, C#, Java, JavaScript, Perl, Python, +# PHP, SQL, Visual Basic, Pascal, Assembly, Ada, Tcl, Ruby, Makefile, +# ActionScript, ColdFusion, R, Fortran + +# If you add a language that you think would be useful to other developers +# and should be included in Natural Docs by default, please e-mail it to +# languages [at] naturaldocs [dot] org. + + +Language: Rust + + Extensions: rc rs + Line Comment: // + Block Comment: /* */ + Package Separator: :: + Function Prototype Enders: ; { + Type Prototype Enders: ; } + Class Prototype Enders: { diff --git a/doc/Topics.txt b/doc/Topics.txt new file mode 100644 index 000000000000..24557eea9f0c --- /dev/null +++ b/doc/Topics.txt @@ -0,0 +1,159 @@ +Format: 1.51 + +# This is the Natural Docs topics file for this project. If you change anything +# here, it will apply to THIS PROJECT ONLY. If you'd like to change something +# for all your projects, edit the Topics.txt in Natural Docs' Config directory +# instead. + + +# If you'd like to prevent keywords from being recognized by Natural Docs, you +# can do it like this: +# Ignore Keywords: [keyword], [keyword], ... +# +# Or you can use the list syntax like how they are defined: +# Ignore Keywords: +# [keyword] +# [keyword], [plural keyword] +# ... + + +#------------------------------------------------------------------------------- +# SYNTAX: +# +# Topic Type: [name] +# Alter Topic Type: [name] +# Creates a new topic type or alters one from the main file. Each type gets +# its own index and behavior settings. Its name can have letters, numbers, +# spaces, and these charaters: - / . ' +# +# Plural: [name] +# Sets the plural name of the topic type, if different. +# +# Keywords: +# [keyword] +# [keyword], [plural keyword] +# ... +# Defines or adds to the list of keywords for the topic type. They may only +# contain letters, numbers, and spaces and are not case sensitive. Plural +# keywords are used for list topics. You can redefine keywords found in the +# main topics file. +# +# Index: [yes|no] +# Whether the topics get their own index. Defaults to yes. Everything is +# included in the general index regardless of this setting. +# +# Scope: [normal|start|end|always global] +# How the topics affects scope. Defaults to normal. +# normal - Topics stay within the current scope. +# start - Topics start a new scope for all the topics beneath it, +# like class topics. +# end - Topics reset the scope back to global for all the topics +# beneath it. +# always global - Topics are defined as global, but do not change the scope +# for any other topics. +# +# Class Hierarchy: [yes|no] +# Whether the topics are part of the class hierarchy. Defaults to no. +# +# Page Title If First: [yes|no] +# Whether the topic's title becomes the page title if it's the first one in +# a file. Defaults to no. +# +# Break Lists: [yes|no] +# Whether list topics should be broken into individual topics in the output. +# Defaults to no. +# +# Can Group With: [type], [type], ... +# Defines a list of topic types that this one can possibly be grouped with. +# Defaults to none. +#------------------------------------------------------------------------------- + +# The following topics are defined in the main file, if you'd like to alter +# their behavior or add keywords: +# +# Generic, Class, Interface, Section, File, Group, Function, Variable, +# Property, Type, Constant, Enumeration, Event, Delegate, Macro, +# Database, Database Table, Database View, Database Index, Database +# Cursor, Database Trigger, Cookie, Build Target + +# If you add something that you think would be useful to other developers +# and should be included in Natural Docs by default, please e-mail it to +# topics [at] naturaldocs [dot] org. + + +#Topic Type: Crate + +# Plural: Crates +# Scope: Always Global + +# Keywords: +# crate, crates + +Topic Type: Syntax Extension + + Plural: Syntax Extensions + Scope: Always Global + + Keywords: + syntax extension, syntax extensions + +#Alter Topic Type: Class + +# Keywords: +# object, objects +# tag, tags +# resource, resources + +Topic Type: Module + Plural: Modules + Scope: Start + Class Hierarchy: Yes + Page Title If First: Yes + + Keywords: + module, modules + +Topic Type: Object + Plural: Objects + Scope: Start + Class Hierarchy: Yes + + Keywords: + obj, objs + +Topic Type: Tag + Plural: Tags + Scope: Start + Class Hierarchy: Yes + + Keywords: + tag, tags + +#Alter Topic Type: Function + +# Scope: Start +# predicate, predicates + +# Ignore Keywords: +# method, methods +# Keywords: +# variant, variants + +Topic Type: Variant + + Plural: Variants + Keywords: + variant, variants + +#Alter Topic Type: Type + +# Keywords: +# tag, tags + +Topic Type: Predicate + + Plural: Predicates + Break Lists: Yes + + Keywords: + predicate, predicates diff --git a/mk/docs.mk b/mk/docs.mk index bab8bf4f6ec1..72e549bec28f 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -19,3 +19,16 @@ doc/%.html: %.texi doc/version.texi docsnap: doc/rust.pdf @$(call E, snap: doc/rust-$(shell date +"%Y-%m-%d")-snap.pdf) $(Q)mv $< doc/rust-$(shell date +"%Y-%m-%d")-snap.pdf + +doc/std/index.html: nd/std/Languages.txt nd/std/Topics.txt \ + $(STDLIB_CRATE) $(STDLIB_INPUTS) + @$(call E, naturaldocs: $@) + naturaldocs -i $(S)src/lib -o HTML doc/std -p nd/std -r + +nd/std/Languages.txt: $(S)doc/Languages.txt + @$(call E, cp: $@) + $(Q)cp $< $@ + +nd/std/Topics.txt: $(S)doc/Topics.txt + @$(call E, cp: $@) + $(Q)cp $< $@ diff --git a/src/lib/bitv.rs b/src/lib/bitv.rs index 4bbd4118d323..023450ec97b0 100644 --- a/src/lib/bitv.rs +++ b/src/lib/bitv.rs @@ -1,3 +1,8 @@ +/* +Module: bitv + +Bitvectors. +*/ export t; export create; @@ -23,12 +28,26 @@ export eq_vec; // an optimizing version of this module that produces a different obj // for the case where nbits <= 32. +/* +Type: t + +The bitvector type. +*/ type t = @{storage: [mutable uint], nbits: uint}; // FIXME: this should be a constant once they work fn uint_bits() -> uint { ret 32u + (1u << 32u >> 27u); } +/* +Function: create + +Constructs a bitvector. + +Parameters: +nbits - The number of bits in the bitvector +init - If true then the bits are initialized to 1, otherwise 0 +*/ fn create(nbits: uint, init: bool) -> t { let elt = if init { !0u } else { 0u }; let storage = vec::init_elt_mut::(elt, nbits / uint_bits() + 1u); diff --git a/src/lib/box.rs b/src/lib/box.rs index a4322c09be92..821a8428d2c9 100644 --- a/src/lib/box.rs +++ b/src/lib/box.rs @@ -1,6 +1,15 @@ +/* +Module: box +*/ + export ptr_eq; +/* +Function: ptr_eq + +Determine if two shared boxes point to the same object +*/ fn ptr_eq(a: @T, b: @T) -> bool { let a_ptr: uint = unsafe::reinterpret_cast(a); let b_ptr: uint = unsafe::reinterpret_cast(b); diff --git a/src/lib/char.rs b/src/lib/char.rs index cbd8f667b860..e91e8697dd86 100644 --- a/src/lib/char.rs +++ b/src/lib/char.rs @@ -1,3 +1,18 @@ +/* +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'; diff --git a/src/lib/comm.rs b/src/lib/comm.rs index dbf7bb3df102..dca101b4e59a 100644 --- a/src/lib/comm.rs +++ b/src/lib/comm.rs @@ -1,3 +1,26 @@ +/* +Module: comm + +Communication between tasks + +Communication between tasks is facilitated by ports (in the receiving task), +and channels (in the sending task). Any number of channels may feed into a +single port. + +Example: + +> use std::task; +> use std::comm; +> +> let p = comm::port(); +> task::spawn(comm::chan(p), fn (c: chan) { +> comm::send(c, "Hello, World"); +> }); +> +> log comm::recv(p); + +*/ + import sys; import ptr; import unsafe; @@ -30,31 +53,66 @@ type port_id = int; // It's critical that this only have one variant, so it has a record // layout, and will work in the rust_task structure in task.rs. -tag chan { chan_t(task::task, port_id); } +/* +Type: chan + +A handle through which data may be sent. + +Each channel is associated with a single . +*/ +tag chan { + chan_t(task::task, port_id); +} resource port_ptr(po: *rustrt::rust_port) { rustrt::drop_port(po); rustrt::del_port(po); } +/* +Type: port + +A handle through which data may be received. + +Ports may be associated with multiple s. +*/ tag port { port_t(@port_ptr); } +/* +Function: send + +Sends data over a channel. + +The sent data is moved into the channel, whereupon the caller loses access +to it. +*/ fn send(ch: chan, -data: T) { let chan_t(t, p) = ch; rustrt::chan_id_send(sys::get_type_desc::(), t, p, data); task::yield(); } +/* +Function: port + +Constructs a port. +*/ fn port() -> port { - let p = rustrt::new_port(sys::size_of::()); - ret port_t(@port_ptr(p)); + port_t(@port_ptr(rustrt::new_port(sys::size_of::()))) } -fn recv(p: port) -> T { - ret rusti::recv(***p); -} +/* +Function: recv +Receive from a port. +*/ +fn recv(p: port) -> T { ret rusti::recv(***p) } + +/* +Function: chan + +Constructs a channel. +*/ fn chan(p: port) -> chan { - let id = rustrt::get_port_id(***p); - ret chan_t(task::get_task_id(), id); + chan_t(task::get_task_id(), rustrt::get_port_id(***p)) } diff --git a/src/lib/ctypes.rs b/src/lib/ctypes.rs index 7e876ed76026..5f4c999126e1 100644 --- a/src/lib/ctypes.rs +++ b/src/lib/ctypes.rs @@ -1,5 +1,12 @@ -// FIXME: This can't be right -type size_t = uint; -type ssize_t = int; +/* +Module: ctypes +Definitions useful for C interop +*/ + +/* Type: size_t */ +type size_t = uint; +/* Type: ssize_t */ +type ssize_t = int; +/* Type: uint32_t */ type uint32_t = u32; diff --git a/src/lib/deque.rs b/src/lib/deque.rs index 24aa95bfc28e..213003e52644 100644 --- a/src/lib/deque.rs +++ b/src/lib/deque.rs @@ -1,21 +1,38 @@ +/* +Module: deque +A deque. Untested as of yet. Likely buggy. +*/ - -/** - * A deque, for fun. Untested as of yet. Likely buggy. - */ -type t = - obj { - fn size() -> uint; - fn add_front(T); - fn add_back(T); - fn pop_front() -> T; - fn pop_back() -> T; - fn peek_front() -> T; - fn peek_back() -> T; - fn get(int) -> T; +/* +Object: t +*/ +type t = obj { + // Method: size + fn size() -> uint; + // Method: add_front + fn add_front(T); + // Method: add_back + fn add_back(T); + // Method: pop_front + fn pop_front() -> T; + // Method: pop_back + fn pop_back() -> T; + // Method: peek_front + fn peek_front() -> T; + // Method: peek_back + fn peek_back() -> T; + // Method: get + fn get(int) -> T; }; +/* +Section: Functions +*/ + +/* +Function: create +*/ fn create() -> t { type cell = option::t; diff --git a/src/lib/either.rs b/src/lib/either.rs index 143f0cabe92d..a67741445996 100644 --- a/src/lib/either.rs +++ b/src/lib/either.rs @@ -1,15 +1,46 @@ +/* +Module: either + +A type that represents one of two alternatives +*/ import option; import option::{some, none}; -tag t { left(T); right(U); } +/* +Tag: t +The either type +*/ +tag t { + /* 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(f_left: block(T) -> V, f_right: block(U) -> V, value: t) -> 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(eithers: [t]) -> [T] { let result: [T] = []; for elt: t in eithers { @@ -18,6 +49,11 @@ fn lefts(eithers: [t]) -> [T] { ret result; } +/* +Function: rights + +Extracts from a vector of either all the right values +*/ fn rights(eithers: [t]) -> [U] { let result: [U] = []; for elt: t in eithers { @@ -26,6 +62,14 @@ fn rights(eithers: [t]) -> [U] { 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(eithers: [t]) -> {lefts: [T], rights: [U]} { let lefts: [T] = []; let rights: [U] = []; @@ -34,6 +78,7 @@ fn partition(eithers: [t]) -> {lefts: [T], rights: [U]} { } ret {lefts: lefts, rights: rights}; } + // // Local Variables: // mode: rust diff --git a/src/lib/extfmt.rs b/src/lib/extfmt.rs index 3f43707cc1b6..b6d04397711d 100644 --- a/src/lib/extfmt.rs +++ b/src/lib/extfmt.rs @@ -1,19 +1,28 @@ +/* +Syntax Extension: fmt +Format a string + +The 'fmt' extension is modeled on the posix printf system. + +A posix conversion ostensibly looks like this + +> %[parameter][flags][width][.precision][length]type + +Given the different numeric type bestiary we have, we omit the 'length' +parameter and support slightly different conversions for 'type' + +> %[parameter][flags][width][.precision]type + +we also only support translating-to-rust a tiny subset of the possible +combinations at the moment. + +Example: + +log #fmt("hello, %s!", "world"); + +*/ -/* The 'fmt' extension is modeled on the posix printf system. - * - * A posix conversion ostensibly looks like this: - * - * %[parameter][flags][width][.precision][length]type - * - * Given the different numeric type bestiary we have, we omit the 'length' - * parameter and support slightly different conversions for 'type': - * - * %[parameter][flags][width][.precision]type - * - * we also only support translating-to-rust a tiny subset of the possible - * combinations at the moment. - */ import option::{some, none}; diff --git a/src/lib/float.rs b/src/lib/float.rs index 1d444b3111af..04960c193b33 100644 --- a/src/lib/float.rs +++ b/src/lib/float.rs @@ -1,7 +1,21 @@ +/* +Module: float +*/ + /** - * String conversions + * Section: String Conversions */ +/* +Function: to_str + +Converts a float to a string + +Parameters: + +num - The float value +digits: The number of significant digits +*/ fn to_str(num: float, digits: uint) -> str { let accum = if num < 0.0 { num = -num; "-" } else { "" }; let trunc = num as uint; @@ -19,23 +33,30 @@ fn to_str(num: float, digits: uint) -> str { ret accum; } -/** - * 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" - * - * @param num A string, possibly empty. - * @return [NaN] if the string did not represent a valid number. - * @return Otherwise, the floating-point number represented [num]. - */ +/* +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" + +Parameters: + +num - A string, possibly empty. + +Returns: + + If the string did not represent a valid number. +Otherwise, the floating-point number represented [num]. +*/ fn from_str(num: str) -> float { let pos = 0u; //Current byte position in the string. //Used to walk the string in O(n). @@ -144,17 +165,21 @@ fn from_str(num: str) -> float { } /** - * Arithmetics + * Section: Arithmetics */ -/** - * Compute the exponentiation of an integer by another integer as a float. - * - * - * @param x The base. - * @param pow The exponent. - * @return [NaN] of both [x] and [pow] are [0u], otherwise [x^pow]. - */ +/* +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: + 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 { @@ -177,20 +202,23 @@ fn pow_uint_to_uint_as_float(x: uint, pow: uint) -> float { /** - * Constants + * Section: Constants */ //TODO: Once this is possible, replace the body of these functions //by an actual constant. +/* Function: NaN */ fn NaN() -> float { ret 0./0.; } +/* Function: infinity */ fn infinity() -> float { ret 1./0.; } +/* Function: neg_infinity */ fn neg_infinity() -> float { ret -1./0.; } diff --git a/src/lib/fs.rs b/src/lib/fs.rs index 9a539f4b826d..5787e9c510c3 100644 --- a/src/lib/fs.rs +++ b/src/lib/fs.rs @@ -1,3 +1,8 @@ +/* +Module: fs + +File system manipulation +*/ import os::getcwd; import os_fs; @@ -6,10 +11,32 @@ native "c-stack-cdecl" mod rustrt { fn rust_file_is_dir(path: str::sbuf) -> int; } +/* +Function: path_sep + +Get the default path separator for the host platform +*/ fn path_sep() -> str { ret str::from_char(os_fs::path_sep); } +// FIXME: This type should probably be constrained +/* +Type: path + +A path or fragment of a filesystem path +*/ type path = str; +/* +Function: dirname + +Get the directory portion of a path + +Returns all of the path up to, but excluding, the final path separator. +The dirname of "/usr/share" will be "/usr", but the dirname of +"/usr/share/" is "/usr/share". + +If the path is not prefixed with a directory, then "." is returned. +*/ fn dirname(p: path) -> path { let i: int = str::rindex(p, os_fs::path_sep as u8); if i == -1 { @@ -19,6 +46,17 @@ fn dirname(p: path) -> path { ret str::substr(p, 0u, i as uint); } +/* +Function: basename + +Get the file name portion of a path + +Returns the portion of the path after the final path separator. +The basename of "/usr/share" will be "share". If there are no +path separators in the path then the returned path is identical to +the provided path. If an empty path is provided or the path ends +with a path separator then an empty path is returned. +*/ fn basename(p: path) -> path { let i: int = str::rindex(p, os_fs::path_sep as u8); if i == -1 { @@ -32,6 +70,15 @@ fn basename(p: path) -> path { // FIXME: Need some typestate to avoid bounds check when len(pre) == 0 +/* +Function: connect + +Connects to path segments + +Given paths `pre` and `post` this function will return a path +that is equal to `post` appended to `pre`, inserting a path separator +between the two as needed. +*/ fn connect(pre: path, post: path) -> path { let len = str::byte_len(pre); ret if pre[len - 1u] == os_fs::path_sep as u8 { @@ -41,6 +88,13 @@ fn connect(pre: path, post: path) -> path { } else { pre + path_sep() + post }; } +/* +Function: connect_many + +Connects a vector of path segments into a single path. + +Inserts path separators as needed. +*/ fn connect_many(paths: [path]) : vec::is_not_empty(paths) -> path { ret if vec::len(paths) == 1u { paths[0] @@ -51,10 +105,20 @@ fn connect_many(paths: [path]) : vec::is_not_empty(paths) -> path { } } +/* +Function: file_id_dir + +Indicates whether a path represents a directory. +*/ fn file_is_dir(p: path) -> bool { ret str::as_buf(p, {|buf| rustrt::rust_file_is_dir(buf) != 0 }); } +/* +Function: list_dir + +Lists the contents of a directory. +*/ fn list_dir(p: path) -> [str] { let p = p; let pl = str::byte_len(p); @@ -68,14 +132,41 @@ fn list_dir(p: path) -> [str] { ret full_paths; } +/* +Function: path_is_absolute + +Indicates whether a path is absolute. + +A path is considered absolute if it begins at the filesystem root ("/") or, +on Windows, begins with a drive letter. +*/ fn path_is_absolute(p: path) -> bool { ret os_fs::path_is_absolute(p); } // FIXME: under Windows, we should prepend the current drive letter to paths // that start with a slash. +/* +Function: make_absolute + +Convert a relative path to an absolute path + +If the given path is relative, return it prepended with the current working +directory. If the given path is already an absolute path, return it +as is. +*/ fn make_absolute(p: path) -> path { if path_is_absolute(p) { ret p; } else { ret connect(getcwd(), p); } } +/* +Function: split + +Split a path into it's individual components + +Splits a given path by path separators and returns a vector containing +each piece of the path. On Windows, if the path is absolute then +the first element of the returned vector will be the drive letter +followed by a colon. +*/ fn split(p: path) -> [path] { let split1 = str::split(p, os_fs::path_sep as u8); let split2 = []; @@ -85,6 +176,13 @@ fn split(p: path) -> [path] { ret split2; } +/* +Function: normalize + +Removes extra "." and ".." entries from paths. + +Does not follow symbolic links. +*/ fn normalize(p: path) -> path { let s = split(p); let s = strip_dots(s); diff --git a/src/lib/fun_treemap.rs b/src/lib/fun_treemap.rs index 4a65d6191de5..4e0aea3f3192 100644 --- a/src/lib/fun_treemap.rs +++ b/src/lib/fun_treemap.rs @@ -1,4 +1,6 @@ /* +Module: fun_treemap + A functional key,value store that works on anything. This works using a binary search tree. In the first version, it's a @@ -19,15 +21,35 @@ export insert; export find; export traverse; +/* Section: Types */ + +/* +Type: treemap +*/ +type treemap = @tree_node; + +/* +Tag: tree_node +*/ tag tree_node { empty; node(@K, @V, @tree_node, @tree_node); } -type treemap = @tree_node; +/* Section: Operations */ +/* +Function: init + +Create a treemap +*/ fn init() -> treemap { @empty } +/* +Function: insert + +Insert a value into the map +*/ fn insert(m: treemap, k: K, v: V) -> treemap { @alt m { @empty. { node(@k, @v, @empty, @empty) } @@ -41,6 +63,11 @@ fn insert(m: treemap, k: K, v: V) -> treemap { } } +/* +Function: find + +Find a value based on the key +*/ fn find(m: treemap, k: K) -> option { alt *m { empty. { none } @@ -52,8 +79,11 @@ fn find(m: treemap, k: K) -> option { } } +/* +Function: traverse -// Performs an in-order traversal +Visit all pairs in the map in order. +*/ fn traverse(m: treemap, f: fn(K, V)) { alt *m { empty. { } diff --git a/src/lib/generic_os.rs b/src/lib/generic_os.rs index bb98c0731f81..ebb157c621cd 100644 --- a/src/lib/generic_os.rs +++ b/src/lib/generic_os.rs @@ -1,5 +1,30 @@ +/* +Module: generic_os + +Some miscellaneous platform functions. + +These should be rolled into another module. +*/ + import str::sbuf; +// Wow, this is an ugly way to write doc comments + +#[cfg(bogus)] +/* +Function: getenv + +Get the value of an environment variable +*/ +fn getenv(n: str) -> option::t { } + +#[cfg(bogus)] +/* +Function: setenv + +Set the value of an environment variable +*/ +fn setenv(n: str, v: str) { } #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] diff --git a/src/lib/getopts.rs b/src/lib/getopts.rs index beae20a0d910..b4f9dee8e722 100644 --- a/src/lib/getopts.rs +++ b/src/lib/getopts.rs @@ -1,13 +1,50 @@ +/* +Module: getopts +Simple getopt alternative. Construct a vector of options, either by using +reqopt, optopt, and optflag or by building them from components yourself, and +pass them to getopts, along with a vector of actual arguments (not including +argv[0]). You'll either get a failure code back, or a match. You'll have to +verify whether the amount of 'free' arguments in the match is what you +expect. Use opt_* accessors to get argument values out of the match object. + +Single-character options are expected to appear on the command line with a +single preceeding dash; multiple-character options are expected to be +proceeded by two dashes. Options that expect an argument accept their argument +following either a space or an equals sign. + +Example: + +The following example shows simple command line parsing for an application +that requires an input file to be specified, accepts an optional output file +name following -o, and accepts both -h and --help as optional flags. + +> fn main(args: [str]) { +> let opts = [ +> optopt("o"), +> optflag("h"), +> optflag("help") +> ]; +> let match = alt getopts(vec::shift(args), opts) { +> success(m) { m } +> failure(f) { fail fail_str(f) } +> }; +> if opt_present(match, "h") || opt_present(match, "help") { +> print_usage(); +> ret; +> } +> let output = opt_maybe_str(match, "o"); +> let input = if !vec::is_empty(match.free) { +> match.free[0] +> } else { +> print_usage(); +> ret; +> } +> do_work(input, output); +> } + +*/ -/* Simple getopt alternative. Construct a vector of options, either by using - * reqopt, optopt, and optflag or by building them from components yourself, - * and pass them to getopts, along with a vector of actual arguments (not - * including argv[0]). You'll either get a failure code back, or a match. - * You'll have to verify whether the amount of 'free' arguments in the match - * is what you expect. Use opt_* accessors (bottom of the file) to get - * argument values out of the match object. - */ import option::{some, none}; export opt; export reqopt; @@ -34,6 +71,11 @@ tag hasarg { yes; no; maybe; } tag occur { req; optional; multi; } +/* +Type: opt + +A description of a possible option +*/ type opt = {name: name, hasarg: hasarg, occur: occur}; fn mkname(nm: str) -> name { @@ -42,28 +84,60 @@ fn mkname(nm: str) -> name { } else { long(nm) }; } +/* +Function: reqopt + +Create an option that is required and takes an argument +*/ fn reqopt(name: str) -> opt { ret {name: mkname(name), hasarg: yes, occur: req}; } +/* +Function: optopt + +Create an option that is optional and takes an argument +*/ fn optopt(name: str) -> opt { ret {name: mkname(name), hasarg: yes, occur: optional}; } +/* +Function: optflag + +Create an option that is optional and does not take an argument +*/ fn optflag(name: str) -> opt { ret {name: mkname(name), hasarg: no, occur: optional}; } +/* +Function: optflagopt + +Create an option that is optional and takes an optional argument +*/ fn optflagopt(name: str) -> opt { ret {name: mkname(name), hasarg: maybe, occur: optional}; } +/* +Function: optmulti + +Create an option that is optional, takes an argument, and may occur +multiple times +*/ fn optmulti(name: str) -> opt { ret {name: mkname(name), hasarg: yes, occur: multi}; } tag optval { val(str); given; } +/* +Type: match + +The result of checking command line arguments. Contains a vector +of matches and a vector of free strings. +*/ type match = {opts: [opt], vals: [mutable [optval]], free: [str]}; fn is_arg(arg: str) -> bool { @@ -81,6 +155,12 @@ fn find_opt(opts: [opt], nm: name) -> option::t { ret none::; } +/* +Type: fail_ + +The type returned when the command line does not conform to the +expected format. Pass this value to to get an error message. +*/ tag fail_ { argument_missing(str); unrecognized_option(str); @@ -89,6 +169,11 @@ tag fail_ { unexpected_argument(str); } +/* +Function: fail_str + +Convert a tag into an error string +*/ fn fail_str(f: fail_) -> str { ret alt f { argument_missing(nm) { "Argument to option '" + nm + "' missing." } @@ -103,8 +188,29 @@ fn fail_str(f: fail_) -> str { }; } +/* +Type: result + +The result of parsing a command line with a set of options + +Variants: + +success(match) - Returned from getopts on success +failure(fail_) - Returned from getopts on failure +*/ tag result { success(match); failure(fail_); } +/* +Function: getopts + +Parse command line arguments according to the provided options + +Returns: + +success(match) - On success. Use functions such as + , etc. to interrogate results. +failure(fail_) - On failure. Use to get an error message. +*/ fn getopts(args: [str], opts: [opt]) -> result { let n_opts = vec::len::(opts); fn f(_x: uint) -> [optval] { ret []; } @@ -208,14 +314,35 @@ fn opt_vals(m: match, nm: str) -> [optval] { fn opt_val(m: match, nm: str) -> optval { ret opt_vals(m, nm)[0]; } +/* +Function: opt_present + +Returns true if an option was matched +*/ fn opt_present(m: match, nm: str) -> bool { ret vec::len::(opt_vals(m, nm)) > 0u; } +/* +Function: opt_str + +Returns the string argument supplied to a matching option + +Failure: + +- If the option was not matched +- If the match did not take an argument +*/ fn opt_str(m: match, nm: str) -> str { ret alt opt_val(m, nm) { val(s) { s } _ { fail } }; } +/* +Function: opt_str + +Returns a vector of the arguments provided to all matches of the given option. +Used when an option accepts multiple values. +*/ fn opt_strs(m: match, nm: str) -> [str] { let acc: [str] = []; for v: optval in opt_vals(m, nm) { @@ -224,6 +351,11 @@ fn opt_strs(m: match, nm: str) -> [str] { ret acc; } +/* +Function: opt_str + +Returns the string argument supplied to a matching option or none +*/ fn opt_maybe_str(m: match, nm: str) -> option::t { let vals = opt_vals(m, nm); if vec::len::(vals) == 0u { ret none::; } @@ -231,9 +363,15 @@ fn opt_maybe_str(m: match, nm: str) -> option::t { } -/// Returns none if the option was not present, `def` if the option was -/// present but no argument was provided, and the argument if the option was -/// present and an argument was provided. +/* +Function: opt_default + +Returns the matching string, a default, or none + +Returns none if the option was not present, `def` if the option was +present but no argument was provided, and the argument if the option was +present and an argument was provided. +*/ fn opt_default(m: match, nm: str, def: str) -> option::t { let vals = opt_vals(m, nm); if vec::len::(vals) == 0u { ret none::; } diff --git a/src/lib/int.rs b/src/lib/int.rs index 7b08b1d8df3d..464ac9deea50 100644 --- a/src/lib/int.rs +++ b/src/lib/int.rs @@ -1,52 +1,105 @@ +/* +Module: int +*/ + +/* +Function: max_value + +The maximum value of an integer +*/ fn max_value() -> int { ret min_value() - 1; } +/* +Function: min_value + +The minumum value of an integer +*/ fn min_value() -> int { ret (-1 << (sys::size_of::() * 8u as int - 1)) as int; } - +/* 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; } +// FIXME: This is redundant fn eq_alias(x: int, y: int) -> bool { ret x == y; } +/* +Function: range + +Iterate over the range [`lo`..`hi`) +*/ fn range(lo: int, hi: int, it: block(int)) { while lo < hi { it(lo); lo += 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::(buf) == 0u { log_err "parse_buf(): buf is empty"; @@ -68,16 +121,41 @@ fn parse_buf(buf: [u8], radix: uint) -> int { 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; } diff --git a/src/lib/io.rs b/src/lib/io.rs index 57ea12d3850f..ab93699f8e53 100644 --- a/src/lib/io.rs +++ b/src/lib/io.rs @@ -1,4 +1,3 @@ - import os::libc; native "c-stack-cdecl" mod rustrt { diff --git a/src/lib/option.rs b/src/lib/option.rs index 50240c3087b4..970349c7d31a 100644 --- a/src/lib/option.rs +++ b/src/lib/option.rs @@ -1,30 +1,85 @@ -// lib/option::rs +/* +Module: option -tag t { none; some(T); } +Represents the presence or absence of a value. +Every option 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 { + /* 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(opt: t) -> &T { alt opt { some(x) { ret x; } none. { fail "option none"; } } } +/* +*/ fn map(f: block(T) -> U, opt: t) -> t { alt opt { some(x) { some(f(x)) } none. { none } } } +/* +Function: is_none + +Returns true if the option equals none +*/ fn is_none(opt: t) -> bool { alt opt { none. { true } some(_) { false } } } +/* +Function: is_some + +Returns true if the option contains some value +*/ fn is_some(opt: t) -> bool { !is_none(opt) } +/* +Function: from_maybe + +Returns the contained value or a default +*/ fn from_maybe(def: T, opt: t) -> T { alt opt { some(x) { x } none. { def } } } +/* +Function: maybe + +Applies a function to the contained value or returns a default +*/ fn maybe(def: U, f: block(T) -> U, opt: t) -> U { alt opt { none. { def } some(t) { f(t) } } } -// Can be defined in terms of the above when/if we have const bind. +// 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(f: block(T), opt: t) { alt opt { none. {/* nothing */ } some(t) { f(t); } } } diff --git a/src/lib/std.rc b/src/lib/std.rc index 89b47685d8a3..7f2539fd4c59 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -1,4 +1,3 @@ - #[link(name = "std", vers = "0.1", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", diff --git a/src/lib/treemap.rs b/src/lib/treemap.rs index a361bd20cdb2..68d732449c65 100644 --- a/src/lib/treemap.rs +++ b/src/lib/treemap.rs @@ -1,4 +1,6 @@ /* +Module: treemap + A key,value store that works on anything. This works using a binary search tree. In the first version, it's a @@ -16,12 +18,32 @@ export insert; export find; export traverse; -tag tree_node { empty; node(@K, @V, treemap, treemap); } +/* Section: Types */ +/* +Type: treemap +*/ type treemap = @mutable tree_node; +/* +Tag: tree_node +*/ +tag tree_node { empty; node(@K, @V, treemap, treemap); } + +/* Section: Operations */ + +/* +Function: init + +Create a treemap +*/ fn init() -> treemap { @mutable empty } +/* +Function: insert + +Insert a value into the map +*/ fn insert(m: treemap, k: K, v: V) { alt m { @empty. { *m = node(@k, @v, @mutable empty, @mutable empty); } @@ -36,6 +58,11 @@ fn insert(m: treemap, k: K, v: V) { } } +/* +Function: find + +Find a value based on the key +*/ fn find(m: treemap, k: K) -> option { alt *m { empty. { none } @@ -51,7 +78,11 @@ fn find(m: treemap, k: K) -> option { } } -// Performs an in-order traversal +/* +Function: traverse + +Visit all pairs in the map in order. +*/ fn traverse(m: treemap, f: fn@(K, V)) { alt *m { empty. { } diff --git a/src/lib/vec.rs b/src/lib/vec.rs index e0184767e9d2..08c8aa52a8a5 100644 --- a/src/lib/vec.rs +++ b/src/lib/vec.rs @@ -1,4 +1,6 @@ -// Interior vector utility functions. +/* +Module: vec +*/ import option::{some, none}; import uint::next_power_of_two; @@ -17,15 +19,40 @@ native "c-stack-cdecl" mod rustrt { count: uint) -> [T]; } -/// Reserves space for `n` elements in the given vector. +/* +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(&v: [mutable? T], n: uint) { rustrt::vec_reserve_shared(sys::get_type_desc::(), v, n); } pure fn len(v: [mutable? T]) -> uint { unchecked { rusti::vec_len(v) } } +/* +Type: init_op + +A function used to initialize the elements of a vector. +*/ type init_op = fn@(uint) -> T; +/* +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(op: init_op, n_elts: uint) -> [T] { let v = []; reserve(v, n_elts); @@ -35,6 +62,14 @@ fn init_fn(op: init_op, n_elts: uint) -> [T] { } // TODO: Remove me once we have slots. +/* +Function: init_fn + +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(op: init_op, n_elts: uint) -> [mutable T] { let v = [mutable]; reserve(v, n_elts); @@ -43,6 +78,14 @@ fn init_fn_mut(op: init_op, n_elts: uint) -> [mutable T] { 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(t: T, n_elts: uint) -> [T] { let v = []; reserve(v, n_elts); @@ -52,6 +95,14 @@ fn init_elt(t: T, n_elts: uint) -> [T] { } // 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(t: T, n_elts: uint) -> [mutable T] { let v = [mutable]; reserve(v, n_elts); @@ -62,6 +113,11 @@ fn init_elt_mut(t: T, n_elts: uint) -> [mutable T] { // 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(v: [T]) -> [mutable T] { let vres = [mutable]; for t: T in v { vres += [mutable t]; } @@ -69,43 +125,91 @@ fn to_mut(v: [T]) -> [mutable T] { } // Same comment as from_mut +/* +Function: from_mut + +Produces an immutable vector from a mutable vector. +*/ fn from_mut(v: [mutable T]) -> [T] { let vres = []; for t: T in v { vres += [t]; } ret vres; } -// Predicates +/* +Predicate: is_empty + +Returns true if a vector contains no elements. +*/ pure fn is_empty(v: [mutable? 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(v: [mutable? T]) -> bool { ret !is_empty(v); } // Accessors -/// Returns the first element of a vector +/* +Function: head + +Returns the first element of a vector + +Predicates: + (v) +*/ fn head(v: [mutable? T]) : is_not_empty(v) -> T { ret v[0]; } -/// Returns all but the first element of a vector +/* +Function: tail + +Returns all but the first element of a vector + +Predicates: + (v) +*/ fn tail(v: [mutable? T]) : is_not_empty(v) -> [T] { ret slice(v, 1u, len(v)); } -/// Returns the last element of `v`. +/* +Function: last + +Returns the last element of `v` + +Returns: + +An option containing the last element of `v` if `v` is not empty, or +none if `v` is empty. +*/ fn last(v: [mutable? T]) -> option::t { if len(v) == 0u { ret none; } ret some(v[len(v) - 1u]); } -/// Returns the last element of a non-empty vector `v`. +/* +Function: last_total + +Returns the last element of a non-empty vector `v` + +Predicates: + (v) +*/ fn last_total(v: [mutable? T]) : is_not_empty(v) -> T { ret v[len(v) - 1u]; } -/// Returns a copy of the elements from [`start`..`end`) from `v`. +/* +Function: slice + +Returns a copy of the elements from [`start`..`end`) from `v`. +*/ fn slice(v: [mutable? T], start: uint, end: uint) -> [T] { assert (start <= end); assert (end <= len(v)); @@ -117,6 +221,11 @@ fn slice(v: [mutable? T], start: uint, end: uint) -> [T] { } // TODO: Remove me once we have slots. +/* +Function: slice_mut + +Returns a copy of the elements from [`start`..`end`) from `v`. +*/ fn slice_mut(v: [mutable? T], start: uint, end: uint) -> [mutable T] { assert (start <= end); assert (end <= len(v)); @@ -130,6 +239,11 @@ fn slice_mut(v: [mutable? T], start: uint, end: uint) -> [mutable T] { // Mutators +/* +Function: shift + +Removes the first element from a vector and return it +*/ fn shift(&v: [mutable? T]) -> T { let ln = len::(v); assert (ln > 0u); @@ -139,6 +253,11 @@ fn shift(&v: [mutable? T]) -> T { } // 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(&v: [mutable? T]) -> T { let ln = len(v); assert (ln > 0u); @@ -153,7 +272,17 @@ fn pop(&v: [mutable? T]) -> T { // Appending -/// Expands the given vector in-place by appending `n` copies of `initval`. +/* +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(&v: [T], n: uint, initval: T) { reserve(v, next_power_of_two(len(v) + n)); let i: uint = 0u; @@ -161,23 +290,54 @@ fn grow(&v: [T], n: uint, initval: T) { } // TODO: Remove me once we have slots. +// FIXME: Can't grow take a [mutable? 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(&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; } } -/// Calls `f` `n` times and appends the results of these calls to the given -/// vector. +/* +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(&v: [T], n: uint, init_fn: fn(uint) -> T) { reserve(v, next_power_of_two(len(v) + n)); let i: uint = 0u; while i < n { v += [init_fn(i)]; i += 1u; } } -/// 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. +/* +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(&v: [mutable T], index: uint, initval: T, val: T) { if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); } v[index] = val; @@ -186,6 +346,11 @@ fn grow_set(&v: [mutable T], index: uint, initval: T, val: T) { // Functional utilities +/* +Function: map + +Apply a function to each element of a vector and return the results +*/ fn map(f: block(T) -> U, v: [mutable? T]) -> [U] { let result = []; reserve(result, len(v)); @@ -196,6 +361,11 @@ fn map(f: block(T) -> U, v: [mutable? T]) -> [U] { ret result; } +/* +Function: map2 + +Apply a function to each pair of elements and return the results +*/ fn map2(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] { let v0_len = len::(v0); if v0_len != len::(v1) { fail; } @@ -205,6 +375,14 @@ fn map2(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] { 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(f: block(T) -> option::t, v: [mutable? T]) -> [U] { let result = []; for elem: T in v { @@ -217,6 +395,15 @@ fn filter_map(f: block(T) -> option::t, v: [mutable? T]) -> [U] { 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(f: block(T) -> bool, v: [mutable? T]) -> [T] { let result = []; for elem: T in v { @@ -228,6 +415,11 @@ fn filter(f: block(T) -> bool, v: [mutable? T]) -> [T] { ret result; } +/* +Function: foldl + +FIXME: This looks like it's actually foldr +*/ fn foldl(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U { let sz = len(v); if sz == 0u { ret z; } @@ -236,44 +428,97 @@ fn foldl(p: block(U, T) -> U, z: U, v: [mutable? T]) -> U { ret p(foldl(p, z, rest), first); } +/* +Function: any + +Return true if a predicate matches any elements + +If the vector contains no elements then false is returned. +*/ fn any(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(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(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(x: T, v: [mutable? 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` matches then an option containing the element +is returned. If `f` matches no elements then none is returned. +*/ fn find(f: block(T) -> bool, v: [T]) -> option::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(x: T, v: [T]) -> option::t { let i: uint = 0u; while i < len(v) { if x == v[i] { ret some::(i); } i += 1u; } ret none; } +/* +Function: position_pred + +Find the first index for which the value matches some predicate +*/ fn position_pred(f: fn(T) -> bool, v: [T]) -> option::t { let i: uint = 0u; while i < len(v) { if f(v[i]) { ret some::(i); } i += 1u; } ret none; } +/* +Predicate: same_length + +Returns true if two vectors have the same length +*/ pure fn same_length(xs: [T], ys: [U]) -> bool { vec::len(xs) == vec::len(ys) } @@ -282,12 +527,34 @@ pure fn same_length(xs: [T], ys: [U]) -> bool { // 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(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: + + (v, u) +*/ fn zip(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] { let zipped = []; let sz = len(v), i = 0u; @@ -296,14 +563,27 @@ fn zip(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] { ret zipped; } -// Swaps two elements in a vector +/* +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(v: [mutable T], a: uint, b: uint) { let t: T = v[a]; v[a] = v[b]; v[b] = t; } -// In place vector reversal +/* +Function: reverse + +Reverse the order of elements in a vector, in place +*/ fn reverse(v: [mutable T]) { let i: uint = 0u; let ln = len::(v); @@ -311,7 +591,11 @@ fn reverse(v: [mutable T]) { } -// Functional vector reversal. Returns a reversed copy of v. +/* +Function: reversed + +Returns a vector with the order of elements reversed +*/ fn reversed(v: [T]) -> [T] { let rs: [T] = []; let i = len::(v); @@ -321,7 +605,12 @@ fn reversed(v: [T]) -> [T] { ret rs; } -// Generating vecs. +// 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 = []; @@ -329,6 +618,12 @@ fn enum_chars(start: u8, end: u8) : u8::le(start, end) -> [char] { 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 = []; @@ -336,6 +631,14 @@ fn enum_uints(start: uint, end: uint) : uint::le(start, end) -> [uint] { ret r; } +/* +Function: eachi + +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 eachi(f: block(T, uint) -> (), v: [mutable? T]) { let i = 0u; let l = len(v); @@ -346,33 +649,75 @@ fn eachi(f: block(T, uint) -> (), v: [mutable? T]) { } } -// Iterate over a list with with the indexes +/* +Function: iter2 + +FIXME: This is exactly the same as eachi +*/ fn iter2(v: [T], it: block(uint, T)) { let i = 0u; for x in v { it(i, x); i += 1u; } } +/* +Function: to_ptr + +FIXME: We don't need this wrapper +*/ +unsafe fn to_ptr(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(ptr: *T, elts: uint) -> [T] { ret rustrt::vec_from_buf_shared(sys::get_type_desc::(), 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(&v: [T], new_len: uint) { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); (**repr).fill = new_len * sys::size_of::(); } + /* + 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(v: [T]) -> *T { let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v)); ret ::unsafe::reinterpret_cast(addr_of((**repr).data)); } } -unsafe fn to_ptr(v: [T]) -> *T { ret unsafe::to_ptr(v); } - // Local Variables: // mode: rust; // fill-column: 78;