Skip to content

Commit

Permalink
auto merge of #9276 : alexcrichton/rust/dox, r=brson
Browse files Browse the repository at this point in the history
Hopefull this will make our libstd docs appear a little more "full".
  • Loading branch information
bors committed Sep 20, 2013
2 parents 2fd3c07 + 88bc11e commit a95604f
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 51 deletions.
52 changes: 52 additions & 0 deletions src/libstd/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,58 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
C-string manipulation and management
This modules provides the basic methods for creating and manipulating
null-terminated strings for use with FFI calls (back to C). Most C APIs require
that the string being passed to them is null-terminated, and by default rust's
string types are *not* null terminated.
The other problem with translating Rust strings to C strings is that Rust
strings can validly contain a null-byte in the middle of the string (0 is a
valid unicode codepoint). This means that not all Rust strings can actually be
translated to C strings.
# Creation of a C string
A C string is managed through the `CString` type defined in this module. It
"owns" the internal buffer of characters and will automatically deallocate the
buffer when the string is dropped. The `ToCStr` trait is implemented for `&str`
and `&[u8]`, but the conversions can fail due to some of the limitations
explained above.
This also means that currently whenever a C string is created, an allocation
must be performed to place the data elsewhere (the lifetime of the C string is
not tied to the lifetime of the original string/data buffer). If C strings are
heavily used in applications, then caching may be advisable to prevent
unnecessary amounts of allocations.
An example of creating and using a C string would be:
~~~{.rust}
use std::libc;
externfn!(fn puts(s: *libc::c_char))
let my_string = "Hello, world!";
// Allocate the C string with an explicit local that owns the string. The
// `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope.
let my_c_string = my_string.to_c_str();
do my_c_string.with_ref |c_buffer| {
unsafe { puts(c_buffer); }
}
// Don't save off the allocation of the C string, the `c_buffer` will be
// deallocated when this block returns!
do my_string.with_c_str |c_buffer| {
unsafe { puts(c_buffer); }
}
~~~
*/

use cast;
use iter::{Iterator, range};
use libc;
Expand Down
175 changes: 142 additions & 33 deletions src/libstd/condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,71 +8,179 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Condition handling */
/*!
#[allow(missing_doc)];
Condition handling
Conditions are a utility used to deal with handling error conditions. The syntax
of a condition handler strikes a resemblance to try/catch blocks in other
languages, but condition handlers are *not* a form of exception handling in the
same manner.
A condition is declared through the `condition!` macro provided by the compiler:
~~~{.rust}
condition! {
pub my_error: int -> ~str;
}
~~~
This macro declares an inner module called `my_error` with one static variable,
`cond` that is a static `Condition` instance. To help understand what the other
parameters are used for, an example usage of this condition would be:
~~~{.rust}
do my_error::cond.trap(|raised_int| {
// the condition `my_error` was raised on, and the value it raised is stored
// in `raised_int`. This closure must return a `~str` type (as specified in
// the declaration of the condition
if raised_int == 3 { ~"three" } else { ~"oh well" }
}).inside {
// The condition handler above is installed for the duration of this block.
// That handler will override any previous handler, but the previous handler
// is restored when this block returns (handlers nest)
//
// If any code from this block (or code from another block) raises on the
// condition, then the above handler will be invoked (so long as there's no
// other nested handler).
println(my_error::cond.raise(3)); // prints "three"
println(my_error::cond.raise(4)); // prints "oh well"
}
~~~
Condition handling is useful in cases where propagating errors is either to
cumbersome or just not necessary in the first place. It should also be noted,
though, that if there is not handler installed when a condition is raised, then
the task invokes `fail!()` and will terminate.
## More Info
Condition handlers as an error strategy is well explained in the [conditions
tutorial](http://static.rust-lang.org/doc/master/tutorial-conditions.html),
along with comparing and contrasting it with other error handling strategies.
*/

use local_data;
use prelude::*;
use unstable::raw::Closure;

// helper for transmutation, shown below.
type RustClosure = (int, int);

#[doc(hidden)]
pub struct Handler<T, U> {
handle: RustClosure,
prev: Option<@Handler<T, U>>,
priv handle: Closure,
priv prev: Option<@Handler<T, U>>,
}

/// This struct represents the state of a condition handler. It contains a key
/// into TLS which holds the currently install handler, along with the name of
/// the condition (useful for debugging).
///
/// This struct should never be created directly, but rather only through the
/// `condition!` macro provided to all libraries using libstd.
pub struct Condition<T, U> {
/// Name of the condition handler
name: &'static str,
/// TLS key used to insert/remove values in TLS.
key: local_data::Key<@Handler<T, U>>
}

impl<T, U> Condition<T, U> {
/// Creates an object which binds the specified handler. This will also save
/// the current handler *on creation* such that when the `Trap` is consumed,
/// it knows which handler to restore.
///
/// # Example
///
/// ~~~{.rust}
/// condition! { my_error: int -> int; }
///
/// let trap = my_error::cond.trap(|error| error + 3);
///
/// // use `trap`'s inside method to register the handler and then run a
/// // block of code with the handler registered
/// ~~~
pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
unsafe {
let p : *RustClosure = ::cast::transmute(&h);
let prev = local_data::get(self.key, |k| k.map(|&x| *x));
let h = @Handler { handle: *p, prev: prev };
Trap { cond: self, handler: h }
}
let h: Closure = unsafe { ::cast::transmute(h) };
let prev = local_data::get(self.key, |k| k.map(|&x| *x));
let h = @Handler { handle: h, prev: prev };
Trap { cond: self, handler: h }
}

/// Raises on this condition, invoking any handler if one has been
/// registered, or failing the current task otherwise.
///
/// While a condition handler is being run, the condition will have no
/// handler listed, so a task failure will occur if the condition is
/// re-raised during the handler.
///
/// # Arguments
///
/// * t - The argument to pass along to the condition handler.
///
/// # Return value
///
/// If a handler is found, its return value is returned, otherwise this
/// function will not return.
pub fn raise(&self, t: T) -> U {
let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
self.raise_default(t, || fail!(msg.clone()))
}

/// Performs the same functionality as `raise`, except that when no handler
/// is found the `default` argument is called instead of failing the task.
pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
unsafe {
match local_data::pop(self.key) {
None => {
debug!("Condition.raise: found no handler");
default()
}
Some(handler) => {
debug!("Condition.raise: found handler");
match handler.prev {
None => {}
Some(hp) => local_data::set(self.key, hp)
}
let handle : &fn(T) -> U =
::cast::transmute(handler.handle);
let u = handle(t);
local_data::set(self.key, handler);
u
match local_data::pop(self.key) {
None => {
debug!("Condition.raise: found no handler");
default()
}
Some(handler) => {
debug!("Condition.raise: found handler");
match handler.prev {
None => {}
Some(hp) => local_data::set(self.key, hp)
}
let handle : &fn(T) -> U = unsafe {
::cast::transmute(handler.handle)
};
let u = handle(t);
local_data::set(self.key, handler);
u
}
}
}
}

/// A `Trap` is created when the `trap` method is invoked on a `Condition`, and
/// it is used to actually bind a handler into the TLS slot reserved for this
/// condition.
///
/// Normally this object is not dealt with directly, but rather it's directly
/// used after being returned from `trap`
struct Trap<'self, T, U> {
cond: &'self Condition<T, U>,
handler: @Handler<T, U>
priv cond: &'self Condition<T, U>,
priv handler: @Handler<T, U>
}

impl<'self, T, U> Trap<'self, T, U> {
/// Execute a block of code with this trap handler's exception handler
/// registered.
///
/// # Example
///
/// ~~~{.rust}
/// condition! { my_error: int -> int; }
///
/// let result = do my_error::cond.trap(|error| error + 3).inside {
/// my_error::cond.raise(4)
/// };
/// assert_eq!(result, 7);
/// ~~~
pub fn inside<V>(&self, inner: &'self fn() -> V) -> V {
let _g = Guard { cond: self.cond };
debug!("Trap: pushing handler to TLS");
Expand All @@ -81,8 +189,9 @@ impl<'self, T, U> Trap<'self, T, U> {
}
}

#[doc(hidden)]
struct Guard<'self, T, U> {
cond: &'self Condition<T, U>
priv cond: &'self Condition<T, U>
}

#[unsafe_destructor]
Expand Down
17 changes: 9 additions & 8 deletions src/libstd/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@

/*!
# The Formatting Module
The Formatting Module
This module contains the runtime support for the `format!` syntax extension. This
macro is implemented in the compiler to emit calls to this module in order to
format arguments at runtime into strings and streams.
This module contains the runtime support for the `format!` syntax extension.
This macro is implemented in the compiler to emit calls to this module in order
to format arguments at runtime into strings and streams.
The functions contained in this module should not normally be used in everyday
use cases of `format!`. The assumptions made by these functions are unsafe for all
inputs, and the compiler performs a large amount of validation on the arguments
to `format!` in order to ensure safety at runtime. While it is possible to call
these functions directly, it is not recommended to do so in the general case.
use cases of `format!`. The assumptions made by these functions are unsafe for
all inputs, and the compiler performs a large amount of validation on the
arguments to `format!` in order to ensure safety at runtime. While it is
possible to call these functions directly, it is not recommended to do so in the
general case.
## Usage
Expand Down
55 changes: 51 additions & 4 deletions src/libstd/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,59 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Composable external iterators
/*!
The `Iterator` trait defines an interface for objects which implement iteration as a state machine.
Composable external iterators
Algorithms like `zip` are provided as `Iterator` implementations which wrap other objects
implementing the `Iterator` trait.
# The `Iterator` trait
This module defines Rust's core iteration trait. The `Iterator` trait has one
un-implemented method, `next`. All other methods are derived through default
methods to perform operations such as `zip`, `chain`, `enumerate`, and `fold`.
The goal of this module is to unify iteration across all containers in Rust.
An iterator can be considered as a state machine which is used to track which
element will be yielded next.
There are various extensions also defined in this module to assist with various
types of iteration, such as the `DoubleEndedIterator` for iterating in reverse,
the `FromIterator` trait for creating a container from an iterator, and much
more.
## Rust's `for` loop
The special syntax used by rust's `for` loop is based around the `Iterator`
trait defined in this module. For loops can be viewed as a syntactical expansion
into a `loop`, for example, the `for` loop in this example is essentially
translated to the `loop` below.
~~~{.rust}
let values = ~[1, 2, 3];
// "Syntactical sugar" taking advantage of an iterator
for &x in values.iter() {
println!("{}", x);
}
// Rough translation of the iteration without a `for` iterator.
let mut it = values.iter();
loop {
match it.next() {
Some(&x) => {
println!("{}", x);
}
None => { break }
}
}
~~~
This `for` loop syntax can be applied to any iterator over any type.
## Iteration protocol and more
More detailed information about iterators can be found in the [container
tutorial](http://static.rust-lang.org/doc/master/tutorial-container.html) with
the rest of the rust manuals.
*/

Expand Down
Loading

0 comments on commit a95604f

Please sign in to comment.