Begin documenting std and add doc generation using naturaldocs

Naturaldocs isn't really that great but it seems easier to get
something working than with doxygen, for which we would need to
convert rust code to something C++ish. We probably want to just
write a rustdoc utility at some point.
This commit is contained in:
Brian Anderson 2011-10-24 15:25:41 -07:00
parent 013107a25c
commit 7ae757583a
23 changed files with 1413 additions and 111 deletions

3
configure vendored
View File

@ -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 \

124
doc/Languages.txt Normal file
View File

@ -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: {

159
doc/Topics.txt Normal file
View File

@ -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

View File

@ -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 $< $@

View File

@ -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::<uint>(elt, nbits / uint_bits() + 1u);

View File

@ -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<T>(a: @T, b: @T) -> bool {
let a_ptr: uint = unsafe::reinterpret_cast(a);
let b_ptr: uint = unsafe::reinterpret_cast(b);

View File

@ -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';

View File

@ -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<str>) {
> 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<unique T> { chan_t(task::task, port_id); }
/*
Type: chan
A handle through which data may be sent.
Each channel is associated with a single <port>.
*/
tag chan<unique T> {
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 <chan>s.
*/
tag port<unique T> { 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<unique T>(ch: chan<T>, -data: T) {
let chan_t(t, p) = ch;
rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data);
task::yield();
}
/*
Function: port
Constructs a port.
*/
fn port<unique T>() -> port<T> {
let p = rustrt::new_port(sys::size_of::<T>());
ret port_t(@port_ptr(p));
port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
}
fn recv<unique T>(p: port<T>) -> T {
ret rusti::recv(***p);
}
/*
Function: recv
Receive from a port.
*/
fn recv<unique T>(p: port<T>) -> T { ret rusti::recv(***p) }
/*
Function: chan
Constructs a channel.
*/
fn chan<unique T>(p: port<T>) -> chan<T> {
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))
}

View File

@ -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;

View File

@ -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<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<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>() -> t<T> {
type cell<T> = option::t<T>;

View File

@ -1,15 +1,46 @@
/*
Module: either
A type that represents one of two alternatives
*/
import option;
import option::{some, none};
tag t<T, U> { left(T); right(U); }
/*
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<T, U>(eithers: [t<T, U>]) -> [T] {
let result: [T] = [];
for elt: t<T, U> in eithers {
@ -18,6 +49,11 @@ fn lefts<T, U>(eithers: [t<T, U>]) -> [T] {
ret result;
}
/*
Function: rights
Extracts from a vector of either all the right values
*/
fn rights<T, U>(eithers: [t<T, U>]) -> [U] {
let result: [U] = [];
for elt: t<T, U> in eithers {
@ -26,6 +62,14 @@ fn rights<T, U>(eithers: [t<T, U>]) -> [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<T, U>(eithers: [t<T, U>]) -> {lefts: [T], rights: [U]} {
let lefts: [T] = [];
let rights: [U] = [];
@ -34,6 +78,7 @@ fn partition<T, U>(eithers: [t<T, U>]) -> {lefts: [T], rights: [U]} {
}
ret {lefts: lefts, rights: rights};
}
//
// Local Variables:
// mode: rust

View File

@ -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};

View File

@ -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:
<NaN> 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:
<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 {
@ -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.;
}

View File

@ -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);

View File

@ -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<K, V> = @tree_node<K, V>;
/*
Tag: tree_node
*/
tag tree_node<K, V> {
empty;
node(@K, @V, @tree_node<K, V>, @tree_node<K, V>);
}
type treemap<K, V> = @tree_node<K, V>;
/* Section: Operations */
/*
Function: init
Create a treemap
*/
fn init<K, V>() -> treemap<K, V> { @empty }
/*
Function: insert
Insert a value into the map
*/
fn insert<K, V>(m: treemap<K, V>, k: K, v: V) -> treemap<K, V> {
@alt m {
@empty. { node(@k, @v, @empty, @empty) }
@ -41,6 +63,11 @@ fn insert<K, V>(m: treemap<K, V>, k: K, v: V) -> treemap<K, V> {
}
}
/*
Function: find
Find a value based on the key
*/
fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> {
alt *m {
empty. { none }
@ -52,8 +79,11 @@ fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> {
}
}
/*
Function: traverse
// Performs an in-order traversal
Visit all pairs in the map in order.
*/
fn traverse<K, V>(m: treemap<K, V>, f: fn(K, V)) {
alt *m {
empty. { }

View File

@ -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<str> { }
#[cfg(bogus)]
/*
Function: setenv
Set the value of an environment variable
*/
fn setenv(n: str, v: str) { }
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]

View File

@ -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<uint> {
ret none::<uint>;
}
/*
Type: fail_
The type returned when the command line does not conform to the
expected format. Pass this value to <fail_str> to get an error message.
*/
tag fail_ {
argument_missing(str);
unrecognized_option(str);
@ -89,6 +169,11 @@ tag fail_ {
unexpected_argument(str);
}
/*
Function: fail_str
Convert a <fail_> tag into an error string
*/
fn fail_str(f: fail_) -> str {
ret alt f {
argument_missing(nm) { "Argument to option '" + nm + "' missing." }
@ -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 <opt_present>
<opt_str>, etc. to interrogate results.
failure(fail_) - On failure. Use <fail_str> to get an error message.
*/
fn getopts(args: [str], opts: [opt]) -> result {
let n_opts = vec::len::<opt>(opts);
fn f(_x: uint) -> [optval] { ret []; }
@ -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::<optval>(opt_vals(m, nm)) > 0u;
}
/*
Function: opt_str
Returns the string argument supplied to a matching option
Failure:
- If the option was not matched
- If the match did not take an argument
*/
fn opt_str(m: match, nm: str) -> str {
ret alt opt_val(m, nm) { val(s) { s } _ { fail } };
}
/*
Function: opt_str
Returns a vector of the arguments provided to all matches of the given option.
Used when an option accepts multiple values.
*/
fn opt_strs(m: match, nm: str) -> [str] {
let acc: [str] = [];
for v: optval in opt_vals(m, nm) {
@ -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<str> {
let vals = opt_vals(m, nm);
if vec::len::<optval>(vals) == 0u { ret none::<str>; }
@ -231,9 +363,15 @@ fn opt_maybe_str(m: match, nm: str) -> option::t<str> {
}
/// Returns none if the option was not present, `def` if the option was
/// present but no argument was provided, and the argument if the option was
/// present and an argument was provided.
/*
Function: opt_default
Returns the matching string, a default, or none
Returns none if the option was not present, `def` if the option was
present but no argument was provided, and the argument if the option was
present and an argument was provided.
*/
fn opt_default(m: match, nm: str, def: str) -> option::t<str> {
let vals = opt_vals(m, nm);
if vec::len::<optval>(vals) == 0u { ret none::<str>; }

View File

@ -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::<int>() * 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::<u8>(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; }

View File

@ -1,4 +1,3 @@
import os::libc;
native "c-stack-cdecl" mod rustrt {

View File

@ -1,30 +1,85 @@
// lib/option::rs
/*
Module: option
tag t<T> { none; some(T); }
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<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
*/
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
*/
fn is_some<T>(opt: t<T>) -> bool { !is_none(opt) }
/*
Function: from_maybe
Returns the contained value or a default
*/
fn from_maybe<T>(def: T, opt: t<T>) -> T {
alt opt { some(x) { x } none. { def } }
}
/*
Function: maybe
Applies a function to the contained value or returns a default
*/
fn maybe<T, U>(def: U, f: block(T) -> U, opt: t<T>) -> U {
alt opt { none. { def } some(t) { f(t) } }
}
// 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<T>(f: block(T), opt: t<T>) {
alt opt { none. {/* nothing */ } some(t) { f(t); } }
}

View File

@ -1,4 +1,3 @@
#[link(name = "std",
vers = "0.1",
uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297",

View File

@ -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<K, V> { empty; node(@K, @V, treemap<K, V>, treemap<K, V>); }
/* Section: Types */
/*
Type: treemap
*/
type treemap<K, V> = @mutable tree_node<K, V>;
/*
Tag: tree_node
*/
tag tree_node<K, V> { empty; node(@K, @V, treemap<K, V>, treemap<K, V>); }
/* Section: Operations */
/*
Function: init
Create a treemap
*/
fn init<K, V>() -> treemap<K, V> { @mutable empty }
/*
Function: insert
Insert a value into the map
*/
fn insert<K, V>(m: treemap<K, V>, k: K, v: V) {
alt m {
@empty. { *m = node(@k, @v, @mutable empty, @mutable empty); }
@ -36,6 +58,11 @@ fn insert<K, V>(m: treemap<K, V>, k: K, v: V) {
}
}
/*
Function: find
Find a value based on the key
*/
fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> {
alt *m {
empty. { none }
@ -51,7 +78,11 @@ fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> {
}
}
// Performs an in-order traversal
/*
Function: traverse
Visit all pairs in the map in order.
*/
fn traverse<K, V>(m: treemap<K, V>, f: fn@(K, V)) {
alt *m {
empty. { }

View File

@ -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<T>(&v: [mutable? T], n: uint) {
rustrt::vec_reserve_shared(sys::get_type_desc::<T>(), v, n);
}
pure fn len<T>(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<T> = 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<T>(op: init_op<T>, n_elts: uint) -> [T] {
let v = [];
reserve(v, n_elts);
@ -35,6 +62,14 @@ fn init_fn<T>(op: init_op<T>, 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<T>(op: init_op<T>, n_elts: uint) -> [mutable T] {
let v = [mutable];
reserve(v, n_elts);
@ -43,6 +78,14 @@ fn init_fn_mut<T>(op: init_op<T>, 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: T, n_elts: uint) -> [T] {
let v = [];
reserve(v, n_elts);
@ -52,6 +95,14 @@ fn init_elt<T>(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: T, n_elts: uint) -> [mutable T] {
let v = [mutable];
reserve(v, n_elts);
@ -62,6 +113,11 @@ fn init_elt_mut<T>(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<T>(v: [T]) -> [mutable T] {
let vres = [mutable];
for t: T in v { vres += [mutable t]; }
@ -69,43 +125,91 @@ fn to_mut<T>(v: [T]) -> [mutable T] {
}
// Same comment as from_mut
/*
Function: from_mut
Produces an immutable vector from a mutable vector.
*/
fn from_mut<T>(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<T>(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<T>(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:
<is_not_empty> (v)
*/
fn head<T>(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:
<is_not_empty> (v)
*/
fn tail<T>(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<T>(v: [mutable? T]) -> option::t<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:
<is_not_empty> (v)
*/
fn last_total<T>(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<T>(v: [mutable? T], start: uint, end: uint) -> [T] {
assert (start <= end);
assert (end <= len(v));
@ -117,6 +221,11 @@ fn slice<T>(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<T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
assert (start <= end);
assert (end <= len(v));
@ -130,6 +239,11 @@ fn slice_mut<T>(v: [mutable? T], start: uint, end: uint) -> [mutable T] {
// Mutators
/*
Function: shift
Removes the first element from a vector and return it
*/
fn shift<T>(&v: [mutable? T]) -> T {
let ln = len::<T>(v);
assert (ln > 0u);
@ -139,6 +253,11 @@ fn shift<T>(&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<T>(&v: [mutable? T]) -> T {
let ln = len(v);
assert (ln > 0u);
@ -153,7 +272,17 @@ fn pop<T>(&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<T>(&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<T>(&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<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; }
}
/// 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<T>(&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<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;
@ -186,6 +346,11 @@ fn grow_set<T>(&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<T, U>(f: block(T) -> U, v: [mutable? T]) -> [U] {
let result = [];
reserve(result, len(v));
@ -196,6 +361,11 @@ fn map<T, U>(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<T, U, V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
let v0_len = len::<T>(v0);
if v0_len != len::<U>(v1) { fail; }
@ -205,6 +375,14 @@ fn map2<T, U, V>(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<T, U>(f: block(T) -> option::t<U>, v: [mutable? T]) -> [U] {
let result = [];
for elem: T in v {
@ -217,6 +395,15 @@ fn filter_map<T, U>(f: block(T) -> option::t<U>, 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<T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
let result = [];
for elem: T in v {
@ -228,6 +415,11 @@ fn filter<T>(f: block(T) -> bool, v: [mutable? T]) -> [T] {
ret result;
}
/*
Function: foldl
FIXME: This looks like it's actually foldr
*/
fn foldl<T, U>(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<T, U>(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<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: [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<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: fn(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;
}
/*
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)
}
@ -282,12 +527,34 @@ pure fn same_length<T, U>(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<T, 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<T, U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
let zipped = [];
let sz = len(v), i = 0u;
@ -296,14 +563,27 @@ fn zip<T, U>(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<T>(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<T>(v: [mutable T]) {
let i: uint = 0u;
let ln = len::<T>(v);
@ -311,7 +591,11 @@ fn reverse<T>(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<T>(v: [T]) -> [T] {
let rs: [T] = [];
let i = len::<T>(v);
@ -321,7 +605,12 @@ fn reversed<T>(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<T>(f: block(T, uint) -> (), v: [mutable? T]) {
let i = 0u;
let l = len(v);
@ -346,33 +649,75 @@ fn eachi<T>(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<T>(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<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: [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: [T]) -> *T {
let repr: **vec_repr = ::unsafe::reinterpret_cast(addr_of(v));
ret ::unsafe::reinterpret_cast(addr_of((**repr).data));
}
}
unsafe fn to_ptr<T>(v: [T]) -> *T { ret unsafe::to_ptr(v); }
// Local Variables:
// mode: rust;
// fill-column: 78;