make_dir $h/test/debug-info
make_dir $h/test/codegen
make_dir $h/test/doc-tutorial
- make_dir $h/test/doc-tutorial-ffi
- make_dir $h/test/doc-tutorial-macros
- make_dir $h/test/doc-tutorial-borrowed-ptr
- make_dir $h/test/doc-tutorial-container
- make_dir $h/test/doc-tutorial-tasks
- make_dir $h/test/doc-tutorial-conditions
+ make_dir $h/test/doc-guide-ffi
+ make_dir $h/test/doc-guide-macros
+ make_dir $h/test/doc-guide-borrowed-ptr
+ make_dir $h/test/doc-guide-container
+ make_dir $h/test/doc-guide-tasks
+ make_dir $h/test/doc-guide-conditions
make_dir $h/test/doc-rust
done
--- /dev/null
+% Rust Borrowed Pointers Guide
+
+# Introduction
+
+Borrowed pointers are one of the more flexible and powerful tools available in
+Rust. A borrowed pointer can point anywhere: into the managed or exchange
+heap, into the stack, and even into the interior of another data structure. A
+borrowed pointer is as flexible as a C pointer or C++ reference. However,
+unlike C and C++ compilers, the Rust compiler includes special static checks
+that ensure that programs use borrowed pointers safely. Another advantage of
+borrowed pointers is that they are invisible to the garbage collector, so
+working with borrowed pointers helps reduce the overhead of automatic memory
+management.
+
+Despite their complete safety, a borrowed pointer's representation at runtime
+is the same as that of an ordinary pointer in a C program. They introduce zero
+overhead. The compiler does all safety checks at compile time.
+
+Although borrowed pointers have rather elaborate theoretical
+underpinnings (region pointers), the core concepts will be familiar to
+anyone who has worked with C or C++. Therefore, the best way to explain
+how they are used—and their limitations—is probably just to work
+through several examples.
+
+# By example
+
+Borrowed pointers are called *borrowed* because they are only valid for
+a limited duration. Borrowed pointers never claim any kind of ownership
+over the data that they point to: instead, they are used for cases
+where you would like to use data for a short time.
+
+As an example, consider a simple struct type `Point`:
+
+~~~
+struct Point {x: f64, y: f64}
+~~~
+
+We can use this simple definition to allocate points in many different ways. For
+example, in this code, each of these three local variables contains a
+point, but allocated in a different place:
+
+~~~
+# struct Point {x: f64, y: f64}
+let on_the_stack : Point = Point {x: 3.0, y: 4.0};
+let managed_box : @Point = @Point {x: 5.0, y: 1.0};
+let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
+~~~
+
+Suppose we wanted to write a procedure that computed the distance between any
+two points, no matter where they were stored. For example, we might like to
+compute the distance between `on_the_stack` and `managed_box`, or between
+`managed_box` and `owned_box`. One option is to define a function that takes
+two arguments of type `Point`—that is, it takes the points by value. But if we
+define it this way, calling the function will cause the points to be
+copied. For points, this is probably not so bad, but often copies are
+expensive. Worse, if the data type contains mutable fields, copying can change
+the semantics of your program in unexpected ways. So we'd like to define a
+function that takes the points by pointer. We can use borrowed pointers to do
+this:
+
+~~~
+# struct Point {x: f64, y: f64}
+# fn sqrt(f: f64) -> f64 { 0.0 }
+fn compute_distance(p1: &Point, p2: &Point) -> f64 {
+ let x_d = p1.x - p2.x;
+ let y_d = p1.y - p2.y;
+ sqrt(x_d * x_d + y_d * y_d)
+}
+~~~
+
+Now we can call `compute_distance()` in various ways:
+
+~~~
+# struct Point {x: f64, y: f64}
+# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
+# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
+# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};
+# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
+compute_distance(&on_the_stack, managed_box);
+compute_distance(managed_box, owned_box);
+~~~
+
+Here, the `&` operator takes the address of the variable
+`on_the_stack`; this is because `on_the_stack` has the type `Point`
+(that is, a struct value) and we have to take its address to get a
+value. We also call this _borrowing_ the local variable
+`on_the_stack`, because we have created an alias: that is, another
+name for the same data.
+
+In contrast, we can pass the boxes `managed_box` and `owned_box` to
+`compute_distance` directly. The compiler automatically converts a box like
+`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another form
+of borrowing: in this case, the caller lends the contents of the managed or
+owned box to the callee.
+
+Whenever a caller lends data to a callee, there are some limitations on what
+the caller can do with the original. For example, if the contents of a
+variable have been lent out, you cannot send that variable to another task. In
+addition, the compiler will reject any code that might cause the borrowed
+value to be freed or overwrite its component fields with values of different
+types (I'll get into what kinds of actions those are shortly). This rule
+should make intuitive sense: you must wait for a borrower to return the value
+that you lent it (that is, wait for the borrowed pointer to go out of scope)
+before you can make full use of it again.
+
+# Other uses for the & operator
+
+In the previous example, the value `on_the_stack` was defined like so:
+
+~~~
+# struct Point {x: f64, y: f64}
+let on_the_stack: Point = Point {x: 3.0, y: 4.0};
+~~~
+
+This declaration means that code can only pass `Point` by value to other
+functions. As a consequence, we had to explicitly take the address of
+`on_the_stack` to get a borrowed pointer. Sometimes however it is more
+convenient to move the & operator into the definition of `on_the_stack`:
+
+~~~
+# struct Point {x: f64, y: f64}
+let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
+~~~
+
+Applying `&` to an rvalue (non-assignable location) is just a convenient
+shorthand for creating a temporary and taking its address. A more verbose
+way to write the same code is:
+
+~~~
+# struct Point {x: f64, y: f64}
+let tmp = Point {x: 3.0, y: 4.0};
+let on_the_stack2 : &Point = &tmp;
+~~~
+
+# Taking the address of fields
+
+As in C, the `&` operator is not limited to taking the address of
+local variables. It can also take the address of fields or
+individual array elements. For example, consider this type definition
+for `rectangle`:
+
+~~~
+struct Point {x: f64, y: f64} // as before
+struct Size {w: f64, h: f64} // as before
+struct Rectangle {origin: Point, size: Size}
+~~~
+
+Now, as before, we can define rectangles in a few different ways:
+
+~~~
+# struct Point {x: f64, y: f64}
+# struct Size {w: f64, h: f64} // as before
+# struct Rectangle {origin: Point, size: Size}
+let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
+ size: Size {w: 3.0, h: 4.0}};
+let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0},
+ size: Size {w: 3.0, h: 4.0}};
+let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0},
+ size: Size {w: 3.0, h: 4.0}};
+~~~
+
+In each case, we can extract out individual subcomponents with the `&`
+operator. For example, I could write:
+
+~~~
+# struct Point {x: f64, y: f64} // as before
+# struct Size {w: f64, h: f64} // as before
+# struct Rectangle {origin: Point, size: Size}
+# let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0}, size: Size {w: 3.0, h: 4.0}};
+# let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0}, size: Size {w: 3.0, h: 4.0}};
+# let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
+# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
+compute_distance(&rect_stack.origin, &rect_managed.origin);
+~~~
+
+which would borrow the field `origin` from the rectangle on the stack
+as well as from the managed box, and then compute the distance between them.
+
+# Borrowing managed boxes and rooting
+
+We’ve seen a few examples so far of borrowing heap boxes, both managed
+and owned. Up till this point, we’ve glossed over issues of
+safety. As stated in the introduction, at runtime a borrowed pointer
+is simply a pointer, nothing more. Therefore, avoiding C's problems
+with dangling pointers requires a compile-time safety check.
+
+The basis for the check is the notion of _lifetimes_. A lifetime is a
+static approximation of the span of execution during which the pointer
+is valid: it always corresponds to some expression or block within the
+program. Code inside that expression can use the pointer without
+restrictions. But if the pointer escapes from that expression (for
+example, if the expression contains an assignment expression that
+assigns the pointer to a mutable field of a data structure with a
+broader scope than the pointer itself), the compiler reports an
+error. We'll be discussing lifetimes more in the examples to come, and
+a more thorough introduction is also available.
+
+When the `&` operator creates a borrowed pointer, the compiler must
+ensure that the pointer remains valid for its entire
+lifetime. Sometimes this is relatively easy, such as when taking the
+address of a local variable or a field that is stored on the stack:
+
+~~~
+struct X { f: int }
+fn example1() {
+ let mut x = X { f: 3 };
+ let y = &mut x.f; // -+ L
+ ... // |
+} // -+
+~~~
+
+Here, the lifetime of the borrowed pointer `y` is simply L, the
+remainder of the function body. The compiler need not do any other
+work to prove that code will not free `x.f`. This is true even if the
+code mutates `x`.
+
+The situation gets more complex when borrowing data inside heap boxes:
+
+~~~
+# struct X { f: int }
+fn example2() {
+ let mut x = @X { f: 3 };
+ let y = &x.f; // -+ L
+ ... // |
+} // -+
+~~~
+
+In this example, the value `x` is a heap box, and `y` is therefore a
+pointer into that heap box. Again the lifetime of `y` is L, the
+remainder of the function body. But there is a crucial difference:
+suppose `x` were to be reassigned during the lifetime L? If the
+compiler isn't careful, the managed box could become *unrooted*, and
+would therefore be subject to garbage collection. A heap box that is
+unrooted is one such that no pointer values in the heap point to
+it. It would violate memory safety for the box that was originally
+assigned to `x` to be garbage-collected, since a non-heap
+pointer *`y`* still points into it.
+
+> ***Note:*** Our current implementation implements the garbage collector
+> using reference counting and cycle detection.
+
+For this reason, whenever an `&` expression borrows the interior of a
+managed box stored in a mutable location, the compiler inserts a
+temporary that ensures that the managed box remains live for the
+entire lifetime. So, the above example would be compiled as if it were
+written
+
+~~~
+# struct X { f: int }
+fn example2() {
+ let mut x = @X {f: 3};
+ let x1 = x;
+ let y = &x1.f; // -+ L
+ ... // |
+} // -+
+~~~
+
+Now if `x` is reassigned, the pointer `y` will still remain valid. This
+process is called *rooting*.
+
+# Borrowing owned boxes
+
+The previous example demonstrated *rooting*, the process by which the
+compiler ensures that managed boxes remain live for the duration of a
+borrow. Unfortunately, rooting does not work for borrows of owned
+boxes, because it is not possible to have two references to a owned
+box.
+
+For owned boxes, therefore, the compiler will only allow a borrow *if
+the compiler can guarantee that the owned box will not be reassigned
+or moved for the lifetime of the pointer*. This does not necessarily
+mean that the owned box is stored in immutable memory. For example,
+the following function is legal:
+
+~~~
+# fn some_condition() -> bool { true }
+# struct Foo { f: int }
+fn example3() -> int {
+ let mut x = ~Foo {f: 3};
+ if some_condition() {
+ let y = &x.f; // -+ L
+ return *y; // |
+ } // -+
+ x = ~Foo {f: 4};
+ ...
+# return 0;
+}
+~~~
+
+Here, as before, the interior of the variable `x` is being borrowed
+and `x` is declared as mutable. However, the compiler can prove that
+`x` is not assigned anywhere in the lifetime L of the variable
+`y`. Therefore, it accepts the function, even though `x` is mutable
+and in fact is mutated later in the function.
+
+It may not be clear why we are so concerned about mutating a borrowed
+variable. The reason is that the runtime system frees any owned box
+_as soon as its owning reference changes or goes out of
+scope_. Therefore, a program like this is illegal (and would be
+rejected by the compiler):
+
+~~~ {.xfail-test}
+fn example3() -> int {
+ let mut x = ~X {f: 3};
+ let y = &x.f;
+ x = ~X {f: 4}; // Error reported here.
+ *y
+}
+~~~
+
+To make this clearer, consider this diagram showing the state of
+memory immediately before the re-assignment of `x`:
+
+~~~ {.notrust}
+ Stack Exchange Heap
+
+ x +----------+
+ | ~{f:int} | ----+
+ y +----------+ |
+ | &int | ----+
+ +----------+ | +---------+
+ +--> | f: 3 |
+ +---------+
+~~~
+
+Once the reassignment occurs, the memory will look like this:
+
+~~~ {.notrust}
+ Stack Exchange Heap
+
+ x +----------+ +---------+
+ | ~{f:int} | -------> | f: 4 |
+ y +----------+ +---------+
+ | &int | ----+
+ +----------+ | +---------+
+ +--> | (freed) |
+ +---------+
+~~~
+
+Here you can see that the variable `y` still points at the old box,
+which has been freed.
+
+In fact, the compiler can apply the same kind of reasoning to any
+memory that is _(uniquely) owned by the stack frame_. So we could
+modify the previous example to introduce additional owned pointers
+and structs, and the compiler will still be able to detect possible
+mutations:
+
+~~~ {.xfail-test}
+fn example3() -> int {
+ struct R { g: int }
+ struct S { f: ~R }
+
+ let mut x = ~S {f: ~R {g: 3}};
+ let y = &x.f.g;
+ x = ~S {f: ~R {g: 4}}; // Error reported here.
+ x.f = ~R {g: 5}; // Error reported here.
+ *y
+}
+~~~
+
+In this case, two errors are reported, one when the variable `x` is
+modified and another when `x.f` is modified. Either modification would
+invalidate the pointer `y`.
+
+# Borrowing and enums
+
+The previous example showed that the type system forbids any borrowing
+of owned boxes found in aliasable, mutable memory. This restriction
+prevents pointers from pointing into freed memory. There is one other
+case where the compiler must be very careful to ensure that pointers
+remain valid: pointers into the interior of an `enum`.
+
+As an example, let’s look at the following `shape` type that can
+represent both rectangles and circles:
+
+~~~
+struct Point {x: f64, y: f64}; // as before
+struct Size {w: f64, h: f64}; // as before
+enum Shape {
+ Circle(Point, f64), // origin, radius
+ Rectangle(Point, Size) // upper-left, dimensions
+}
+~~~
+
+Now we might write a function to compute the area of a shape. This
+function takes a borrowed pointer to a shape, to avoid the need for
+copying.
+
+~~~
+# struct Point {x: f64, y: f64}; // as before
+# struct Size {w: f64, h: f64}; // as before
+# enum Shape {
+# Circle(Point, f64), // origin, radius
+# Rectangle(Point, Size) // upper-left, dimensions
+# }
+# static tau: f64 = 6.28;
+fn compute_area(shape: &Shape) -> f64 {
+ match *shape {
+ Circle(_, radius) => 0.5 * tau * radius * radius,
+ Rectangle(_, ref size) => size.w * size.h
+ }
+}
+~~~
+
+The first case matches against circles. Here, the pattern extracts the
+radius from the shape variant and the action uses it to compute the
+area of the circle. (Like any up-to-date engineer, we use the [tau
+circle constant][tau] and not that dreadfully outdated notion of pi).
+
+[tau]: http://www.math.utah.edu/~palais/pi.html
+
+The second match is more interesting. Here we match against a
+rectangle and extract its size: but rather than copy the `size`
+struct, we use a by-reference binding to create a pointer to it. In
+other words, a pattern binding like `ref size` binds the name `size`
+to a pointer of type `&size` into the _interior of the enum_.
+
+To make this more clear, let's look at a diagram of memory layout in
+the case where `shape` points at a rectangle:
+
+~~~ {.notrust}
+Stack Memory
+
++-------+ +---------------+
+| shape | ------> | rectangle( |
++-------+ | {x: f64, |
+| size | -+ | y: f64}, |
++-------+ +----> | {w: f64, |
+ | h: f64}) |
+ +---------------+
+~~~
+
+Here you can see that rectangular shapes are composed of five words of
+memory. The first is a tag indicating which variant this enum is
+(`rectangle`, in this case). The next two words are the `x` and `y`
+fields for the point and the remaining two are the `w` and `h` fields
+for the size. The binding `size` is then a pointer into the inside of
+the shape.
+
+Perhaps you can see where the danger lies: if the shape were somehow
+to be reassigned, perhaps to a circle, then although the memory used
+to store that shape value would still be valid, _it would have a
+different type_! The following diagram shows what memory would look
+like if code overwrote `shape` with a circle:
+
+~~~ {.notrust}
+Stack Memory
+
++-------+ +---------------+
+| shape | ------> | circle( |
++-------+ | {x: f64, |
+| size | -+ | y: f64}, |
++-------+ +----> | f64) |
+ | |
+ +---------------+
+~~~
+
+As you can see, the `size` pointer would be pointing at a `f64`
+instead of a struct. This is not good: dereferencing the second field
+of a `f64` as if it were a struct with two fields would be a memory
+safety violation.
+
+So, in fact, for every `ref` binding, the compiler will impose the
+same rules as the ones we saw for borrowing the interior of a owned
+box: it must be able to guarantee that the `enum` will not be
+overwritten for the duration of the borrow. In fact, the compiler
+would accept the example we gave earlier. The example is safe because
+the shape pointer has type `&Shape`, which means "borrowed pointer to
+immutable memory containing a `shape`". If, however, the type of that
+pointer were `&mut Shape`, then the ref binding would be ill-typed.
+Just as with owned boxes, the compiler will permit `ref` bindings
+into data owned by the stack frame even if the data are mutable,
+but otherwise it requires that the data reside in immutable memory.
+
+# Returning borrowed pointers
+
+So far, all of the examples we have looked at, use borrowed pointers in a
+“downward” direction. That is, a method or code block creates a
+borrowed pointer, then uses it within the same scope. It is also
+possible to return borrowed pointers as the result of a function, but
+as we'll see, doing so requires some explicit annotation.
+
+For example, we could write a subroutine like this:
+
+~~~
+struct Point {x: f64, y: f64}
+fn get_x<'r>(p: &'r Point) -> &'r f64 { &p.x }
+~~~
+
+Here, the function `get_x()` returns a pointer into the structure it
+was given. The type of the parameter (`&'r Point`) and return type
+(`&'r f64`) both use a new syntactic form that we have not seen so
+far. Here the identifier `r` names the lifetime of the pointer
+explicitly. So in effect, this function declares that it takes a
+pointer with lifetime `r` and returns a pointer with that same
+lifetime.
+
+In general, it is only possible to return borrowed pointers if they
+are derived from a parameter to the procedure. In that case, the
+pointer result will always have the same lifetime as one of the
+parameters; named lifetimes indicate which parameter that
+is.
+
+In the previous examples, function parameter types did not include a
+lifetime name. In those examples, the compiler simply creates a fresh
+name for the lifetime automatically: that is, the lifetime name is
+guaranteed to refer to a distinct lifetime from the lifetimes of all
+other parameters.
+
+Named lifetimes that appear in function signatures are conceptually
+the same as the other lifetimes we have seen before, but they are a bit
+abstract: they don’t refer to a specific expression within `get_x()`,
+but rather to some expression within the *caller of `get_x()`*. The
+lifetime `r` is actually a kind of *lifetime parameter*: it is defined
+by the caller to `get_x()`, just as the value for the parameter `p` is
+defined by that caller.
+
+In any case, whatever the lifetime of `r` is, the pointer produced by
+`&p.x` always has the same lifetime as `p` itself: a pointer to a
+field of a struct is valid as long as the struct is valid. Therefore,
+the compiler accepts the function `get_x()`.
+
+To emphasize this point, let’s look at a variation on the example, this
+time one that does not compile:
+
+~~~ {.xfail-test}
+struct Point {x: f64, y: f64}
+fn get_x_sh(p: @Point) -> &f64 {
+ &p.x // Error reported here
+}
+~~~
+
+Here, the function `get_x_sh()` takes a managed box as input and
+returns a borrowed pointer. As before, the lifetime of the borrowed
+pointer that will be returned is a parameter (specified by the
+caller). That means that `get_x_sh()` promises to return a borrowed
+pointer that is valid for as long as the caller would like: this is
+subtly different from the first example, which promised to return a
+pointer that was valid for as long as its pointer argument was valid.
+
+Within `get_x_sh()`, we see the expression `&p.x` which takes the
+address of a field of a managed box. The presence of this expression
+implies that the compiler must guarantee that, so long as the
+resulting pointer is valid, the managed box will not be reclaimed by
+the garbage collector. But recall that `get_x_sh()` also promised to
+return a pointer that was valid for as long as the caller wanted it to
+be. Clearly, `get_x_sh()` is not in a position to make both of these
+guarantees; in fact, it cannot guarantee that the pointer will remain
+valid at all once it returns, as the parameter `p` may or may not be
+live in the caller. Therefore, the compiler will report an error here.
+
+In general, if you borrow a managed (or owned) box to create a
+borrowed pointer, the pointer will only be valid within the function
+and cannot be returned. This is why the typical way to return borrowed
+pointers is to take borrowed pointers as input (the only other case in
+which it can be legal to return a borrowed pointer is if the pointer
+points at a static constant).
+
+# Named lifetimes
+
+Let's look at named lifetimes in more detail. Named lifetimes allow
+for grouping of parameters by lifetime. For example, consider this
+function:
+
+~~~
+# struct Point {x: f64, y: f64}; // as before
+# struct Size {w: f64, h: f64}; // as before
+# enum Shape {
+# Circle(Point, f64), // origin, radius
+# Rectangle(Point, Size) // upper-left, dimensions
+# }
+# fn compute_area(shape: &Shape) -> f64 { 0.0 }
+fn select<'r, T>(shape: &'r Shape, threshold: f64,
+ a: &'r T, b: &'r T) -> &'r T {
+ if compute_area(shape) > threshold {a} else {b}
+}
+~~~
+
+This function takes three borrowed pointers and assigns each the same
+lifetime `r`. In practice, this means that, in the caller, the
+lifetime `r` will be the *intersection of the lifetime of the three
+region parameters*. This may be overly conservative, as in this
+example:
+
+~~~
+# struct Point {x: f64, y: f64}; // as before
+# struct Size {w: f64, h: f64}; // as before
+# enum Shape {
+# Circle(Point, f64), // origin, radius
+# Rectangle(Point, Size) // upper-left, dimensions
+# }
+# fn compute_area(shape: &Shape) -> f64 { 0.0 }
+# fn select<'r, T>(shape: &Shape, threshold: f64,
+# a: &'r T, b: &'r T) -> &'r T {
+# if compute_area(shape) > threshold {a} else {b}
+# }
+ // -+ r
+fn select_based_on_unit_circle<'r, T>( // |-+ B
+ threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
+ // | |
+ let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |
+ select(&shape, threshold, a, b) // | |
+} // |-+
+ // -+
+~~~
+
+In this call to `select()`, the lifetime of the first parameter shape
+is B, the function body. Both of the second two parameters `a` and `b`
+share the same lifetime, `r`, which is a lifetime parameter of
+`select_based_on_unit_circle()`. The caller will infer the
+intersection of these two lifetimes as the lifetime of the returned
+value, and hence the return value of `select()` will be assigned a
+lifetime of B. This will in turn lead to a compilation error, because
+`select_based_on_unit_circle()` is supposed to return a value with the
+lifetime `r`.
+
+To address this, we can modify the definition of `select()` to
+distinguish the lifetime of the first parameter from the lifetime of
+the latter two. After all, the first parameter is not being
+returned. Here is how the new `select()` might look:
+
+~~~
+# struct Point {x: f64, y: f64}; // as before
+# struct Size {w: f64, h: f64}; // as before
+# enum Shape {
+# Circle(Point, f64), // origin, radius
+# Rectangle(Point, Size) // upper-left, dimensions
+# }
+# fn compute_area(shape: &Shape) -> f64 { 0.0 }
+fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: f64,
+ a: &'r T, b: &'r T) -> &'r T {
+ if compute_area(shape) > threshold {a} else {b}
+}
+~~~
+
+Here you can see that `shape`'s lifetime is now named `tmp`. The
+parameters `a`, `b`, and the return value all have the lifetime `r`.
+However, since the lifetime `tmp` is not returned, it would be more
+concise to just omit the named lifetime for `shape` altogether:
+
+~~~
+# struct Point {x: f64, y: f64}; // as before
+# struct Size {w: f64, h: f64}; // as before
+# enum Shape {
+# Circle(Point, f64), // origin, radius
+# Rectangle(Point, Size) // upper-left, dimensions
+# }
+# fn compute_area(shape: &Shape) -> f64 { 0.0 }
+fn select<'r, T>(shape: &Shape, threshold: f64,
+ a: &'r T, b: &'r T) -> &'r T {
+ if compute_area(shape) > threshold {a} else {b}
+}
+~~~
+
+This is equivalent to the previous definition.
+
+# Conclusion
+
+So there you have it: a (relatively) brief tour of the borrowed pointer
+system. For more details, we refer to the (yet to be written) reference
+document on borrowed pointers, which will explain the full notation
+and give more examples.
--- /dev/null
+% Rust Condition and Error-handling Guide
+
+# Introduction
+
+Rust does not provide exception handling[^why-no-exceptions]
+in the form most commonly seen in other programming languages such as C++ or Java.
+Instead, it provides four mechanisms that work together to handle errors or other rare events.
+The four mechanisms are:
+
+ - Options
+ - Results
+ - Failure
+ - Conditions
+
+This guide will lead you through use of these mechanisms
+in order to understand the trade-offs of each and relationships between them.
+
+# Example program
+
+This guide will be based around an example program
+that attempts to read lines from a file
+consisting of pairs of numbers,
+and then print them back out with slightly different formatting.
+The input to the program might look like this:
+
+~~~~ {.notrust}
+$ cat numbers.txt
+1 2
+34 56
+789 123
+45 67
+~~~~
+
+For which the intended output looks like this:
+
+~~~~ {.notrust}
+$ ./example numbers.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+An example program that does this task reads like this:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+fn main() {
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+
+ // Path takes a generic by-value, rather than by reference
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+ let mut reader = BufferedReader::new(File::open(&path));
+
+ // 1. Iterate over the lines of our file.
+ for line in reader.lines() {
+ // 2. Split the line into fields ("words").
+ let fields = line.words().to_owned_vec();
+ // 3. Match the vector of fields against a vector pattern.
+ match fields {
+
+ // 4. When the line had two fields:
+ [a, b] => {
+ // 5. Try parsing both fields as ints.
+ match (from_str::<int>(a), from_str::<int>(b)) {
+
+ // 6. If parsing succeeded for both, push both.
+ (Some(a), Some(b)) => pairs.push((a,b)),
+ // 7. Ignore non-int fields.
+ _ => ()
+ }
+ }
+ // 8. Ignore lines that don't have 2 fields.
+ _ => ()
+ }
+ }
+ pairs
+}
+~~~~
+
+This example shows the use of `Option`,
+along with some other forms of error-handling (and non-handling).
+We will look at these mechanisms
+and then modify parts of the example to perform "better" error handling.
+
+# Options
+
+The simplest and most lightweight mechanism in Rust for indicating an error is the type `std::option::Option<T>`.
+This type is a general purpose `enum`
+for conveying a value of type `T`, represented as `Some(T)`
+_or_ the sentinel `None`, to indicate the absence of a `T` value.
+For simple APIs, it may be sufficient to encode errors as `Option<T>`,
+returning `Some(T)` on success and `None` on error.
+In the example program, the call to `from_str::<int>` returns `Option<int>`
+with the understanding that "all parse errors" result in `None`.
+The resulting `Option<int>` values are matched against the pattern `(Some(a), Some(b))`
+in steps 5 and 6 in the example program,
+to handle the case in which both fields were parsed successfully.
+
+Using `Option` as in this API has some advantages:
+
+ - Simple API, users can read it and guess how it works.
+ - Very efficient, only an extra `enum` tag on return values.
+ - Caller has flexibility in handling or propagating errors.
+ - Caller is forced to acknowledge existence of possible-error before using value.
+
+However, it has serious disadvantages too:
+
+ - Verbose, requires matching results or calling `Option::unwrap` everywhere.
+ - Infects caller: if caller doesn't know how to handle the error, must propagate (or force).
+ - Temptation to do just that: force the `Some(T)` case by blindly calling `unwrap`,
+ which hides the error from the API without providing any way to make the program robust against the error.
+ - Collapses all errors into one:
+ - Caller can't handle different errors differently.
+ - Caller can't even report a very precise error message
+
+Note that in order to keep the example code reasonably compact,
+several unwanted cases are silently ignored:
+lines that do not contain two fields, as well as fields that do not parse as ints.
+To propagate these cases to the caller using `Option` would require even more verbose code.
+
+# Results
+
+Before getting into _trapping_ the error,
+we will look at a slight refinement on the `Option` type above.
+This second mechanism for indicating an error is called a `Result`.
+The type `std::result::Result<T,E>` is another simple `enum` type with two forms, `Ok(T)` and `Err(E)`.
+The `Result` type is not substantially different from the `Option` type in terms of its ergonomics.
+Its main advantage is that the error constructor `Err(E)` can convey _more detail_ about the error.
+For example, the `from_str` API could be reformed
+to return a `Result` carrying an informative description of a parse error,
+like this:
+
+~~~~ {.ignore}
+enum IntParseErr {
+ EmptyInput,
+ Overflow,
+ BadChar(char)
+}
+
+fn from_str(&str) -> Result<int,IntParseErr> {
+ // ...
+}
+~~~~
+
+This would give the caller more information for both handling and reporting the error,
+but would otherwise retain the verbosity problems of using `Option`.
+In particular, it would still be necessary for the caller to return a further `Result` to _its_ caller if it did not want to handle the error.
+Manually propagating result values this way can be attractive in certain circumstances
+— for example when processing must halt on the very first error, or backtrack —
+but as we will see later, many cases have simpler options available.
+
+# Failure
+
+The third and arguably easiest mechanism for handling errors is called "failure".
+In fact it was hinted at earlier by suggesting that one can choose to propagate `Option` or `Result` types _or "force" them_.
+"Forcing" them, in this case, means calling a method like `Option<T>::unwrap`,
+which contains the following code:
+
+~~~~ {.ignore}
+pub fn unwrap(self) -> T {
+ match self {
+ Some(x) => return x,
+ None => fail!("option::unwrap `None`")
+ }
+}
+~~~~
+
+That is, it returns `T` when `self` is `Some(T)`, and _fails_ when `self` is `None`.
+
+Every Rust task can _fail_, either indirectly due to a kill signal or other asynchronous event,
+or directly by failing an `assert!` or calling the `fail!` macro.
+Failure is an _unrecoverable event_ at the task level:
+it causes the task to halt normal execution and unwind its control stack,
+freeing all task-local resources (the local heap as well as any task-owned values from the global heap)
+and running destructors (the `drop` method of the `Drop` trait)
+as frames are unwound and heap values destroyed.
+A failing task is not permitted to "catch" the unwinding during failure and recover,
+it is only allowed to clean up and exit.
+
+Failure has advantages:
+
+ - Simple and non-verbose. Suitable for programs that can't reasonably continue past an error anyways.
+ - _All_ errors (except memory-safety errors) can be uniformly trapped in a supervisory task outside the failing task.
+ For a large program to be robust against a variety of errors,
+ often some form of task-level partitioning to contain pervasive errors (arithmetic overflow, division by zero,
+ logic bugs) is necessary anyways.
+
+As well as obvious disadvantages:
+
+ - A blunt instrument, terminates the containing task entirely.
+
+Recall that in the first two approaches to error handling,
+the example program was only handling success cases, and ignoring error cases.
+That is, if the input is changed to contain a malformed line:
+
+~~~~ {.notrust}
+$ cat bad.txt
+1 2
+34 56
+ostrich
+789 123
+45 67
+~~~~
+
+Then the program would give the same output as if there was no error:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+If the example is rewritten to use failure, these error cases can be trapped.
+In this rewriting, failures are trapped by placing the I/O logic in a sub-task,
+and trapping its exit status using `task::try`:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+use std::task;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+fn main() {
+
+ // Isolate failure within a subtask.
+ let result = do task::try {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+
+ };
+ if result.is_err() {
+ println("parsing failed");
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
+
+ // Explicitly fail on malformed lines.
+ _ => fail!()
+ }
+ }
+ pairs
+}
+~~~~
+
+With these changes in place, running the program on malformed input gives a different answer:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+rust: task failed at 'explicit failure', ./example.rs:44
+parsing failed
+~~~~
+
+Note that while failure unwinds the sub-task performing I/O in `read_int_pairs`,
+control returns to `main` and can easily continue uninterrupted.
+In this case, control simply prints out `parsing failed` and then exits `main` (successfully).
+Failure of a (sub-)task is analogous to calling `exit(1)` or `abort()` in a unix C program:
+all the state of a sub-task is cleanly discarded on exit,
+and a supervisor task can take appropriate action
+without worrying about its own state having been corrupted.
+
+# Conditions
+
+The final mechanism for handling errors is called a "condition".
+Conditions are less blunt than failure, and less cumbersome than the `Option` or `Result` types;
+indeed they are designed to strike just the right balance between the two.
+Conditions require some care to use effectively, but give maximum flexibility with minimum verbosity.
+While conditions use exception-like terminology ("trap", "raise") they are significantly different:
+
+ - Like exceptions and failure, conditions separate the site at which the error is raised from the site where it is trapped.
+ - Unlike exceptions and unlike failure, when a condition is raised and trapped, _no unwinding occurs_.
+ - A successfully trapped condition causes execution to continue _at the site of the error_, as though no error occurred.
+
+Conditions are declared with the `condition!` macro.
+Each condition has a name, an input type and an output type, much like a function.
+In fact, conditions are implemented as dynamically-scoped functions held in task local storage.
+
+The `condition!` macro declares a module with the name of the condition;
+the module contains a single static value called `cond`, of type `std::condition::Condition`.
+The `cond` value within the module is the rendezvous point
+between the site of error and the site that handles the error.
+It has two methods of interest: `raise` and `trap`.
+
+The `raise` method maps a value of the condition's input type to its output type.
+The input type should therefore convey all relevant information to the condition handler.
+The output type should convey all relevant information _for continuing execution at the site of error_.
+When the error site raises a condition handler,
+the `Condition::raise` method searches for the innermost installed task-local condition _handler_,
+and if any such handler is found, calls it with the provided input value.
+If no handler is found, `Condition::raise` will fail the task with an appropriate error message.
+
+Rewriting the example to use a condition in place of ignoring malformed lines makes it slightly longer,
+but similarly clear as the version that used `fail!` in the logic where the error occurs:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+// Introduce a new condition.
+condition! {
+ pub malformed_line : ~str -> (int,int);
+}
+
+fn main() {
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
+ // On malformed lines, call the condition handler and
+ // push whatever the condition handler returns.
+ _ => pairs.push(malformed_line::cond.raise(line.clone()))
+ }
+ }
+ pairs
+}
+~~~~
+
+When this is run on malformed input, it still fails,
+but with a slightly different failure message than before:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+rust: task failed at 'Unhandled condition: malformed_line: ~"ostrich"', .../libstd/condition.rs:43
+~~~~
+
+While this superficially resembles the trapped `fail!` call before,
+it is only because the example did not install a handler for the condition.
+The different failure message is indicating, among other things,
+that the condition-handling system is being invoked and failing
+only due to the absence of a _handler_ that traps the condition.
+
+# Trapping a condition
+
+To trap a condition, use `Condition::trap` in some caller of the site that calls `Condition::raise`.
+For example, this version of the program traps the `malformed_line` condition
+and replaces bad input lines with the pair `(-1,-1)`:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+condition! {
+ pub malformed_line : ~str -> (int,int);
+}
+
+fn main() {
+ // Trap the condition:
+ malformed_line::cond.trap(|_| (-1,-1)).inside(|| {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+
+ })
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
+ _ => pairs.push(malformed_line::cond.raise(line.clone()))
+ }
+ }
+ pairs
+}
+~~~~
+
+Note that the remainder of the program is _unchanged_ with this trap in place;
+only the caller that installs the trap changed.
+Yet when the condition-trapping variant runs on the malformed input,
+it continues execution past the malformed line, substituting the handler's return value.
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+-0001, -0001
+0789, 0123
+0045, 0067
+~~~~
+
+# Refining a condition
+
+As you work with a condition, you may find that the original set of options you present for recovery is insufficient.
+This is no different than any other issue of API design:
+a condition handler is an API for recovering from the condition, and sometimes APIs need to be enriched.
+In the example program, the first form of the `malformed_line` API implicitly assumes that recovery involves a substitute value.
+This assumption may not be correct; some callers may wish to skip malformed lines, for example.
+Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+// Modify the condition signature to return an Option.
+condition! {
+ pub malformed_line : ~str -> Option<(int,int)>;
+}
+
+fn main() {
+ // Trap the condition and return `None`
+ malformed_line::cond.trap(|_| None).inside(|| {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+
+ })
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
+
+ // On malformed lines, call the condition handler and
+ // either ignore the line (if the handler returns `None`)
+ // or push any `Some(pair)` value returned instead.
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ Some(pair) => pairs.push(pair),
+ None => ()
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Again, note that the remainder of the program is _unchanged_,
+in particular the signature of `read_int_pairs` is unchanged,
+even though the innermost part of its reading-loop has a new way of handling a malformed line.
+When the example is run with the `None` trap in place,
+the line is ignored as it was in the first example,
+but the choice of whether to ignore or use a substitute value has been moved to some caller,
+possibly a distant caller.
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+# Further refining a condition
+
+Like with any API, the process of refining argument and return types of a condition will continue,
+until all relevant combinations encountered in practice are encoded.
+In the example, suppose a third possible recovery form arose: reusing the previous value read.
+This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`.
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+// Introduce a new enum to convey condition-handling strategy to error site.
+pub enum MalformedLineFix {
+ UsePair(int,int),
+ IgnoreLine,
+ UsePreviousLine
+}
+
+// Modify the condition signature to return the new enum.
+// Note: a condition introduces a new module, so the enum must be
+// named with the `super::` prefix to access it.
+condition! {
+ pub malformed_line : ~str -> super::MalformedLineFix;
+}
+
+fn main() {
+ // Trap the condition and return `UsePreviousLine`
+ malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+
+ })
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
+
+ // On malformed lines, call the condition handler and
+ // take action appropriate to the enum value returned.
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ UsePair(a,b) => pairs.push((a,b)),
+ IgnoreLine => (),
+ UsePreviousLine => {
+ let prev = pairs[pairs.len() - 1];
+ pairs.push(prev)
+ }
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Running the example with `UsePreviousLine` as the fix code returned from the handler
+gives the expected result:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0034, 0056
+0789, 0123
+0045, 0067
+~~~~
+
+At this point the example has a rich variety of recovery options,
+none of which is visible to casual users of the `read_int_pairs` function.
+This is intentional: part of the purpose of using a condition
+is to free intermediate callers from the burden of having to write repetitive error-propagation logic,
+and/or having to change function call and return types as error-handling strategies are refined.
+
+# Multiple conditions, intermediate callers
+
+So far the function trapping the condition and the function raising it have been immediately adjacent in the call stack.
+That is, the caller traps and its immediate callee raises.
+In most programs, the function that traps may be separated by very many function calls from the function that raises.
+Again, this is part of the point of using conditions:
+to support that separation without having to thread multiple error values and recovery strategies all the way through the program's main logic.
+
+Careful readers will notice that there is a remaining failure mode in the example program: the call to `.unwrap()` when parsing each integer.
+For example, when presented with a file that has the correct number of fields on a line,
+but a non-numeric value in one of them, such as this:
+
+~~~~ {.notrust}
+$ cat bad.txt
+1 2
+34 56
+7 marmot
+789 123
+45 67
+~~~~
+
+
+Then the program fails once more:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+task <unnamed> failed at 'called `Option::unwrap()` on a `None` value', .../libstd/option.rs:314
+~~~~
+
+To make the program robust — or at least flexible — in the face of this potential failure,
+a second condition and a helper function will suffice:
+
+~~~~
+# #[allow(unused_imports)];
+# extern mod extra;
+use std::io::buffered::BufferedReader;
+use std::io::File;
+# mod BufferedReader {
+# use std::io::File;
+# use std::io::mem::MemReader;
+# use std::io::buffered::BufferedReader;
+# static s : &'static [u8] = bytes!("1 2\n\
+# 34 56\n\
+# 789 123\n\
+# 45 67\n\
+# ");
+# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
+# BufferedReader::new(MemReader::new(s.to_owned()))
+# }
+# }
+
+pub enum MalformedLineFix {
+ UsePair(int,int),
+ IgnoreLine,
+ UsePreviousLine
+}
+
+condition! {
+ pub malformed_line : ~str -> ::MalformedLineFix;
+}
+
+// Introduce a second condition.
+condition! {
+ pub malformed_int : ~str -> int;
+}
+
+fn main() {
+ // Trap the `malformed_int` condition and return -1
+ malformed_int::cond.trap(|_| -1).inside(|| {
+
+ // Trap the `malformed_line` condition and return `UsePreviousLine`
+ malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {
+
+ // The protected logic.
+ let pairs = read_int_pairs();
+ for &(a,b) in pairs.iter() {
+ println!("{:4.4d}, {:4.4d}", a, b);
+ }
+
+ })
+ })
+}
+
+// Parse an int; if parsing fails, call the condition handler and
+// return whatever it returns.
+fn parse_int(x: &str) -> int {
+ match from_str::<int>(x) {
+ Some(v) => v,
+ None => malformed_int::cond.raise(x.to_owned())
+ }
+}
+
+fn read_int_pairs() -> ~[(int,int)] {
+ let mut pairs = ~[];
+# let _g = std::io::ignore_io_error();
+ let path = Path::new(&"foo.txt");
+
+ let mut reader = BufferedReader::new(File::open(&path));
+ for line in reader.lines() {
+ match line.words().to_owned_vec() {
+ // Delegate parsing ints to helper function that will
+ // handle parse errors by calling `malformed_int`.
+ [a, b] => pairs.push((parse_int(a), parse_int(b))),
+
+ _ => {
+ match malformed_line::cond.raise(line.clone()) {
+ UsePair(a,b) => pairs.push((a,b)),
+ IgnoreLine => (),
+ UsePreviousLine => {
+ let prev = pairs[pairs.len() - 1];
+ pairs.push(prev)
+ }
+ }
+ }
+ }
+ }
+ pairs
+}
+~~~~
+
+Again, note that `read_int_pairs` has not changed signature,
+nor has any of the machinery for trapping or raising `malformed_line`,
+but now the program can handle the "right number of fields, non-integral field" form of bad input:
+
+~~~~ {.notrust}
+$ ./example bad.txt
+0001, 0002
+0034, 0056
+0007, -0001
+0789, 0123
+0045, 0067
+~~~~
+
+There are three other things to note in this variant of the example program:
+
+ - It traps multiple conditions simultaneously,
+ nesting the protected logic of one `trap` call inside the other.
+
+ - There is a function in between the `trap` site and `raise` site for the `malformed_int` condition.
+ There could be any number of calls between them:
+ so long as the `raise` occurs within a callee (of any depth) of the logic protected by the `trap` call,
+ it will invoke the handler.
+
+ - This variant insulates callers from a design choice in the library:
+ the `from_str` function was designed to return an `Option<int>`,
+ but this program insulates callers from that choice,
+ routing all `None` values that arise from parsing integers in this file into the condition.
+
+
+# When to use which technique
+
+This guide explored several techniques for handling errors.
+Each is appropriate to different circumstances:
+
+ - If an error may be extremely frequent, expected, and very likely dealt with by an immediate caller,
+ then returning an `Option` or `Result` type is best. These types force the caller to handle the error,
+ and incur the lowest speed overhead, usually only returning one extra word to tag the return value.
+ Between `Option` and `Result`: use an `Option` when there is only one kind of error,
+ otherwise make an `enum FooErr` to represent the possible error codes and use `Result<T,FooErr>`.
+
+ - If an error can reasonably be handled at the site it occurs by one of a few strategies — possibly including failure —
+ and it is not clear which strategy a caller would want to use, a condition is best.
+ For many errors, the only reasonable "non-stop" recovery strategies are to retry some number of times,
+ create or substitute an empty or sentinel value, ignore the error, or fail.
+
+ - If an error cannot reasonably be handled at the site it occurs,
+ and the only reasonable response is to abandon a large set of operations in progress,
+ then directly failing is best.
+
+Note that an unhandled condition will cause failure (along with a more-informative-than-usual message),
+so if there is any possibility that a caller might wish to "ignore and keep going",
+it is usually harmless to use a condition in place of a direct call to `fail!()`.
+
+
+[^why-no-exceptions]: Exceptions in languages like C++ and Java permit unwinding, like Rust's failure system,
+but with the option to halt unwinding partway through the process and continue execution.
+This behavior unfortunately means that the _heap_ may be left in an inconsistent but accessible state,
+if an exception is thrown part way through the process of initializing or modifying memory.
+To compensate for this risk, correct C++ and Java code must program in an extremely elaborate and difficult "exception-safe" style
+— effectively transactional style against heap structures —
+or else risk introducing silent and very difficult-to-debug errors due to control resuming in a corrupted heap after a caught exception.
+These errors are frequently memory-safety errors, which Rust strives to eliminate,
+and so Rust unwinding is unrecoverable within a single task:
+once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
--- /dev/null
+% Containers and Iterators Guide
+
+# Containers
+
+The container traits are defined in the `std::container` module.
+
+## Unique vectors
+
+Vectors have `O(1)` indexing, push (to the end) and pop (from the end). Vectors
+are the most common container in Rust, and are flexible enough to fit many use
+cases.
+
+Vectors can also be sorted and used as efficient lookup tables with the
+`bsearch()` method, if all the elements are inserted at one time and
+deletions are unnecessary.
+
+## Maps and sets
+
+Maps are collections of unique keys with corresponding values, and sets are
+just unique keys without a corresponding value. The `Map` and `Set` traits in
+`std::container` define the basic interface.
+
+The standard library provides three owned map/set types:
+
+* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to
+ implement `Eq` and `Hash`
+* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint`
+* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys
+ to implement `TotalOrd`
+
+These maps do not use managed pointers so they can be sent between tasks as
+long as the key and value types are sendable. Neither the key or value type has
+to be copyable.
+
+The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
+order.
+
+Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
+making the order of a set of keys in a given hash table randomized. Rust
+provides a [SipHash](https://131002.net/siphash/) implementation for any type
+implementing the `IterBytes` trait.
+
+## Double-ended queues
+
+The `extra::ringbuf` module implements a double-ended queue with `O(1)`
+amortized inserts and removals from both ends of the container. It also has
+`O(1)` indexing like a vector. The contained elements are not required to be
+copyable, and the queue will be sendable if the contained type is sendable.
+Its interface `Deque` is defined in `extra::collections`.
+
+The `extra::dlist` module implements a double-ended linked list, also
+implementing the `Deque` trait, with `O(1)` removals and inserts at either end,
+and `O(1)` concatenation.
+
+## Priority queues
+
+The `extra::priority_queue` module implements a queue ordered by a key. The
+contained elements are not required to be copyable, and the queue will be
+sendable if the contained type is sendable.
+
+Insertions have `O(log n)` time complexity and checking or popping the largest
+element is `O(1)`. Converting a vector to a priority queue can be done
+in-place, and has `O(n)` complexity. A priority queue can also be converted to
+a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
+heapsort.
+
+# Iterators
+
+## Iteration protocol
+
+The iteration protocol is defined by the `Iterator` trait in the
+`std::iter` module. The minimal implementation of the trait is a `next`
+method, yielding the next element from an iterator object:
+
+~~~
+/// An infinite stream of zeroes
+struct ZeroStream;
+
+impl Iterator<int> for ZeroStream {
+ fn next(&mut self) -> Option<int> {
+ Some(0)
+ }
+}
+~~~~
+
+Reaching the end of the iterator is signalled by returning `None` instead of
+`Some(item)`:
+
+~~~
+# fn main() {}
+/// A stream of N zeroes
+struct ZeroStream {
+ priv remaining: uint
+}
+
+impl ZeroStream {
+ fn new(n: uint) -> ZeroStream {
+ ZeroStream { remaining: n }
+ }
+}
+
+impl Iterator<int> for ZeroStream {
+ fn next(&mut self) -> Option<int> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ Some(0)
+ }
+ }
+}
+~~~
+
+In general, you cannot rely on the behavior of the `next()` method after it has
+returned `None`. Some iterators may return `None` forever. Others may behave
+differently.
+
+## Container iterators
+
+Containers implement iteration over the contained elements by returning an
+iterator object. For example, vector slices several iterators available:
+
+* `iter()` and `rev_iter()`, for immutable references to the elements
+* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
+* `move_iter()` and `move_rev_iter()`, to move the elements out by-value
+
+A typical mutable container will implement at least `iter()`, `mut_iter()` and
+`move_iter()` along with the reverse variants if it maintains an order.
+
+### Freezing
+
+Unlike most other languages with external iterators, Rust has no *iterator
+invalidation*. As long an iterator is still in scope, the compiler will prevent
+modification of the container through another handle.
+
+~~~
+let mut xs = [1, 2, 3];
+{
+ let _it = xs.iter();
+
+ // the vector is frozen for this scope, the compiler will statically
+ // prevent modification
+}
+// the vector becomes unfrozen again at the end of the scope
+~~~
+
+These semantics are due to most container iterators being implemented with `&`
+and `&mut`.
+
+## Iterator adaptors
+
+The `Iterator` trait provides many common algorithms as default methods. For
+example, the `fold` method will accumulate the items yielded by an `Iterator`
+into a single value:
+
+~~~
+let xs = [1, 9, 2, 3, 14, 12];
+let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
+assert_eq!(result, -41);
+~~~
+
+Most adaptors return an adaptor object implementing the `Iterator` trait itself:
+
+~~~
+let xs = [1, 9, 2, 3, 14, 12];
+let ys = [5, 2, 1, 8];
+let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
+assert_eq!(sum, 57);
+~~~
+
+Some iterator adaptors may return `None` before exhausting the underlying
+iterator. Additionally, if these iterator adaptors are called again after
+returning `None`, they may call their underlying iterator again even if the
+adaptor will continue to return `None` forever. This may not be desired if the
+underlying iterator has side-effects.
+
+In order to provide a guarantee about behavior once `None` has been returned, an
+iterator adaptor named `fuse()` is provided. This returns an iterator that will
+never call its underlying iterator again once `None` has been returned:
+
+~~~
+let xs = [1,2,3,4,5];
+let mut calls = 0;
+let it = xs.iter().scan((), |_, x| {
+ calls += 1;
+ if *x < 3 { Some(x) } else { None }});
+// the iterator will only yield 1 and 2 before returning None
+// If we were to call it 5 times, calls would end up as 5, despite only 2 values
+// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
+// can fix this.
+let mut it = it.fuse();
+it.next();
+it.next();
+it.next();
+it.next();
+it.next();
+assert_eq!(calls, 3);
+~~~
+
+## For loops
+
+The function `range` (or `range_inclusive`) allows to simply iterate through a given range:
+
+~~~
+for i in range(0, 5) {
+ print!("{} ", i) // prints "0 1 2 3 4"
+}
+
+for i in std::iter::range_inclusive(0, 5) { // needs explicit import
+ print!("{} ", i) // prints "0 1 2 3 4 5"
+}
+~~~
+
+The `for` keyword can be used as sugar for iterating through any iterator:
+
+~~~
+let xs = [2u, 3, 5, 7, 11, 13, 17];
+
+// print out all the elements in the vector
+for x in xs.iter() {
+ println(x.to_str())
+}
+
+// print out all but the first 3 elements in the vector
+for x in xs.iter().skip(3) {
+ println(x.to_str())
+}
+~~~
+
+For loops are *often* used with a temporary iterator object, as above. They can
+also advance the state of an iterator in a mutable location:
+
+~~~
+let xs = [1, 2, 3, 4, 5];
+let ys = ["foo", "bar", "baz", "foobar"];
+
+// create an iterator yielding tuples of elements from both vectors
+let mut it = xs.iter().zip(ys.iter());
+
+// print out the pairs of elements up to (&3, &"baz")
+for (x, y) in it {
+ println!("{} {}", *x, *y);
+
+ if *x == 3 {
+ break;
+ }
+}
+
+// yield and print the last pair from the iterator
+println!("last: {:?}", it.next());
+
+// the iterator is now fully consumed
+assert!(it.next().is_none());
+~~~
+
+## Conversion
+
+Iterators offer generic conversion to containers with the `collect` adaptor:
+
+~~~
+let xs = [0, 1, 1, 2, 3, 5, 8];
+let ys = xs.rev_iter().skip(1).map(|&x| x * 2).collect::<~[int]>();
+assert_eq!(ys, ~[10, 6, 4, 2, 2, 0]);
+~~~
+
+The method requires a type hint for the container type, if the surrounding code
+does not provide sufficient information.
+
+Containers can provide conversion from iterators through `collect` by
+implementing the `FromIterator` trait. For example, the implementation for
+vectors is as follows:
+
+~~~ {.xfail-test}
+impl<A> FromIterator<A> for ~[A] {
+ pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
+ let (lower, _) = iterator.size_hint();
+ let mut xs = with_capacity(lower);
+ for x in iterator {
+ xs.push(x);
+ }
+ xs
+ }
+}
+~~~
+
+### Size hints
+
+The `Iterator` trait provides a `size_hint` default method, returning a lower
+bound and optionally on upper bound on the length of the iterator:
+
+~~~ {.xfail-test}
+fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
+~~~
+
+The vector implementation of `FromIterator` from above uses the lower bound
+to pre-allocate enough space to hold the minimum number of elements the
+iterator will yield.
+
+The default implementation is always correct, but it should be overridden if
+the iterator can provide better information.
+
+The `ZeroStream` from earlier can provide an exact lower and upper bound:
+
+~~~
+# fn main() {}
+/// A stream of N zeroes
+struct ZeroStream {
+ priv remaining: uint
+}
+
+impl ZeroStream {
+ fn new(n: uint) -> ZeroStream {
+ ZeroStream { remaining: n }
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ (self.remaining, Some(self.remaining))
+ }
+}
+
+impl Iterator<int> for ZeroStream {
+ fn next(&mut self) -> Option<int> {
+ if self.remaining == 0 {
+ None
+ } else {
+ self.remaining -= 1;
+ Some(0)
+ }
+ }
+}
+~~~
+
+## Double-ended iterators
+
+The `DoubleEndedIterator` trait represents an iterator able to yield elements
+from either end of a range. It inherits from the `Iterator` trait and extends
+it with the `next_back` function.
+
+A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning
+another `DoubleEndedIterator` with `next` and `next_back` exchanged.
+
+~~~
+let xs = [1, 2, 3, 4, 5, 6];
+let mut it = xs.iter();
+println!("{:?}", it.next()); // prints `Some(&1)`
+println!("{:?}", it.next()); // prints `Some(&2)`
+println!("{:?}", it.next_back()); // prints `Some(&6)`
+
+// prints `5`, `4` and `3`
+for &x in it.invert() {
+ println!("{}", x)
+}
+~~~
+
+The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted
+version of the standard immutable and mutable vector iterators.
+
+The `chain`, `map`, `filter`, `filter_map` and `inspect` adaptors are
+`DoubleEndedIterator` implementations if the underlying iterators are.
+
+~~~
+let xs = [1, 2, 3, 4];
+let ys = [5, 6, 7, 8];
+let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
+
+println!("{:?}", it.next()); // prints `Some(2)`
+
+// prints `16`, `14`, `12`, `10`, `8`, `6`, `4`
+for x in it.invert() {
+ println!("{}", x);
+}
+~~~
+
+The `reverse_` method is also available for any double-ended iterator yielding
+mutable references. It can be used to reverse a container in-place. Note that
+the trailing underscore is a workaround for issue #5898 and will be removed.
+
+~~~
+let mut ys = [1, 2, 3, 4, 5];
+ys.mut_iter().reverse_();
+assert_eq!(ys, [5, 4, 3, 2, 1]);
+~~~
+
+## Random-access iterators
+
+The `RandomAccessIterator` trait represents an iterator offering random access
+to the whole range. The `indexable` method retrieves the number of elements
+accessible with the `idx` method.
+
+The `chain` adaptor is an implementation of `RandomAccessIterator` if the
+underlying iterators are.
+
+~~~
+let xs = [1, 2, 3, 4, 5];
+let ys = ~[7, 9, 11];
+let mut it = xs.iter().chain(ys.iter());
+println!("{:?}", it.idx(0)); // prints `Some(&1)`
+println!("{:?}", it.idx(5)); // prints `Some(&7)`
+println!("{:?}", it.idx(7)); // prints `Some(&11)`
+println!("{:?}", it.idx(8)); // prints `None`
+
+// yield two elements from the beginning, and one from the end
+it.next();
+it.next();
+it.next_back();
+
+println!("{:?}", it.idx(0)); // prints `Some(&3)`
+println!("{:?}", it.idx(4)); // prints `Some(&9)`
+println!("{:?}", it.idx(6)); // prints `None`
+~~~
--- /dev/null
+% Rust Foreign Function Interface Guide
+
+# Introduction
+
+This guide will use the [snappy](https://code.google.com/p/snappy/)
+compression/decompression library as an introduction to writing bindings for
+foreign code. Rust is currently unable to call directly into a C++ library, but
+snappy includes a C interface (documented in
+[`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)).
+
+The following is a minimal example of calling a foreign function which will
+compile if snappy is installed:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+#[link(name = "snappy")]
+extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+}
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println!("max compressed length of a 100 byte buffer: {}", x);
+}
+~~~~
+
+The `extern` block is a list of function signatures in a foreign library, in
+this case with the platform's C ABI. The `#[link(...)]` attribute is used to
+instruct the linker to link against the snappy library so the symbols are
+resolved.
+
+Foreign functions are assumed to be unsafe so calls to them need to be wrapped
+with `unsafe {}` as a promise to the compiler that everything contained within
+truly is safe. C libraries often expose interfaces that aren't thread-safe, and
+almost any function that takes a pointer argument isn't valid for all possible
+inputs since the pointer could be dangling, and raw pointers fall outside of
+Rust's safe memory model.
+
+When declaring the argument types to a foreign function, the Rust compiler can
+not check if the declaration is correct, so specifying it correctly is part of
+keeping the binding correct at runtime.
+
+The `extern` block can be extended to cover the entire snappy API:
+
+~~~~ {.xfail-test}
+use std::libc::{c_int, size_t};
+
+#[link(name = "snappy")]
+extern {
+ fn snappy_compress(input: *u8,
+ input_length: size_t,
+ compressed: *mut u8,
+ compressed_length: *mut size_t) -> c_int;
+ fn snappy_uncompress(compressed: *u8,
+ compressed_length: size_t,
+ uncompressed: *mut u8,
+ uncompressed_length: *mut size_t) -> c_int;
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+ fn snappy_uncompressed_length(compressed: *u8,
+ compressed_length: size_t,
+ result: *mut size_t) -> c_int;
+ fn snappy_validate_compressed_buffer(compressed: *u8,
+ compressed_length: size_t) -> c_int;
+}
+~~~~
+
+# Creating a safe interface
+
+The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts
+like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe
+internal details.
+
+Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust
+vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
+length is number of elements currently contained, and the capacity is the total size in elements of
+the allocated memory. The length is less than or equal to the capacity.
+
+~~~~ {.xfail-test}
+pub fn validate_compressed_buffer(src: &[u8]) -> bool {
+ unsafe {
+ snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
+ }
+}
+~~~~
+
+The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
+guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
+signature.
+
+The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
+allocated to hold the output too.
+
+The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum
+required capacity to hold the compressed output. The vector can then be passed to the
+`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
+the true length after compression for setting the length.
+
+~~~~ {.xfail-test}
+pub fn compress(src: &[u8]) -> ~[u8] {
+ unsafe {
+ let srclen = src.len() as size_t;
+ let psrc = src.as_ptr();
+
+ let mut dstlen = snappy_max_compressed_length(srclen);
+ let mut dst = vec::with_capacity(dstlen as uint);
+ let pdst = dst.as_mut_ptr();
+
+ snappy_compress(psrc, srclen, pdst, &mut dstlen);
+ dst.set_len(dstlen as uint);
+ dst
+ }
+}
+~~~~
+
+Decompression is similar, because snappy stores the uncompressed size as part of the compression
+format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
+
+~~~~ {.xfail-test}
+pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
+ unsafe {
+ let srclen = src.len() as size_t;
+ let psrc = src.as_ptr();
+
+ let mut dstlen: size_t = 0;
+ snappy_uncompressed_length(psrc, srclen, &mut dstlen);
+
+ let mut dst = vec::with_capacity(dstlen as uint);
+ let pdst = dst.as_mut_ptr();
+
+ if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
+ dst.set_len(dstlen as uint);
+ Some(dst)
+ } else {
+ None // SNAPPY_INVALID_INPUT
+ }
+ }
+}
+~~~~
+
+For reference, the examples used here are also available as an [library on
+GitHub](https://github.com/thestinger/rust-snappy).
+
+# Stack management
+
+Rust tasks by default run on a "large stack". This is actually implemented as a
+reserving a large segment of the address space and then lazily mapping in pages
+as they are needed. When calling an external C function, the code is invoked on
+the same stack as the rust stack. This means that there is no extra
+stack-switching mechanism in place because it is assumed that the large stack
+for the rust task is plenty for the C function to have.
+
+A planned future improvement (net yet implemented at the time of this writing)
+is to have a guard page at the end of every rust stack. No rust function will
+hit this guard page (due to Rust's usage of LLVM's `__morestack`). The intention
+for this unmapped page is to prevent infinite recursion in C from overflowing
+onto other rust stacks. If the guard page is hit, then the process will be
+terminated with a message saying that the guard page was hit.
+
+For normal external function usage, this all means that there shouldn't be any
+need for any extra effort on a user's perspective. The C stack naturally
+interleaves with the rust stack, and it's "large enough" for both to
+interoperate. If, however, it is determined that a larger stack is necessary,
+there are appropriate functions in the task spawning API to control the size of
+the stack of the task which is spawned.
+
+# Destructors
+
+Foreign libraries often hand off ownership of resources to the calling code.
+When this occurs, we must use Rust's destructors to provide safety and guarantee
+the release of these resources (especially in the case of failure).
+
+As an example, we give a reimplementation of owned boxes by wrapping `malloc`
+and `free`:
+
+~~~~
+use std::cast;
+use std::libc::{c_void, size_t, malloc, free};
+use std::ptr;
+use std::unstable::intrinsics;
+
+// Define a wrapper around the handle returned by the foreign code.
+// Unique<T> has the same semantics as ~T
+pub struct Unique<T> {
+ // It contains a single raw, mutable pointer to the object in question.
+ priv ptr: *mut T
+}
+
+// Implement methods for creating and using the values in the box.
+// NB: For simplicity and correctness, we require that T has kind Send
+// (owned boxes relax this restriction, and can contain managed (GC) boxes).
+// This is because, as implemented, the garbage collector would not know
+// about any shared boxes stored in the malloc'd region of memory.
+impl<T: Send> Unique<T> {
+ pub fn new(value: T) -> Unique<T> {
+ unsafe {
+ let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
+ assert!(!ptr::is_null(ptr));
+ // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
+ // move_val_init moves a value into this memory without
+ // attempting to drop the original value.
+ intrinsics::move_val_init(&mut *ptr, value);
+ Unique{ptr: ptr}
+ }
+ }
+
+ // the 'r lifetime results in the same semantics as `&*x` with ~T
+ pub fn borrow<'r>(&'r self) -> &'r T {
+ unsafe { cast::copy_lifetime(self, &*self.ptr) }
+ }
+
+ // the 'r lifetime results in the same semantics as `&mut *x` with ~T
+ pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
+ unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }
+ }
+}
+
+// The key ingredient for safety, we associate a destructor with
+// Unique<T>, making the struct manage the raw pointer: when the
+// struct goes out of scope, it will automatically free the raw pointer.
+// NB: This is an unsafe destructor, because rustc will not normally
+// allow destructors to be associated with parametrized types, due to
+// bad interaction with managed boxes. (With the Send restriction,
+// we don't have this problem.)
+#[unsafe_destructor]
+impl<T: Send> Drop for Unique<T> {
+ fn drop(&mut self) {
+ unsafe {
+ let x = intrinsics::uninit(); // dummy value to swap in
+ // We need to move the object out of the box, so that
+ // the destructor is called (at the end of this scope.)
+ ptr::replace_ptr(self.ptr, x);
+ free(self.ptr as *c_void)
+ }
+ }
+}
+
+// A comparison between the built-in ~ and this reimplementation
+fn main() {
+ {
+ let mut x = ~5;
+ *x = 10;
+ } // `x` is freed here
+
+ {
+ let mut y = Unique::new(5);
+ *y.borrow_mut() = 10;
+ } // `y` is freed here
+}
+~~~~
+
+# Linking
+
+The `link` attribute on `extern` blocks provides the basic building block for
+instructing rustc how it will link to native libraries. There are two accepted
+forms of the link attribute today:
+
+* `#[link(name = "foo")]`
+* `#[link(name = "foo", kind = "bar")]`
+
+In both of these cases, `foo` is the name of the native library that we're
+linking to, and in the second case `bar` is the type of native library that the
+compiler is linking to. There are currently three known types of native
+libraries:
+
+* Dynamic - `#[link(name = "readline")]
+* Static - `#[link(name = "my_build_dependency", kind = "static")]
+* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]
+
+Note that frameworks are only available on OSX targets.
+
+The different `kind` values are meant to differentiate how the native library
+participates in linkage. From a linkage perspective, the rust compiler creates
+two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
+Native dynamic libraries and frameworks are propagated to the final artifact
+boundary, while static libraries are not propagated at all.
+
+A few examples of how this model can be used are:
+
+* A native build dependency. Sometimes some C/C++ glue is needed when writing
+ some rust code, but distribution of the C/C++ code in a library format is just
+ a burden. In this case, the code will be archived into `libfoo.a` and then the
+ rust crate would declare a dependency via `#[link(name = "foo", kind =
+ "static")]`.
+
+ Regardless of the flavor of output for the crate, the native static library
+ will be included in the output, meaning that distribution of the native static
+ library is not necessary.
+
+* A normal dynamic dependency. Common system libraries (like `readline`) are
+ available on a large number of systems, and often a static copy of these
+ libraries cannot be found. When this dependency is included in a rust crate,
+ partial targets (like rlibs) will not link to the library, but when the rlib
+ is included in a final target (like a binary), the native library will be
+ linked in.
+
+On OSX, frameworks behave with the same semantics as a dynamic library.
+
+## The `link_args` attribute
+
+There is one other way to tell rustc how to customize linking, and that is via
+the `link_args` attribute. This attribute is applied to `extern` blocks and
+specifies raw flags which need to get passed to the linker when producing an
+artifact. An example usage would be:
+
+~~~ {.xfail-test}
+#[link_args = "-foo -bar -baz"]
+extern {}
+~~~
+
+Note that this feature is currently hidden behind the `feature(link_args)` gate
+because this is not a sanctioned way of performing linking. Right now rustc
+shells out to the system linker, so it makes sense to provide extra command line
+arguments, but this will not always be the case. In the future rustc may use
+LLVM directly to link native libraries in which case `link_args` will have no
+meaning.
+
+It is highly recommended to *not* use this attribute, and rather use the more
+formal `#[link(...)]` attribute on `extern` blocks instead.
+
+# Unsafe blocks
+
+Some operations, like dereferencing unsafe pointers or calling functions that have been marked
+unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
+the compiler that the unsafety does not leak out of the block.
+
+Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
+this:
+
+~~~~
+unsafe fn kaboom(ptr: *int) -> int { *ptr }
+~~~~
+
+This function can only be called from an `unsafe` block or another `unsafe` function.
+
+# Accessing foreign globals
+
+Foreign APIs often export a global variable which could do something like track
+global state. In order to access these variables, you declare them in `extern`
+blocks with the `static` keyword:
+
+~~~{.xfail-test}
+use std::libc;
+
+#[link(name = "readline")]
+extern {
+ static rl_readline_version: libc::c_int;
+}
+
+fn main() {
+ println!("You have readline version {} installed.",
+ rl_readline_version as int);
+}
+~~~
+
+Alternatively, you may need to alter global state provided by a foreign
+interface. To do this, statics can be declared with `mut` so rust can mutate
+them.
+
+~~~{.xfail-test}
+use std::libc;
+use std::ptr;
+
+#[link(name = "readline")]
+extern {
+ static mut rl_prompt: *libc::c_char;
+}
+
+fn main() {
+ do "[my-awesome-shell] $".as_c_str |buf| {
+ unsafe { rl_prompt = buf; }
+ // get a line, process it
+ unsafe { rl_prompt = ptr::null(); }
+ }
+}
+~~~
+
+# Foreign calling conventions
+
+Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
+calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
+conventions. Rust provides a way to tell the compiler which convention to use:
+
+~~~~
+#[cfg(target_os = "win32", target_arch = "x86")]
+#[link_name = "kernel32"]
+extern "stdcall" {
+ fn SetEnvironmentVariableA(n: *u8, v: *u8) -> std::libc::c_int;
+}
+~~~~
+
+This applies to the entire `extern` block. The list of supported ABI constraints
+are:
+
+* `stdcall`
+* `aapcs`
+* `cdecl`
+* `fastcall`
+* `Rust`
+* `rust-intrinsic`
+* `system`
+* `C`
+
+Most of the abis in this list are self-explanatory, but the `system` abi may
+seem a little odd. This constraint selects whatever the appropriate ABI is for
+interoperating with the target's libraries. For example, on win32 with a x86
+architecture, this means that the abi used would be `stdcall`. On x86_64,
+however, windows uses the `C` calling convention, so `C` would be used. This
+means that in our previous example, we could have used `extern "system" { ... }`
+to define a block for all windows systems, not just x86 ones.
+
+# Interoperability with foreign code
+
+Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
+A `#[packed]` attribute is available, which will lay out the struct members without padding.
+However, there are currently no guarantees about the layout of an `enum`.
+
+Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
+object. However, they should not be manually created because they are managed by internal
+allocators. Borrowed pointers can safely be assumed to be non-nullable pointers directly to the
+type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so
+prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions
+about them.
+
+Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
+`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a
+NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function.
+
+The standard library includes type aliases and function definitions for the C standard library in
+the `libc` module, and Rust links against `libc` and `libm` by default.
--- /dev/null
+% Rust Macros Guide
+
+# Introduction
+
+Functions are the primary tool that programmers can use to build abstractions.
+Sometimes, however, programmers want to abstract over compile-time syntax
+rather than run-time values.
+Macros provide syntactic abstraction.
+For an example of how this can be useful, consider the following two code fragments,
+which both pattern-match on their input and both return early in one case,
+doing nothing otherwise:
+
+~~~~
+# enum t { special_a(uint), special_b(uint) };
+# fn f() -> uint {
+# let input_1 = special_a(0);
+# let input_2 = special_a(0);
+match input_1 {
+ special_a(x) => { return x; }
+ _ => {}
+}
+// ...
+match input_2 {
+ special_b(x) => { return x; }
+ _ => {}
+}
+# return 0u;
+# }
+~~~~
+
+This code could become tiresome if repeated many times.
+However, no function can capture its functionality to make it possible
+to abstract the repetition away.
+Rust's macro system, however, can eliminate the repetition. Macros are
+lightweight custom syntax extensions, themselves defined using the
+`macro_rules!` syntax extension. The following `early_return` macro captures
+the pattern in the above code:
+
+~~~~
+# enum t { special_a(uint), special_b(uint) };
+# fn f() -> uint {
+# let input_1 = special_a(0);
+# let input_2 = special_a(0);
+macro_rules! early_return(
+ ($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`
+ match $inp {
+ $sp(x) => { return x; }
+ _ => {}
+ }
+ );
+)
+// ...
+early_return!(input_1 special_a);
+// ...
+early_return!(input_2 special_b);
+# return 0;
+# }
+~~~~
+
+Macros are defined in pattern-matching style: in the above example, the text
+`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
+*macro invocation syntax*, a pattern denoting how to write a call to the
+macro. The text on the right-hand side of the `=>`, beginning with `match
+$inp`, is the *macro transcription syntax*: what the macro expands to.
+
+# Invocation syntax
+
+The macro invocation syntax specifies the syntax for the arguments to the
+macro. It appears on the left-hand side of the `=>` in a macro definition. It
+conforms to the following rules:
+
+1. It must be surrounded by parentheses.
+2. `$` has special meaning (described below).
+3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
+forbidden.
+
+Otherwise, the invocation syntax is free-form.
+
+To take as an argument a fragment of Rust code, write `$` followed by a name
+ (for use on the right-hand side), followed by a `:`, followed by a *fragment
+ specifier*. The fragment specifier denotes the sort of fragment to match. The
+ most common fragment specifiers are:
+
+* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`,
+ `foo`.)
+* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
+ `f(42)`.)
+* `ty` (a type. Examples: `int`, `~[(char, ~str)]`, `&T`.)
+* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
+ a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
+* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
+
+The parser interprets any token that's not preceded by a `$` literally. Rust's usual
+rules of tokenization apply,
+
+So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
+that could be invoked like: `my_macro!(i->(( 2+2 )))`.
+
+## Invocation location
+
+A macro invocation may take the place of (and therefore expand to)
+an expression, an item, or a statement.
+The Rust parser will parse the macro invocation as a "placeholder"
+for whichever of those three nonterminals is appropriate for the location.
+
+At expansion time, the output of the macro will be parsed as whichever of the
+three nonterminals it stands in for. This means that a single macro might,
+for example, expand to an item or an expression, depending on its arguments
+(and cause a syntax error if it is called with the wrong argument for its
+location). Although this behavior sounds excessively dynamic, it is known to
+be useful under some circumstances.
+
+
+# Transcription syntax
+
+The right-hand side of the `=>` follows the same rules as the left-hand side,
+except that a `$` need only be followed by the name of the syntactic fragment
+to transcribe into the macro expansion; its type need not be repeated.
+
+The right-hand side must be enclosed by delimiters, which the transcriber ignores.
+Therefore `() => ((1,2,3))` is a macro that expands to a tuple expression,
+`() => (let $x=$val)` is a macro that expands to a statement,
+and `() => (1,2,3)` is a macro that expands to a syntax error
+(since the transcriber interprets the parentheses on the right-hand-size as delimiters,
+and `1,2,3` is not a valid Rust expression on its own).
+
+Except for permissibility of `$name` (and `$(...)*`, discussed below), the
+right-hand side of a macro definition is ordinary Rust syntax. In particular,
+macro invocations (including invocations of the macro currently being defined)
+are permitted in expression, statement, and item locations. However, nothing
+else about the code is examined or executed by the macro system; execution
+still has to wait until run-time.
+
+## Interpolation location
+
+The interpolation `$argument_name` may appear in any location consistent with
+its fragment specifier (i.e., if it is specified as `ident`, it may be used
+anywhere an identifier is permitted).
+
+# Multiplicity
+
+## Invocation
+
+Going back to the motivating example, recall that `early_return` expanded into
+a `match` that would `return` if the `match`'s scrutinee matched the
+"special case" identifier provided as the second argument to `early_return`,
+and do nothing otherwise. Now suppose that we wanted to write a
+version of `early_return` that could handle a variable number of "special"
+cases.
+
+The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition
+accepts zero or more occurrences of its contents. It works much
+like the `*` operator in regular expressions. It also supports a
+separator token (a comma-separated list could be written `$(...),*`), and `+`
+instead of `*` to mean "at least one".
+
+~~~~
+# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};
+# fn f() -> uint {
+# let input_1 = special_a(0);
+# let input_2 = special_a(0);
+macro_rules! early_return(
+ ($inp:expr, [ $($sp:ident)|+ ]) => (
+ match $inp {
+ $(
+ $sp(x) => { return x; }
+ )+
+ _ => {}
+ }
+ );
+)
+// ...
+early_return!(input_1, [special_a|special_c|special_d]);
+// ...
+early_return!(input_2, [special_b]);
+# return 0;
+# }
+~~~~
+
+### Transcription
+
+As the above example demonstrates, `$(...)*` is also valid on the right-hand
+side of a macro definition. The behavior of `*` in transcription,
+especially in cases where multiple `*`s are nested, and multiple different
+names are involved, can seem somewhat magical and intuitive at first. The
+system that interprets them is called "Macro By Example". The two rules to
+keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer"
+of repetitions for all of the `$name`s it contains in lockstep, and (2) each
+`$name` must be under at least as many `$(...)*`s as it was matched against.
+If it is under more, it'll be repeated, as appropriate.
+
+## Parsing limitations
+
+
+For technical reasons, there are two limitations to the treatment of syntax
+fragments by the macro parser:
+
+1. The parser will always parse as much as possible of a Rust syntactic
+fragment. For example, if the comma were omitted from the syntax of
+`early_return!` above, `input_1 [` would've been interpreted as the beginning
+of an array index. In fact, invoking the macro would have been impossible.
+2. The parser must have eliminated all ambiguity by the time it reaches a
+`$name:fragment_specifier` declaration. This limitation can result in parse
+errors when declarations occur at the beginning of, or immediately after,
+a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to
+parse because the parser would be forced to choose between parsing `t` and
+parsing `e`. Changing the invocation syntax to require a distinctive token in
+front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`
+solves the problem.
+
+# Macro argument pattern matching
+
+## Motivation
+
+Now consider code like the following:
+
+~~~~
+# enum t1 { good_1(t2, uint), bad_1 };
+# struct t2 { body: t3 }
+# enum t3 { good_2(uint), bad_2};
+# fn f(x: t1) -> uint {
+match x {
+ good_1(g1, val) => {
+ match g1.body {
+ good_2(result) => {
+ // complicated stuff goes here
+ return result + val;
+ },
+ _ => fail!("Didn't get good_2")
+ }
+ }
+ _ => return 0 // default value
+}
+# }
+~~~~
+
+All the complicated stuff is deeply indented, and the error-handling code is
+separated from matches that fail. We'd like to write a macro that performs
+a match, but with a syntax that suits the problem better. The following macro
+can solve the problem:
+
+~~~~
+macro_rules! biased_match (
+ // special case: `let (x) = ...` is illegal, so use `let x = ...` instead
+ ( ($e:expr) ~ ($p:pat) else $err:stmt ;
+ binds $bind_res:ident
+ ) => (
+ let $bind_res = match $e {
+ $p => ( $bind_res ),
+ _ => { $err }
+ };
+ );
+ // more than one name; use a tuple
+ ( ($e:expr) ~ ($p:pat) else $err:stmt ;
+ binds $( $bind_res:ident ),*
+ ) => (
+ let ( $( $bind_res ),* ) = match $e {
+ $p => ( $( $bind_res ),* ),
+ _ => { $err }
+ };
+ )
+)
+
+# enum t1 { good_1(t2, uint), bad_1 };
+# struct t2 { body: t3 }
+# enum t3 { good_2(uint), bad_2};
+# fn f(x: t1) -> uint {
+biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
+ binds g1, val )
+biased_match!((g1.body) ~ (good_2(result) )
+ else { fail!("Didn't get good_2") };
+ binds result )
+// complicated stuff goes here
+return result + val;
+# }
+~~~~
+
+This solves the indentation problem. But if we have a lot of chained matches
+like this, we might prefer to write a single macro invocation. The input
+pattern we want is clear:
+~~~~
+# macro_rules! b(
+ ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
+ binds $( $bind_res:ident ),*
+ )
+# => (0))
+~~~~
+
+However, it's not possible to directly expand to nested match statements. But
+there is a solution.
+
+## The recursive approach to macro writing
+
+A macro may accept multiple different input grammars. The first one to
+successfully match the actual argument to a macro invocation is the one that
+"wins".
+
+In the case of the example above, we want to write a recursive macro to
+process the semicolon-terminated lines, one-by-one. So, we want the following
+input patterns:
+
+~~~~
+# macro_rules! b(
+ ( binds $( $bind_res:ident ),* )
+# => (0))
+~~~~
+...and:
+
+~~~~
+# macro_rules! b(
+ ( ($e :expr) ~ ($p :pat) else $err :stmt ;
+ $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
+ binds $( $bind_res:ident ),*
+ )
+# => (0))
+~~~~
+
+The resulting macro looks like this. Note that the separation into
+`biased_match!` and `biased_match_rec!` occurs only because we have an outer
+piece of syntax (the `let`) which we only want to transcribe once.
+
+~~~~
+
+macro_rules! biased_match_rec (
+ // Handle the first layer
+ ( ($e :expr) ~ ($p :pat) else $err :stmt ;
+ $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
+ binds $( $bind_res:ident ),*
+ ) => (
+ match $e {
+ $p => {
+ // Recursively handle the next layer
+ biased_match_rec!($( ($e_rest) ~ ($p_rest) else $err_rest ; )*
+ binds $( $bind_res ),*
+ )
+ }
+ _ => { $err }
+ }
+ );
+ ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
+)
+
+// Wrap the whole thing in a `let`.
+macro_rules! biased_match (
+ // special case: `let (x) = ...` is illegal, so use `let x = ...` instead
+ ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
+ binds $bind_res:ident
+ ) => (
+ let ( $( $bind_res ),* ) = biased_match_rec!(
+ $( ($e) ~ ($p) else $err ; )*
+ binds $bind_res
+ );
+ );
+ // more than one name: use a tuple
+ ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
+ binds $( $bind_res:ident ),*
+ ) => (
+ let ( $( $bind_res ),* ) = biased_match_rec!(
+ $( ($e) ~ ($p) else $err ; )*
+ binds $( $bind_res ),*
+ );
+ )
+)
+
+
+# enum t1 { good_1(t2, uint), bad_1 };
+# struct t2 { body: t3 }
+# enum t3 { good_2(uint), bad_2};
+# fn f(x: t1) -> uint {
+biased_match!(
+ (x) ~ (good_1(g1, val)) else { return 0 };
+ (g1.body) ~ (good_2(result) ) else { fail!("Didn't get good_2") };
+ binds val, result )
+// complicated stuff goes here
+return result + val;
+# }
+~~~~
+
+This technique applies to many cases where transcribing a result all at once is not possible.
+The resulting code resembles ordinary functional programming in some respects,
+but has some important differences from functional programming.
+
+The first difference is important, but also easy to forget: the transcription
+(right-hand) side of a `macro_rules!` rule is literal syntax, which can only
+be executed at run-time. If a piece of transcription syntax does not itself
+appear inside another macro invocation, it will become part of the final
+program. If it is inside a macro invocation (for example, the recursive
+invocation of `biased_match_rec!`), it does have the opportunity to affect
+transcription, but only through the process of attempted pattern matching.
+
+The second, related, difference is that the evaluation order of macros feels
+"backwards" compared to ordinary programming. Given an invocation
+`m1!(m2!())`, the expander first expands `m1!`, giving it as input the literal
+syntax `m2!()`. If it transcribes its argument unchanged into an appropriate
+position (in particular, not as an argument to yet another macro invocation),
+the expander will then proceed to evaluate `m2!()` (along with any other macro
+invocations `m1!(m2!())` produced).
+
+# A final note
+
+Macros, as currently implemented, are not for the faint of heart. Even
+ordinary syntax errors can be more difficult to debug when they occur inside a
+macro, and errors caused by parse problems in generated code can be very
+tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
+states, invoking `trace_macros!(true)` will automatically print those
+intermediate states out, and passing the flag `--pretty expanded` as a
+command-line argument to the compiler will show the result of expansion.
--- /dev/null
+% Rust Packaging Guide
+
+# Introduction
+
+Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
+package up your Rust code and share it with other people. This guide will
+get you started on all of the concepts and commands you need to give the gift
+of Rust code to someone else.
+
+# Installing External Packages
+
+First, let's try to use an external package somehow. I've made a sample package
+called `hello` to demonstrate how to do so. Here's how `hello` is used:
+
+~~~~
+extern mod hello;
+
+fn main() {
+ hello::world();
+}
+~~~~
+
+Easy! But if you try to compile this, you'll get an error:
+
+~~~~ {.notrust}
+$ rustc main.rs
+main.rs:1:0: 1:17 error: can't find crate for `hello`
+main.rs:1 extern mod hello;
+ ^~~~~~~~~~~~~~~~~
+~~~~
+
+This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
+`rustpkg` has an easy way to fetch others' code: the `install` command. It's
+used like this:
+
+~~~ {.notrust}
+$ rustpkg install PKG_ID
+~~~
+
+This will install a package named `PKG_ID` into your current Rust environment.
+I called it `PKG_ID` in this example because `rustpkg` calls this a 'package
+identifier.' When using it with an external package like this, it's often a
+URI fragment. You see, Rust has no central authority for packages. You can
+build your own `hello` library if you want, and that's fine. We'd both host
+them in different places and different projects would rely on whichever version
+they preferred.
+
+To install the `hello` library, simply run this in your terminal:
+
+~~~ {.notrust}
+$ rustpkg install github.com/steveklabnik/hello
+~~~
+
+You should see a message that looks like this:
+
+~~~ {.notrust}
+note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
+~~~
+
+Now, compiling our example should work:
+
+~~~ {.notrust}
+$ rustc main.rs
+$ ./main
+Hello, world.
+~~~
+
+Simple! That's all it takes.
+
+# Workspaces
+
+Before we can talk about how to make packages of your own, you have to
+understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
+a directory that has certain sub-directories that `rustpkg` expects. Different
+Rust projects will go into different workspaces.
+
+A workspace consists of any directory that has the following
+directories:
+
+* `src`: The directory where all the source code goes.
+* `build`: This directory contains all of the build output.
+* `lib`: The directory where any libraries distributed with the package go.
+* `bin`: This directory holds any binaries distributed with the package.
+
+There are also default file names you'll want to follow as well:
+
+* `main.rs`: A file that's going to become an executable.
+* `lib.rs`: A file that's going to become a library.
+
+# Building your own Package
+
+Now that you've got workspaces down, let's build your own copy of `hello`. Go
+to wherever you keep your personal projects, and let's make all of the
+directories we'll need. I'll refer to this personal project directory as
+`~/src` for the rest of this guide.
+
+## Creating our workspace
+
+~~~ {.notrust}
+$ cd ~/src
+$ mkdir -p hello/src/hello
+$ cd hello
+~~~
+
+Easy enough! Let's do one or two more things that are nice to do:
+
+~~~ {.notrust}
+$ git init .
+$ cat > README.md
+# hello
+
+A simple package for Rust.
+
+## Installation
+
+```
+$ rustpkg install github.com/YOUR_USERNAME/hello
+```
+^D
+$ cat > .gitignore
+.rust
+build
+^D
+$ git commit -am "Initial commit."
+~~~
+
+If you're not familliar with the `cat >` idiom, it will make files with the
+text you type inside. Control-D (`^D`) ends the text for the file.
+
+Anyway, we've got a README and a `.gitignore`. Let's talk about that
+`.gitignore` for a minute: we are ignoring two directories, `build` and
+`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
+want to check those into a repository. `.rust` is a directory that `rustpkg`
+uses to keep track of its own settings, as well as the source code of any other
+external packages that this workspace uses. This is where that `rustpkg
+install` puts all of its files. Those are also not to go into our repository,
+so we ignore it all as well.
+
+Next, let's add a source file:
+
+~~~
+#[desc = "A hello world Rust package."];
+#[license = "MIT"];
+
+pub fn world() {
+ println("Hello, world.");
+}
+~~~
+
+Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
+
+## Crate attributes for packages
+
+`license` is equally simple: the license we want this code to have. I chose MIT
+here, but you should pick whatever license makes the most sense for you.
+
+`desc` is a description of the package and what it does. This should just be a
+sentence or two.
+
+## Building your package
+
+Building your package is simple:
+
+~~~ {.notrust}
+$ rustpkg build hello
+~~~
+
+This will compile `src/hello/lib.rs` into a library. After this process
+completes, you'll want to check out `build`:
+
+~~~ {.notrust}
+$ ls build/x86_64-unknown-linux-gnu/hello/
+libhello-ed8619dad9ce7d58-0.1.0.so
+~~~
+
+This directory naming structure is called a 'build triple,' and is because I'm
+on 64 bit Linux. Yours may differ based on platform.
+
+You'll also notice that `src/hello/lib.rs` turned into
+`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
+library name, a hash of its content, and the version.
+
+Now that your library builds, you'll want to commit:
+
+~~~ {.notrust}
+$ git add src
+$ git commit -m "Adding source code."
+~~~
+
+If you're using GitHub, after creating the project, do this:
+
+~~~ {.notrust}
+$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
+$ git push origin -u master
+~~~
+
+Now you can install and use it! Go anywhere else in your filesystem:
+
+~~~ {.notrust}
+$ cd ~/src/foo
+$ rustpkg install github.com/YOUR_USERNAME/hello
+WARNING: The Rust package manager is experimental and may be unstable
+note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
+~~~
+
+That's it!
+
+# Testing your Package
+
+Testing your package is simple as well. First, let's change `src/hello/lib.rs` to contain
+a function that can be sensibly tested:
+
+~~~
+#[desc = "A Rust package for determining whether unsigned integers are even."];
+#[license = "MIT"];
+
+pub fn is_even(i: uint) -> bool {
+ i % 2 == 0
+}
+~~~
+
+Once you've edited `lib.rs`, you can create a second crate file, `src/hello/test.rs`,
+to put tests in:
+
+~~~
+#[license = "MIT"];
+extern mod hello;
+use hello::is_even;
+
+#[test]
+fn test_is_even() {
+ assert!(is_even(0));
+ assert!(!is_even(1));
+ assert!(is_even(2));
+}
+~~~
+
+Note that you have to import the crate you just created in `lib.rs` with the
+`extern mod hello` directive. That's because you're putting the tests in a different
+crate from the main library that you created.
+
+Now, you can use the `rustpkg test` command to build this test crate (and anything else
+it depends on) and run the tests, all in one step:
+
+~~~ {.notrust}
+$ rustpkg test hello
+WARNING: The Rust package manager is experimental and may be unstable
+note: Installed package hello-0.1 to /Users/tjc/.rust
+
+running 1 test
+test test_is_even ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+~~~
+
+# More resources
+
+There's a lot more going on with `rustpkg`, this is just to get you started.
+Check out [the rustpkg manual](rustpkg.html) for the full details on how to
+customize `rustpkg`.
+
+A tag was created on GitHub specifically for `rustpkg`-related issues. You can
+[see all the Issues for rustpkg
+here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
+with bugs as well as new feature plans. `rustpkg` is still under development,
+and so may be a bit flaky at the moment.
+
+You may also want to check out [this blog
+post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
+design decisions and justifications.
--- /dev/null
+% Rust Tasks and Communication Guide
+
+# Introduction
+
+Rust provides safe concurrency through a combination
+of lightweight, memory-isolated tasks and message passing.
+This guide will describe the concurrency model in Rust, how it
+relates to the Rust type system, and introduce
+the fundamental library abstractions for constructing concurrent programs.
+
+Rust tasks are not the same as traditional threads: rather,
+they are considered _green threads_, lightweight units of execution that the Rust
+runtime schedules cooperatively onto a small number of operating system threads.
+On a multi-core system Rust tasks will be scheduled in parallel by default.
+Because tasks are significantly
+cheaper to create than traditional threads, Rust can create hundreds of
+thousands of concurrent tasks on a typical 32-bit system.
+In general, all Rust code executes inside a task, including the `main` function.
+
+In order to make efficient use of memory Rust tasks have dynamically sized stacks.
+A task begins its life with a small
+amount of stack space (currently in the low thousands of bytes, depending on
+platform), and acquires more stack as needed.
+Unlike in languages such as C, a Rust task cannot accidentally write to
+memory beyond the end of the stack, causing crashes or worse.
+
+Tasks provide failure isolation and recovery. When a fatal error occurs in Rust
+code as a result of an explicit call to `fail!()`, an assertion failure, or
+another invalid operation, the runtime system destroys the entire
+task. Unlike in languages such as Java and C++, there is no way to `catch` an
+exception. Instead, tasks may monitor each other for failure.
+
+Tasks use Rust's type system to provide strong memory safety guarantees. In
+particular, the type system guarantees that tasks cannot share mutable state
+with each other. Tasks communicate with each other by transferring _owned_
+data through the global _exchange heap_.
+
+## A note about the libraries
+
+While Rust's type system provides the building blocks needed for safe
+and efficient tasks, all of the task functionality itself is implemented
+in the standard and extra libraries, which are still under development
+and do not always present a consistent or complete interface.
+
+For your reference, these are the standard modules involved in Rust
+concurrency at this writing:
+
+* [`std::task`] - All code relating to tasks and task scheduling,
+* [`std::comm`] - The message passing interface,
+* [`extra::comm`] - Additional messaging types based on `std::comm`,
+* [`extra::sync`] - More exotic synchronization tools, including locks,
+* [`extra::arc`] - The Arc (atomically reference counted) type,
+ for safely sharing immutable data,
+* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time.
+
+[`std::task`]: std/task/index.html
+[`std::comm`]: std/comm/index.html
+[`extra::comm`]: extra/comm/index.html
+[`extra::sync`]: extra/sync/index.html
+[`extra::arc`]: extra/arc/index.html
+[`extra::future`]: extra/future/index.html
+
+# Basics
+
+The programming interface for creating and managing tasks lives
+in the `task` module of the `std` library, and is thus available to all
+Rust code by default. At its simplest, creating a task is a matter of
+calling the `spawn` function with a closure argument. `spawn` executes the
+closure in the new task.
+
+~~~~
+# use std::task::spawn;
+
+// Print something profound in a different task using a named function
+fn print_message() { println("I am running in a different task!"); }
+spawn(print_message);
+
+// Print something more profound in a different task using a lambda expression
+spawn(proc() println("I am also running in a different task!") );
+
+// The canonical way to spawn is using `do` notation
+do spawn {
+ println("I too am running in a different task!");
+}
+~~~~
+
+In Rust, there is nothing special about creating tasks: a task is not a
+concept that appears in the language semantics. Instead, Rust's type system
+provides all the tools necessary to implement safe concurrency: particularly,
+_owned types_. The language leaves the implementation details to the standard
+library.
+
+The `spawn` function has a very simple type signature: `fn spawn(f:
+proc())`. Because it accepts only owned closures, and owned closures
+contain only owned data, `spawn` can safely move the entire closure
+and all its associated state into an entirely different task for
+execution. Like any closure, the function passed to `spawn` may capture
+an environment that it carries across tasks.
+
+~~~
+# use std::task::spawn;
+# fn generate_task_number() -> int { 0 }
+// Generate some state locally
+let child_task_number = generate_task_number();
+
+do spawn {
+ // Capture it in the remote task
+ println!("I am child number {}", child_task_number);
+}
+~~~
+
+## Communication
+
+Now that we have spawned a new task, it would be nice if we could
+communicate with it. Recall that Rust does not have shared mutable
+state, so one task may not manipulate variables owned by another task.
+Instead we use *pipes*.
+
+A pipe is simply a pair of endpoints: one for sending messages and another for
+receiving messages. Pipes are low-level communication building-blocks and so
+come in a variety of forms, each one appropriate for a different use case. In
+what follows, we cover the most commonly used varieties.
+
+The simplest way to create a pipe is to use `Chan::new`
+function to create a `(Port, Chan)` pair. In Rust parlance, a *channel*
+is a sending endpoint of a pipe, and a *port* is the receiving
+endpoint. Consider the following example of calculating two results
+concurrently:
+
+~~~~
+# use std::task::spawn;
+
+let (port, chan): (Port<int>, Chan<int>) = Chan::new();
+
+do spawn || {
+ let result = some_expensive_computation();
+ chan.send(result);
+}
+
+some_other_expensive_computation();
+let result = port.recv();
+# fn some_expensive_computation() -> int { 42 }
+# fn some_other_expensive_computation() {}
+~~~~
+
+Let's examine this example in detail. First, the `let` statement creates a
+stream for sending and receiving integers (the left-hand side of the `let`,
+`(chan, port)`, is an example of a *destructuring let*: the pattern separates
+a tuple into its component parts).
+
+~~~~
+let (port, chan): (Port<int>, Chan<int>) = Chan::new();
+~~~~
+
+The child task will use the channel to send data to the parent task,
+which will wait to receive the data on the port. The next statement
+spawns the child task.
+
+~~~~
+# use std::task::spawn;
+# fn some_expensive_computation() -> int { 42 }
+# let (port, chan) = Chan::new();
+do spawn || {
+ let result = some_expensive_computation();
+ chan.send(result);
+}
+~~~~
+
+Notice that the creation of the task closure transfers `chan` to the child
+task implicitly: the closure captures `chan` in its environment. Both `Chan`
+and `Port` are sendable types and may be captured into tasks or otherwise
+transferred between them. In the example, the child task runs an expensive
+computation, then sends the result over the captured channel.
+
+Finally, the parent continues with some other expensive
+computation, then waits for the child's result to arrive on the
+port:
+
+~~~~
+# fn some_other_expensive_computation() {}
+# let (port, chan) = Chan::<int>::new();
+# chan.send(0);
+some_other_expensive_computation();
+let result = port.recv();
+~~~~
+
+The `Port` and `Chan` pair created by `Chan::new` enables efficient
+communication between a single sender and a single receiver, but multiple
+senders cannot use a single `Chan`, and multiple receivers cannot use a single
+`Port`. What if our example needed to compute multiple results across a number
+of tasks? The following program is ill-typed:
+
+~~~ {.xfail-test}
+# use std::task::{spawn};
+# fn some_expensive_computation() -> int { 42 }
+let (port, chan) = Chan::new();
+
+do spawn {
+ chan.send(some_expensive_computation());
+}
+
+// ERROR! The previous spawn statement already owns the channel,
+// so the compiler will not allow it to be captured again
+do spawn {
+ chan.send(some_expensive_computation());
+}
+~~~
+
+Instead we can use a `SharedChan`, a type that allows a single
+`Chan` to be shared by multiple senders.
+
+~~~
+# use std::task::spawn;
+
+let (port, chan) = SharedChan::new();
+
+for init_val in range(0u, 3) {
+ // Create a new channel handle to distribute to the child task
+ let child_chan = chan.clone();
+ do spawn {
+ child_chan.send(some_expensive_computation(init_val));
+ }
+}
+
+let result = port.recv() + port.recv() + port.recv();
+# fn some_expensive_computation(_i: uint) -> int { 42 }
+~~~
+
+Here we transfer ownership of the channel into a new `SharedChan` value. Like
+`Chan`, `SharedChan` is a non-copyable, owned type (sometimes also referred to
+as an *affine* or *linear* type). Unlike with `Chan`, though, the programmer
+may duplicate a `SharedChan`, with the `clone()` method. A cloned
+`SharedChan` produces a new handle to the same channel, allowing multiple
+tasks to send data to a single port. Between `spawn`, `Chan` and
+`SharedChan`, we have enough tools to implement many useful concurrency
+patterns.
+
+Note that the above `SharedChan` example is somewhat contrived since
+you could also simply use three `Chan` pairs, but it serves to
+illustrate the point. For reference, written with multiple streams, it
+might look like the example below.
+
+~~~
+# use std::task::spawn;
+# use std::vec;
+
+// Create a vector of ports, one for each child task
+let ports = vec::from_fn(3, |init_val| {
+ let (port, chan) = Chan::new();
+ do spawn {
+ chan.send(some_expensive_computation(init_val));
+ }
+ port
+});
+
+// Wait on each port, accumulating the results
+let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
+# fn some_expensive_computation(_i: uint) -> int { 42 }
+~~~
+
+## Backgrounding computations: Futures
+With `extra::future`, rust has a mechanism for requesting a computation and getting the result
+later.
+
+The basic example below illustrates this.
+~~~
+# fn make_a_sandwich() {};
+fn fib(n: u64) -> u64 {
+ // lengthy computation returning an uint
+ 12586269025
+}
+
+let mut delayed_fib = extra::future::Future::spawn(proc() fib(50));
+make_a_sandwich();
+println!("fib(50) = {:?}", delayed_fib.get())
+~~~
+
+The call to `future::spawn` returns immediately a `future` object regardless of how long it
+takes to run `fib(50)`. You can then make yourself a sandwich while the computation of `fib` is
+running. The result of the execution of the method is obtained by calling `get` on the future.
+This call will block until the value is available (*i.e.* the computation is complete). Note that
+the future needs to be mutable so that it can save the result for next time `get` is called.
+
+Here is another example showing how futures allow you to background computations. The workload will
+be distributed on the available cores.
+~~~
+# use std::vec;
+fn partial_sum(start: uint) -> f64 {
+ let mut local_sum = 0f64;
+ for num in range(start*100000, (start+1)*100000) {
+ local_sum += (num as f64 + 1.0).pow(&-2.0);
+ }
+ local_sum
+}
+
+fn main() {
+ let mut futures = vec::from_fn(1000, |ind| do extra::future::Future::spawn { partial_sum(ind) });
+
+ let mut final_res = 0f64;
+ for ft in futures.mut_iter() {
+ final_res += ft.get();
+ }
+ println!("π^2/6 is not far from : {}", final_res);
+}
+~~~
+
+## Sharing immutable data without copy: Arc
+
+To share immutable data between tasks, a first approach would be to only use pipes as we have seen
+previously. A copy of the data to share would then be made for each task. In some cases, this would
+add up to a significant amount of wasted memory and would require copying the same data more than
+necessary.
+
+To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in
+the `extra` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
+acts as a reference to the shared data and only this reference is shared and cloned.
+
+Here is a small example showing how to use Arcs. We wish to run concurrently several computations on
+a single large vector of floats. Each task needs the full vector to perform its duty.
+~~~
+# use std::vec;
+# use std::rand;
+use extra::arc::Arc;
+
+fn pnorm(nums: &~[f64], p: uint) -> f64 {
+ nums.iter().fold(0.0, |a,b| a+(*b).pow(&(p as f64)) ).pow(&(1.0 / (p as f64)))
+}
+
+fn main() {
+ let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
+ println!("Inf-norm = {}", *numbers.iter().max().unwrap());
+
+ let numbers_arc = Arc::new(numbers);
+
+ for num in range(1u, 10) {
+ let (port, chan) = Chan::new();
+ chan.send(numbers_arc.clone());
+
+ do spawn {
+ let local_arc : Arc<~[f64]> = port.recv();
+ let task_numbers = local_arc.get();
+ println!("{}-norm = {}", num, pnorm(task_numbers, num));
+ }
+ }
+}
+~~~
+
+The function `pnorm` performs a simple computation on the vector (it computes the sum of its items
+at the power given as argument and takes the inverse power of this value). The Arc on the vector is
+created by the line
+~~~
+# use extra::arc::Arc;
+# use std::vec;
+# use std::rand;
+# let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
+let numbers_arc=Arc::new(numbers);
+~~~
+and a clone of it is sent to each task
+~~~
+# use extra::arc::Arc;
+# use std::vec;
+# use std::rand;
+# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
+# let numbers_arc = Arc::new(numbers);
+# let (port, chan) = Chan::new();
+chan.send(numbers_arc.clone());
+~~~
+copying only the wrapper and not its contents.
+
+Each task recovers the underlying data by
+~~~
+# use extra::arc::Arc;
+# use std::vec;
+# use std::rand;
+# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
+# let numbers_arc=Arc::new(numbers);
+# let (port, chan) = Chan::new();
+# chan.send(numbers_arc.clone());
+# let local_arc : Arc<~[f64]> = port.recv();
+let task_numbers = local_arc.get();
+~~~
+and can use it as if it were local.
+
+The `arc` module also implements Arcs around mutable data that are not covered here.
+
+# Handling task failure
+
+Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
+(which can also be written with an error string as an argument: `fail!(
+~reason)`) and the `assert!` construct (which effectively calls `fail!()`
+if a boolean expression is false) are both ways to raise exceptions. When a
+task raises an exception the task unwinds its stack---running destructors and
+freeing memory along the way---and then exits. Unlike exceptions in C++,
+exceptions in Rust are unrecoverable within a single task: once a task fails,
+there is no way to "catch" the exception.
+
+While it isn't possible for a task to recover from failure, tasks may notify
+each other of failure. The simplest way of handling task failure is with the
+`try` function, which is similar to `spawn`, but immediately blocks waiting
+for the child task to finish. `try` returns a value of type `Result<T,
+()>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this
+case, because the type arguments to `Result` are `int` and `()`, callers can
+pattern-match on a result to check whether it's an `Ok` result with an `int`
+field (representing a successful result) or an `Err` result (representing
+termination with an error).
+
+~~~{.xfail-test .linked-failure}
+# use std::task;
+# fn some_condition() -> bool { false }
+# fn calculate_result() -> int { 0 }
+let result: Result<int, ()> = do task::try {
+ if some_condition() {
+ calculate_result()
+ } else {
+ fail!("oops!");
+ }
+};
+assert!(result.is_err());
+~~~
+
+Unlike `spawn`, the function spawned using `try` may return a value,
+which `try` will dutifully propagate back to the caller in a [`Result`]
+enum. If the child task terminates successfully, `try` will
+return an `Ok` result; if the child task fails, `try` will return
+an `Error` result.
+
+[`Result`]: std/result/index.html
+
+> ***Note:*** A failed task does not currently produce a useful error
+> value (`try` always returns `Err(())`). In the
+> future, it may be possible for tasks to intercept the value passed to
+> `fail!()`.
+
+TODO: Need discussion of `future_result` in order to make failure
+modes useful.
+
+But not all failures are created equal. In some cases you might need to
+abort the entire program (perhaps you're writing an assert which, if
+it trips, indicates an unrecoverable logic error); in other cases you
+might want to contain the failure at a certain boundary (perhaps a
+small piece of input from the outside world, which you happen to be
+processing in parallel, is malformed and its processing task can't
+proceed).
+
+## Creating a task with a bi-directional communication path
+
+A very common thing to do is to spawn a child task where the parent
+and child both need to exchange messages with each other. The
+function `extra::comm::DuplexStream()` supports this pattern. We'll
+look briefly at how to use it.
+
+To see how `DuplexStream()` works, we will create a child task
+that repeatedly receives a `uint` message, converts it to a string, and sends
+the string in response. The child terminates when it receives `0`.
+Here is the function that implements the child task:
+
+~~~{.xfail-test .linked-failure}
+# use extra::comm::DuplexStream;
+# use std::uint;
+fn stringifier(channel: &DuplexStream<~str, uint>) {
+ let mut value: uint;
+ loop {
+ value = channel.recv();
+ channel.send(uint::to_str(value));
+ if value == 0 { break; }
+ }
+}
+~~~~
+
+The implementation of `DuplexStream` supports both sending and
+receiving. The `stringifier` function takes a `DuplexStream` that can
+send strings (the first type parameter) and receive `uint` messages
+(the second type parameter). The body itself simply loops, reading
+from the channel and then sending its response back. The actual
+response itself is simply the stringified version of the received value,
+`uint::to_str(value)`.
+
+Here is the code for the parent task:
+
+~~~{.xfail-test .linked-failure}
+# use std::task::spawn;
+# use std::uint;
+# use extra::comm::DuplexStream;
+# fn stringifier(channel: &DuplexStream<~str, uint>) {
+# let mut value: uint;
+# loop {
+# value = channel.recv();
+# channel.send(uint::to_str(value));
+# if value == 0u { break; }
+# }
+# }
+# fn main() {
+
+let (from_child, to_child) = DuplexStream::new();
+
+do spawn {
+ stringifier(&to_child);
+};
+
+from_child.send(22);
+assert!(from_child.recv() == ~"22");
+
+from_child.send(23);
+from_child.send(0);
+
+assert!(from_child.recv() == ~"23");
+assert!(from_child.recv() == ~"0");
+
+# }
+~~~~
+
+The parent task first calls `DuplexStream` to create a pair of bidirectional
+endpoints. It then uses `task::spawn` to create the child task, which captures
+one end of the communication channel. As a result, both parent and child can
+send and receive data to and from the other.
--- /dev/null
+% Rust Testing Guide
+
+# Quick start
+
+To create test functions, add a `#[test]` attribute like this:
+
+```rust
+fn return_two() -> int {
+ 2
+}
+
+#[test]
+fn return_two_test() {
+ let x = return_two();
+ assert!(x == 2);
+}
+```
+
+To run these tests, use `rustc --test`:
+
+```
+$ rustc --test foo.rs; ./foo
+running 1 test
+test return_two_test ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
+```
+
+`rustc foo.rs` will *not* compile the tests, since `#[test]` implies
+`#[cfg(test)]`. The `--test` flag to `rustc` implies `--cfg test`.
+
+
+# Unit testing in Rust
+
+Rust has built in support for simple unit testing. Functions can be
+marked as unit tests using the 'test' attribute.
+
+```rust
+#[test]
+fn return_none_if_empty() {
+ // ... test code ...
+}
+```
+
+A test function's signature must have no arguments and no return
+value. To run the tests in a crate, it must be compiled with the
+'--test' flag: `rustc myprogram.rs --test -o myprogram-tests`. Running
+the resulting executable will run all the tests in the crate. A test
+is considered successful if its function returns; if the task running
+the test fails, through a call to `fail!`, a failed `check` or
+`assert`, or some other (`assert_eq`, `assert_approx_eq`, ...) means,
+then the test fails.
+
+When compiling a crate with the '--test' flag '--cfg test' is also
+implied, so that tests can be conditionally compiled.
+
+```rust
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn return_none_if_empty() {
+ // ... test code ...
+ }
+}
+```
+
+Additionally #[test] items behave as if they also have the
+#[cfg(test)] attribute, and will not be compiled when the --test flag
+is not used.
+
+Tests that should not be run can be annotated with the 'ignore'
+attribute. The existence of these tests will be noted in the test
+runner output, but the test will not be run. Tests can also be ignored
+by configuration so, for example, to ignore a test on windows you can
+write `#[ignore(cfg(target_os = "win32"))]`.
+
+Tests that are intended to fail can be annotated with the
+'should_fail' attribute. The test will be run, and if it causes its
+task to fail then the test will be counted as successful; otherwise it
+will be counted as a failure. For example:
+
+```rust
+#[test]
+#[should_fail]
+fn test_out_of_bounds_failure() {
+ let v: [int] = [];
+ v[0];
+}
+```
+
+A test runner built with the '--test' flag supports a limited set of
+arguments to control which tests are run: the first free argument
+passed to a test runner specifies a filter used to narrow down the set
+of tests being run; the '--ignored' flag tells the test runner to run
+only tests with the 'ignore' attribute.
+
+## Parallelism
+
+By default, tests are run in parallel, which can make interpreting
+failure output difficult. In these cases you can set the
+`RUST_TEST_TASKS` environment variable to 1 to make the tests run
+sequentially.
+
+## Benchmarking
+
+The test runner also understands a simple form of benchmark execution.
+Benchmark functions are marked with the `#[bench]` attribute, rather
+than `#[test]`, and have a different form and meaning. They are
+compiled along with `#[test]` functions when a crate is compiled with
+`--test`, but they are not run by default. To run the benchmark
+component of your testsuite, pass `--bench` to the compiled test
+runner.
+
+The type signature of a benchmark function differs from a unit test:
+it takes a mutable reference to type `test::BenchHarness`. Inside the
+benchmark function, any time-variable or "setup" code should execute
+first, followed by a call to `iter` on the benchmark harness, passing
+a closure that contains the portion of the benchmark you wish to
+actually measure the per-iteration speed of.
+
+For benchmarks relating to processing/generating data, one can set the
+`bytes` field to the number of bytes consumed/produced in each
+iteration; this will used to show the throughput of the benchmark.
+This must be the amount used in each iteration, *not* the total
+amount.
+
+For example:
+
+```rust
+extern mod extra;
+use std::vec;
+
+#[bench]
+fn bench_sum_1024_ints(b: &mut extra::test::BenchHarness) {
+ let v = vec::from_fn(1024, |n| n);
+ b.iter(|| {v.iter().fold(0, |old, new| old + *new);} );
+}
+
+#[bench]
+fn initialise_a_vector(b: &mut extra::test::BenchHarness) {
+ b.iter(|| {vec::from_elem(1024, 0u64);} );
+ b.bytes = 1024 * 8;
+}
+```
+
+The benchmark runner will calibrate measurement of the benchmark
+function to run the `iter` block "enough" times to get a reliable
+measure of the per-iteration speed.
+
+Advice on writing benchmarks:
+
+ - Move setup code outside the `iter` loop; only put the part you
+ want to measure inside
+ - Make the code do "the same thing" on each iteration; do not
+ accumulate or change state
+ - Make the outer function idempotent too; the benchmark runner is
+ likely to run it many times
+ - Make the inner `iter` loop short and fast so benchmark runs are
+ fast and the calibrator can adjust the run-length at fine
+ resolution
+ - Make the code in the `iter` loop do something simple, to assist in
+ pinpointing performance improvements (or regressions)
+
+To run benchmarks, pass the `--bench` flag to the compiled
+test-runner. Benchmarks are compiled-in but not executed by default.
+
+## Examples
+
+### Typical test run
+
+```
+> mytests
+
+running 30 tests
+running driver::tests::mytest1 ... ok
+running driver::tests::mytest2 ... ignored
+... snip ...
+running driver::tests::mytest30 ... ok
+
+result: ok. 28 passed; 0 failed; 2 ignored
+```
+
+### Test run with failures
+
+```
+> mytests
+
+running 30 tests
+running driver::tests::mytest1 ... ok
+running driver::tests::mytest2 ... ignored
+... snip ...
+running driver::tests::mytest30 ... FAILED
+
+result: FAILED. 27 passed; 1 failed; 2 ignored
+```
+
+### Running ignored tests
+
+```
+> mytests --ignored
+
+running 2 tests
+running driver::tests::mytest2 ... failed
+running driver::tests::mytest10 ... ok
+
+result: FAILED. 1 passed; 1 failed; 0 ignored
+```
+
+### Running a subset of tests
+
+```
+> mytests mytest1
+
+running 11 tests
+running driver::tests::mytest1 ... ok
+running driver::tests::mytest10 ... ignored
+... snip ...
+running driver::tests::mytest19 ... ok
+
+result: ok. 11 passed; 0 failed; 1 ignored
+```
+
+### Running benchmarks
+
+```
+> mytests --bench
+
+running 2 tests
+test bench_sum_1024_ints ... bench: 709 ns/iter (+/- 82)
+test initialise_a_vector ... bench: 424 ns/iter (+/- 99) = 19320 MB/s
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
+```
+
+## Saving and ratcheting metrics
+
+When running benchmarks or other tests, the test runner can record
+per-test "metrics". Each metric is a scalar `f64` value, plus a noise
+value which represents uncertainty in the measurement. By default, all
+`#[bench]` benchmarks are recorded as metrics, which can be saved as
+JSON in an external file for further reporting.
+
+In addition, the test runner supports _ratcheting_ against a metrics
+file. Ratcheting is like saving metrics, except that after each run,
+if the output file already exists the results of the current run are
+compared against the contents of the existing file, and any regression
+_causes the testsuite to fail_. If the comparison passes -- if all
+metrics stayed the same (within noise) or improved -- then the metrics
+file is overwritten with the new values. In this way, a metrics file
+in your workspace can be used to ensure your work does not regress
+performance.
+
+Test runners take 3 options that are relevant to metrics:
+
+ - `--save-metrics=<file.json>` will save the metrics from a test run
+ to `file.json`
+ - `--ratchet-metrics=<file.json>` will ratchet the metrics against
+ the `file.json`
+ - `--ratchet-noise-percent=N` will override the noise measurements
+ in `file.json`, and consider a metric change less than `N%` to be
+ noise. This can be helpful if you are testing in a noisy
+ environment where the benchmark calibration loop cannot acquire a
+ clear enough signal.
+++ /dev/null
-% Rust Borrowed Pointers Tutorial
-
-# Introduction
-
-Borrowed pointers are one of the more flexible and powerful tools available in
-Rust. A borrowed pointer can point anywhere: into the managed or exchange
-heap, into the stack, and even into the interior of another data structure. A
-borrowed pointer is as flexible as a C pointer or C++ reference. However,
-unlike C and C++ compilers, the Rust compiler includes special static checks
-that ensure that programs use borrowed pointers safely. Another advantage of
-borrowed pointers is that they are invisible to the garbage collector, so
-working with borrowed pointers helps reduce the overhead of automatic memory
-management.
-
-Despite their complete safety, a borrowed pointer's representation at runtime
-is the same as that of an ordinary pointer in a C program. They introduce zero
-overhead. The compiler does all safety checks at compile time.
-
-Although borrowed pointers have rather elaborate theoretical
-underpinnings (region pointers), the core concepts will be familiar to
-anyone who has worked with C or C++. Therefore, the best way to explain
-how they are used—and their limitations—is probably just to work
-through several examples.
-
-# By example
-
-Borrowed pointers are called *borrowed* because they are only valid for
-a limited duration. Borrowed pointers never claim any kind of ownership
-over the data that they point to: instead, they are used for cases
-where you would like to use data for a short time.
-
-As an example, consider a simple struct type `Point`:
-
-~~~
-struct Point {x: f64, y: f64}
-~~~
-
-We can use this simple definition to allocate points in many different ways. For
-example, in this code, each of these three local variables contains a
-point, but allocated in a different place:
-
-~~~
-# struct Point {x: f64, y: f64}
-let on_the_stack : Point = Point {x: 3.0, y: 4.0};
-let managed_box : @Point = @Point {x: 5.0, y: 1.0};
-let owned_box : ~Point = ~Point {x: 7.0, y: 9.0};
-~~~
-
-Suppose we wanted to write a procedure that computed the distance between any
-two points, no matter where they were stored. For example, we might like to
-compute the distance between `on_the_stack` and `managed_box`, or between
-`managed_box` and `owned_box`. One option is to define a function that takes
-two arguments of type `Point`—that is, it takes the points by value. But if we
-define it this way, calling the function will cause the points to be
-copied. For points, this is probably not so bad, but often copies are
-expensive. Worse, if the data type contains mutable fields, copying can change
-the semantics of your program in unexpected ways. So we'd like to define a
-function that takes the points by pointer. We can use borrowed pointers to do
-this:
-
-~~~
-# struct Point {x: f64, y: f64}
-# fn sqrt(f: f64) -> f64 { 0.0 }
-fn compute_distance(p1: &Point, p2: &Point) -> f64 {
- let x_d = p1.x - p2.x;
- let y_d = p1.y - p2.y;
- sqrt(x_d * x_d + y_d * y_d)
-}
-~~~
-
-Now we can call `compute_distance()` in various ways:
-
-~~~
-# struct Point {x: f64, y: f64}
-# let on_the_stack : Point = Point{x: 3.0, y: 4.0};
-# let managed_box : @Point = @Point{x: 5.0, y: 1.0};
-# let owned_box : ~Point = ~Point{x: 7.0, y: 9.0};
-# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
-compute_distance(&on_the_stack, managed_box);
-compute_distance(managed_box, owned_box);
-~~~
-
-Here, the `&` operator takes the address of the variable
-`on_the_stack`; this is because `on_the_stack` has the type `Point`
-(that is, a struct value) and we have to take its address to get a
-value. We also call this _borrowing_ the local variable
-`on_the_stack`, because we have created an alias: that is, another
-name for the same data.
-
-In contrast, we can pass the boxes `managed_box` and `owned_box` to
-`compute_distance` directly. The compiler automatically converts a box like
-`@Point` or `~Point` to a borrowed pointer like `&Point`. This is another form
-of borrowing: in this case, the caller lends the contents of the managed or
-owned box to the callee.
-
-Whenever a caller lends data to a callee, there are some limitations on what
-the caller can do with the original. For example, if the contents of a
-variable have been lent out, you cannot send that variable to another task. In
-addition, the compiler will reject any code that might cause the borrowed
-value to be freed or overwrite its component fields with values of different
-types (I'll get into what kinds of actions those are shortly). This rule
-should make intuitive sense: you must wait for a borrower to return the value
-that you lent it (that is, wait for the borrowed pointer to go out of scope)
-before you can make full use of it again.
-
-# Other uses for the & operator
-
-In the previous example, the value `on_the_stack` was defined like so:
-
-~~~
-# struct Point {x: f64, y: f64}
-let on_the_stack: Point = Point {x: 3.0, y: 4.0};
-~~~
-
-This declaration means that code can only pass `Point` by value to other
-functions. As a consequence, we had to explicitly take the address of
-`on_the_stack` to get a borrowed pointer. Sometimes however it is more
-convenient to move the & operator into the definition of `on_the_stack`:
-
-~~~
-# struct Point {x: f64, y: f64}
-let on_the_stack2: &Point = &Point {x: 3.0, y: 4.0};
-~~~
-
-Applying `&` to an rvalue (non-assignable location) is just a convenient
-shorthand for creating a temporary and taking its address. A more verbose
-way to write the same code is:
-
-~~~
-# struct Point {x: f64, y: f64}
-let tmp = Point {x: 3.0, y: 4.0};
-let on_the_stack2 : &Point = &tmp;
-~~~
-
-# Taking the address of fields
-
-As in C, the `&` operator is not limited to taking the address of
-local variables. It can also take the address of fields or
-individual array elements. For example, consider this type definition
-for `rectangle`:
-
-~~~
-struct Point {x: f64, y: f64} // as before
-struct Size {w: f64, h: f64} // as before
-struct Rectangle {origin: Point, size: Size}
-~~~
-
-Now, as before, we can define rectangles in a few different ways:
-
-~~~
-# struct Point {x: f64, y: f64}
-# struct Size {w: f64, h: f64} // as before
-# struct Rectangle {origin: Point, size: Size}
-let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0},
- size: Size {w: 3.0, h: 4.0}};
-let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0},
- size: Size {w: 3.0, h: 4.0}};
-let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0},
- size: Size {w: 3.0, h: 4.0}};
-~~~
-
-In each case, we can extract out individual subcomponents with the `&`
-operator. For example, I could write:
-
-~~~
-# struct Point {x: f64, y: f64} // as before
-# struct Size {w: f64, h: f64} // as before
-# struct Rectangle {origin: Point, size: Size}
-# let rect_stack = &Rectangle {origin: Point {x: 1.0, y: 2.0}, size: Size {w: 3.0, h: 4.0}};
-# let rect_managed = @Rectangle {origin: Point {x: 3.0, y: 4.0}, size: Size {w: 3.0, h: 4.0}};
-# let rect_owned = ~Rectangle {origin: Point {x: 5.0, y: 6.0}, size: Size {w: 3.0, h: 4.0}};
-# fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 }
-compute_distance(&rect_stack.origin, &rect_managed.origin);
-~~~
-
-which would borrow the field `origin` from the rectangle on the stack
-as well as from the managed box, and then compute the distance between them.
-
-# Borrowing managed boxes and rooting
-
-We’ve seen a few examples so far of borrowing heap boxes, both managed
-and owned. Up till this point, we’ve glossed over issues of
-safety. As stated in the introduction, at runtime a borrowed pointer
-is simply a pointer, nothing more. Therefore, avoiding C's problems
-with dangling pointers requires a compile-time safety check.
-
-The basis for the check is the notion of _lifetimes_. A lifetime is a
-static approximation of the span of execution during which the pointer
-is valid: it always corresponds to some expression or block within the
-program. Code inside that expression can use the pointer without
-restrictions. But if the pointer escapes from that expression (for
-example, if the expression contains an assignment expression that
-assigns the pointer to a mutable field of a data structure with a
-broader scope than the pointer itself), the compiler reports an
-error. We'll be discussing lifetimes more in the examples to come, and
-a more thorough introduction is also available.
-
-When the `&` operator creates a borrowed pointer, the compiler must
-ensure that the pointer remains valid for its entire
-lifetime. Sometimes this is relatively easy, such as when taking the
-address of a local variable or a field that is stored on the stack:
-
-~~~
-struct X { f: int }
-fn example1() {
- let mut x = X { f: 3 };
- let y = &mut x.f; // -+ L
- ... // |
-} // -+
-~~~
-
-Here, the lifetime of the borrowed pointer `y` is simply L, the
-remainder of the function body. The compiler need not do any other
-work to prove that code will not free `x.f`. This is true even if the
-code mutates `x`.
-
-The situation gets more complex when borrowing data inside heap boxes:
-
-~~~
-# struct X { f: int }
-fn example2() {
- let mut x = @X { f: 3 };
- let y = &x.f; // -+ L
- ... // |
-} // -+
-~~~
-
-In this example, the value `x` is a heap box, and `y` is therefore a
-pointer into that heap box. Again the lifetime of `y` is L, the
-remainder of the function body. But there is a crucial difference:
-suppose `x` were to be reassigned during the lifetime L? If the
-compiler isn't careful, the managed box could become *unrooted*, and
-would therefore be subject to garbage collection. A heap box that is
-unrooted is one such that no pointer values in the heap point to
-it. It would violate memory safety for the box that was originally
-assigned to `x` to be garbage-collected, since a non-heap
-pointer *`y`* still points into it.
-
-> ***Note:*** Our current implementation implements the garbage collector
-> using reference counting and cycle detection.
-
-For this reason, whenever an `&` expression borrows the interior of a
-managed box stored in a mutable location, the compiler inserts a
-temporary that ensures that the managed box remains live for the
-entire lifetime. So, the above example would be compiled as if it were
-written
-
-~~~
-# struct X { f: int }
-fn example2() {
- let mut x = @X {f: 3};
- let x1 = x;
- let y = &x1.f; // -+ L
- ... // |
-} // -+
-~~~
-
-Now if `x` is reassigned, the pointer `y` will still remain valid. This
-process is called *rooting*.
-
-# Borrowing owned boxes
-
-The previous example demonstrated *rooting*, the process by which the
-compiler ensures that managed boxes remain live for the duration of a
-borrow. Unfortunately, rooting does not work for borrows of owned
-boxes, because it is not possible to have two references to a owned
-box.
-
-For owned boxes, therefore, the compiler will only allow a borrow *if
-the compiler can guarantee that the owned box will not be reassigned
-or moved for the lifetime of the pointer*. This does not necessarily
-mean that the owned box is stored in immutable memory. For example,
-the following function is legal:
-
-~~~
-# fn some_condition() -> bool { true }
-# struct Foo { f: int }
-fn example3() -> int {
- let mut x = ~Foo {f: 3};
- if some_condition() {
- let y = &x.f; // -+ L
- return *y; // |
- } // -+
- x = ~Foo {f: 4};
- ...
-# return 0;
-}
-~~~
-
-Here, as before, the interior of the variable `x` is being borrowed
-and `x` is declared as mutable. However, the compiler can prove that
-`x` is not assigned anywhere in the lifetime L of the variable
-`y`. Therefore, it accepts the function, even though `x` is mutable
-and in fact is mutated later in the function.
-
-It may not be clear why we are so concerned about mutating a borrowed
-variable. The reason is that the runtime system frees any owned box
-_as soon as its owning reference changes or goes out of
-scope_. Therefore, a program like this is illegal (and would be
-rejected by the compiler):
-
-~~~ {.xfail-test}
-fn example3() -> int {
- let mut x = ~X {f: 3};
- let y = &x.f;
- x = ~X {f: 4}; // Error reported here.
- *y
-}
-~~~
-
-To make this clearer, consider this diagram showing the state of
-memory immediately before the re-assignment of `x`:
-
-~~~ {.notrust}
- Stack Exchange Heap
-
- x +----------+
- | ~{f:int} | ----+
- y +----------+ |
- | &int | ----+
- +----------+ | +---------+
- +--> | f: 3 |
- +---------+
-~~~
-
-Once the reassignment occurs, the memory will look like this:
-
-~~~ {.notrust}
- Stack Exchange Heap
-
- x +----------+ +---------+
- | ~{f:int} | -------> | f: 4 |
- y +----------+ +---------+
- | &int | ----+
- +----------+ | +---------+
- +--> | (freed) |
- +---------+
-~~~
-
-Here you can see that the variable `y` still points at the old box,
-which has been freed.
-
-In fact, the compiler can apply the same kind of reasoning to any
-memory that is _(uniquely) owned by the stack frame_. So we could
-modify the previous example to introduce additional owned pointers
-and structs, and the compiler will still be able to detect possible
-mutations:
-
-~~~ {.xfail-test}
-fn example3() -> int {
- struct R { g: int }
- struct S { f: ~R }
-
- let mut x = ~S {f: ~R {g: 3}};
- let y = &x.f.g;
- x = ~S {f: ~R {g: 4}}; // Error reported here.
- x.f = ~R {g: 5}; // Error reported here.
- *y
-}
-~~~
-
-In this case, two errors are reported, one when the variable `x` is
-modified and another when `x.f` is modified. Either modification would
-invalidate the pointer `y`.
-
-# Borrowing and enums
-
-The previous example showed that the type system forbids any borrowing
-of owned boxes found in aliasable, mutable memory. This restriction
-prevents pointers from pointing into freed memory. There is one other
-case where the compiler must be very careful to ensure that pointers
-remain valid: pointers into the interior of an `enum`.
-
-As an example, let’s look at the following `shape` type that can
-represent both rectangles and circles:
-
-~~~
-struct Point {x: f64, y: f64}; // as before
-struct Size {w: f64, h: f64}; // as before
-enum Shape {
- Circle(Point, f64), // origin, radius
- Rectangle(Point, Size) // upper-left, dimensions
-}
-~~~
-
-Now we might write a function to compute the area of a shape. This
-function takes a borrowed pointer to a shape, to avoid the need for
-copying.
-
-~~~
-# struct Point {x: f64, y: f64}; // as before
-# struct Size {w: f64, h: f64}; // as before
-# enum Shape {
-# Circle(Point, f64), // origin, radius
-# Rectangle(Point, Size) // upper-left, dimensions
-# }
-# static tau: f64 = 6.28;
-fn compute_area(shape: &Shape) -> f64 {
- match *shape {
- Circle(_, radius) => 0.5 * tau * radius * radius,
- Rectangle(_, ref size) => size.w * size.h
- }
-}
-~~~
-
-The first case matches against circles. Here, the pattern extracts the
-radius from the shape variant and the action uses it to compute the
-area of the circle. (Like any up-to-date engineer, we use the [tau
-circle constant][tau] and not that dreadfully outdated notion of pi).
-
-[tau]: http://www.math.utah.edu/~palais/pi.html
-
-The second match is more interesting. Here we match against a
-rectangle and extract its size: but rather than copy the `size`
-struct, we use a by-reference binding to create a pointer to it. In
-other words, a pattern binding like `ref size` binds the name `size`
-to a pointer of type `&size` into the _interior of the enum_.
-
-To make this more clear, let's look at a diagram of memory layout in
-the case where `shape` points at a rectangle:
-
-~~~ {.notrust}
-Stack Memory
-
-+-------+ +---------------+
-| shape | ------> | rectangle( |
-+-------+ | {x: f64, |
-| size | -+ | y: f64}, |
-+-------+ +----> | {w: f64, |
- | h: f64}) |
- +---------------+
-~~~
-
-Here you can see that rectangular shapes are composed of five words of
-memory. The first is a tag indicating which variant this enum is
-(`rectangle`, in this case). The next two words are the `x` and `y`
-fields for the point and the remaining two are the `w` and `h` fields
-for the size. The binding `size` is then a pointer into the inside of
-the shape.
-
-Perhaps you can see where the danger lies: if the shape were somehow
-to be reassigned, perhaps to a circle, then although the memory used
-to store that shape value would still be valid, _it would have a
-different type_! The following diagram shows what memory would look
-like if code overwrote `shape` with a circle:
-
-~~~ {.notrust}
-Stack Memory
-
-+-------+ +---------------+
-| shape | ------> | circle( |
-+-------+ | {x: f64, |
-| size | -+ | y: f64}, |
-+-------+ +----> | f64) |
- | |
- +---------------+
-~~~
-
-As you can see, the `size` pointer would be pointing at a `f64`
-instead of a struct. This is not good: dereferencing the second field
-of a `f64` as if it were a struct with two fields would be a memory
-safety violation.
-
-So, in fact, for every `ref` binding, the compiler will impose the
-same rules as the ones we saw for borrowing the interior of a owned
-box: it must be able to guarantee that the `enum` will not be
-overwritten for the duration of the borrow. In fact, the compiler
-would accept the example we gave earlier. The example is safe because
-the shape pointer has type `&Shape`, which means "borrowed pointer to
-immutable memory containing a `shape`". If, however, the type of that
-pointer were `&mut Shape`, then the ref binding would be ill-typed.
-Just as with owned boxes, the compiler will permit `ref` bindings
-into data owned by the stack frame even if the data are mutable,
-but otherwise it requires that the data reside in immutable memory.
-
-# Returning borrowed pointers
-
-So far, all of the examples we have looked at, use borrowed pointers in a
-“downward” direction. That is, a method or code block creates a
-borrowed pointer, then uses it within the same scope. It is also
-possible to return borrowed pointers as the result of a function, but
-as we'll see, doing so requires some explicit annotation.
-
-For example, we could write a subroutine like this:
-
-~~~
-struct Point {x: f64, y: f64}
-fn get_x<'r>(p: &'r Point) -> &'r f64 { &p.x }
-~~~
-
-Here, the function `get_x()` returns a pointer into the structure it
-was given. The type of the parameter (`&'r Point`) and return type
-(`&'r f64`) both use a new syntactic form that we have not seen so
-far. Here the identifier `r` names the lifetime of the pointer
-explicitly. So in effect, this function declares that it takes a
-pointer with lifetime `r` and returns a pointer with that same
-lifetime.
-
-In general, it is only possible to return borrowed pointers if they
-are derived from a parameter to the procedure. In that case, the
-pointer result will always have the same lifetime as one of the
-parameters; named lifetimes indicate which parameter that
-is.
-
-In the previous examples, function parameter types did not include a
-lifetime name. In those examples, the compiler simply creates a fresh
-name for the lifetime automatically: that is, the lifetime name is
-guaranteed to refer to a distinct lifetime from the lifetimes of all
-other parameters.
-
-Named lifetimes that appear in function signatures are conceptually
-the same as the other lifetimes we have seen before, but they are a bit
-abstract: they don’t refer to a specific expression within `get_x()`,
-but rather to some expression within the *caller of `get_x()`*. The
-lifetime `r` is actually a kind of *lifetime parameter*: it is defined
-by the caller to `get_x()`, just as the value for the parameter `p` is
-defined by that caller.
-
-In any case, whatever the lifetime of `r` is, the pointer produced by
-`&p.x` always has the same lifetime as `p` itself: a pointer to a
-field of a struct is valid as long as the struct is valid. Therefore,
-the compiler accepts the function `get_x()`.
-
-To emphasize this point, let’s look at a variation on the example, this
-time one that does not compile:
-
-~~~ {.xfail-test}
-struct Point {x: f64, y: f64}
-fn get_x_sh(p: @Point) -> &f64 {
- &p.x // Error reported here
-}
-~~~
-
-Here, the function `get_x_sh()` takes a managed box as input and
-returns a borrowed pointer. As before, the lifetime of the borrowed
-pointer that will be returned is a parameter (specified by the
-caller). That means that `get_x_sh()` promises to return a borrowed
-pointer that is valid for as long as the caller would like: this is
-subtly different from the first example, which promised to return a
-pointer that was valid for as long as its pointer argument was valid.
-
-Within `get_x_sh()`, we see the expression `&p.x` which takes the
-address of a field of a managed box. The presence of this expression
-implies that the compiler must guarantee that, so long as the
-resulting pointer is valid, the managed box will not be reclaimed by
-the garbage collector. But recall that `get_x_sh()` also promised to
-return a pointer that was valid for as long as the caller wanted it to
-be. Clearly, `get_x_sh()` is not in a position to make both of these
-guarantees; in fact, it cannot guarantee that the pointer will remain
-valid at all once it returns, as the parameter `p` may or may not be
-live in the caller. Therefore, the compiler will report an error here.
-
-In general, if you borrow a managed (or owned) box to create a
-borrowed pointer, the pointer will only be valid within the function
-and cannot be returned. This is why the typical way to return borrowed
-pointers is to take borrowed pointers as input (the only other case in
-which it can be legal to return a borrowed pointer is if the pointer
-points at a static constant).
-
-# Named lifetimes
-
-Let's look at named lifetimes in more detail. Named lifetimes allow
-for grouping of parameters by lifetime. For example, consider this
-function:
-
-~~~
-# struct Point {x: f64, y: f64}; // as before
-# struct Size {w: f64, h: f64}; // as before
-# enum Shape {
-# Circle(Point, f64), // origin, radius
-# Rectangle(Point, Size) // upper-left, dimensions
-# }
-# fn compute_area(shape: &Shape) -> f64 { 0.0 }
-fn select<'r, T>(shape: &'r Shape, threshold: f64,
- a: &'r T, b: &'r T) -> &'r T {
- if compute_area(shape) > threshold {a} else {b}
-}
-~~~
-
-This function takes three borrowed pointers and assigns each the same
-lifetime `r`. In practice, this means that, in the caller, the
-lifetime `r` will be the *intersection of the lifetime of the three
-region parameters*. This may be overly conservative, as in this
-example:
-
-~~~
-# struct Point {x: f64, y: f64}; // as before
-# struct Size {w: f64, h: f64}; // as before
-# enum Shape {
-# Circle(Point, f64), // origin, radius
-# Rectangle(Point, Size) // upper-left, dimensions
-# }
-# fn compute_area(shape: &Shape) -> f64 { 0.0 }
-# fn select<'r, T>(shape: &Shape, threshold: f64,
-# a: &'r T, b: &'r T) -> &'r T {
-# if compute_area(shape) > threshold {a} else {b}
-# }
- // -+ r
-fn select_based_on_unit_circle<'r, T>( // |-+ B
- threshold: f64, a: &'r T, b: &'r T) -> &'r T { // | |
- // | |
- let shape = Circle(Point {x: 0., y: 0.}, 1.); // | |
- select(&shape, threshold, a, b) // | |
-} // |-+
- // -+
-~~~
-
-In this call to `select()`, the lifetime of the first parameter shape
-is B, the function body. Both of the second two parameters `a` and `b`
-share the same lifetime, `r`, which is a lifetime parameter of
-`select_based_on_unit_circle()`. The caller will infer the
-intersection of these two lifetimes as the lifetime of the returned
-value, and hence the return value of `select()` will be assigned a
-lifetime of B. This will in turn lead to a compilation error, because
-`select_based_on_unit_circle()` is supposed to return a value with the
-lifetime `r`.
-
-To address this, we can modify the definition of `select()` to
-distinguish the lifetime of the first parameter from the lifetime of
-the latter two. After all, the first parameter is not being
-returned. Here is how the new `select()` might look:
-
-~~~
-# struct Point {x: f64, y: f64}; // as before
-# struct Size {w: f64, h: f64}; // as before
-# enum Shape {
-# Circle(Point, f64), // origin, radius
-# Rectangle(Point, Size) // upper-left, dimensions
-# }
-# fn compute_area(shape: &Shape) -> f64 { 0.0 }
-fn select<'r, 'tmp, T>(shape: &'tmp Shape, threshold: f64,
- a: &'r T, b: &'r T) -> &'r T {
- if compute_area(shape) > threshold {a} else {b}
-}
-~~~
-
-Here you can see that `shape`'s lifetime is now named `tmp`. The
-parameters `a`, `b`, and the return value all have the lifetime `r`.
-However, since the lifetime `tmp` is not returned, it would be more
-concise to just omit the named lifetime for `shape` altogether:
-
-~~~
-# struct Point {x: f64, y: f64}; // as before
-# struct Size {w: f64, h: f64}; // as before
-# enum Shape {
-# Circle(Point, f64), // origin, radius
-# Rectangle(Point, Size) // upper-left, dimensions
-# }
-# fn compute_area(shape: &Shape) -> f64 { 0.0 }
-fn select<'r, T>(shape: &Shape, threshold: f64,
- a: &'r T, b: &'r T) -> &'r T {
- if compute_area(shape) > threshold {a} else {b}
-}
-~~~
-
-This is equivalent to the previous definition.
-
-# Conclusion
-
-So there you have it: a (relatively) brief tour of the borrowed pointer
-system. For more details, we refer to the (yet to be written) reference
-document on borrowed pointers, which will explain the full notation
-and give more examples.
+++ /dev/null
-% Rust Condition and Error-handling Tutorial
-
-# Introduction
-
-Rust does not provide exception handling[^why-no-exceptions]
-in the form most commonly seen in other programming languages such as C++ or Java.
-Instead, it provides four mechanisms that work together to handle errors or other rare events.
-The four mechanisms are:
-
- - Options
- - Results
- - Failure
- - Conditions
-
-This tutorial will lead you through use of these mechanisms
-in order to understand the trade-offs of each and relationships between them.
-
-# Example program
-
-This tutorial will be based around an example program
-that attempts to read lines from a file
-consisting of pairs of numbers,
-and then print them back out with slightly different formatting.
-The input to the program might look like this:
-
-~~~~ {.notrust}
-$ cat numbers.txt
-1 2
-34 56
-789 123
-45 67
-~~~~
-
-For which the intended output looks like this:
-
-~~~~ {.notrust}
-$ ./example numbers.txt
-0001, 0002
-0034, 0056
-0789, 0123
-0045, 0067
-~~~~
-
-An example program that does this task reads like this:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-fn main() {
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-
- // Path takes a generic by-value, rather than by reference
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
- let mut reader = BufferedReader::new(File::open(&path));
-
- // 1. Iterate over the lines of our file.
- for line in reader.lines() {
- // 2. Split the line into fields ("words").
- let fields = line.words().to_owned_vec();
- // 3. Match the vector of fields against a vector pattern.
- match fields {
-
- // 4. When the line had two fields:
- [a, b] => {
- // 5. Try parsing both fields as ints.
- match (from_str::<int>(a), from_str::<int>(b)) {
-
- // 6. If parsing succeeded for both, push both.
- (Some(a), Some(b)) => pairs.push((a,b)),
- // 7. Ignore non-int fields.
- _ => ()
- }
- }
- // 8. Ignore lines that don't have 2 fields.
- _ => ()
- }
- }
- pairs
-}
-~~~~
-
-This example shows the use of `Option`,
-along with some other forms of error-handling (and non-handling).
-We will look at these mechanisms
-and then modify parts of the example to perform "better" error handling.
-
-# Options
-
-The simplest and most lightweight mechanism in Rust for indicating an error is the type `std::option::Option<T>`.
-This type is a general purpose `enum`
-for conveying a value of type `T`, represented as `Some(T)`
-_or_ the sentinel `None`, to indicate the absence of a `T` value.
-For simple APIs, it may be sufficient to encode errors as `Option<T>`,
-returning `Some(T)` on success and `None` on error.
-In the example program, the call to `from_str::<int>` returns `Option<int>`
-with the understanding that "all parse errors" result in `None`.
-The resulting `Option<int>` values are matched against the pattern `(Some(a), Some(b))`
-in steps 5 and 6 in the example program,
-to handle the case in which both fields were parsed successfully.
-
-Using `Option` as in this API has some advantages:
-
- - Simple API, users can read it and guess how it works.
- - Very efficient, only an extra `enum` tag on return values.
- - Caller has flexibility in handling or propagating errors.
- - Caller is forced to acknowledge existence of possible-error before using value.
-
-However, it has serious disadvantages too:
-
- - Verbose, requires matching results or calling `Option::unwrap` everywhere.
- - Infects caller: if caller doesn't know how to handle the error, must propagate (or force).
- - Temptation to do just that: force the `Some(T)` case by blindly calling `unwrap`,
- which hides the error from the API without providing any way to make the program robust against the error.
- - Collapses all errors into one:
- - Caller can't handle different errors differently.
- - Caller can't even report a very precise error message
-
-Note that in order to keep the example code reasonably compact,
-several unwanted cases are silently ignored:
-lines that do not contain two fields, as well as fields that do not parse as ints.
-To propagate these cases to the caller using `Option` would require even more verbose code.
-
-# Results
-
-Before getting into _trapping_ the error,
-we will look at a slight refinement on the `Option` type above.
-This second mechanism for indicating an error is called a `Result`.
-The type `std::result::Result<T,E>` is another simple `enum` type with two forms, `Ok(T)` and `Err(E)`.
-The `Result` type is not substantially different from the `Option` type in terms of its ergonomics.
-Its main advantage is that the error constructor `Err(E)` can convey _more detail_ about the error.
-For example, the `from_str` API could be reformed
-to return a `Result` carrying an informative description of a parse error,
-like this:
-
-~~~~ {.ignore}
-enum IntParseErr {
- EmptyInput,
- Overflow,
- BadChar(char)
-}
-
-fn from_str(&str) -> Result<int,IntParseErr> {
- // ...
-}
-~~~~
-
-This would give the caller more information for both handling and reporting the error,
-but would otherwise retain the verbosity problems of using `Option`.
-In particular, it would still be necessary for the caller to return a further `Result` to _its_ caller if it did not want to handle the error.
-Manually propagating result values this way can be attractive in certain circumstances
-— for example when processing must halt on the very first error, or backtrack —
-but as we will see later, many cases have simpler options available.
-
-# Failure
-
-The third and arguably easiest mechanism for handling errors is called "failure".
-In fact it was hinted at earlier by suggesting that one can choose to propagate `Option` or `Result` types _or "force" them_.
-"Forcing" them, in this case, means calling a method like `Option<T>::unwrap`,
-which contains the following code:
-
-~~~~ {.ignore}
-pub fn unwrap(self) -> T {
- match self {
- Some(x) => return x,
- None => fail!("option::unwrap `None`")
- }
-}
-~~~~
-
-That is, it returns `T` when `self` is `Some(T)`, and _fails_ when `self` is `None`.
-
-Every Rust task can _fail_, either indirectly due to a kill signal or other asynchronous event,
-or directly by failing an `assert!` or calling the `fail!` macro.
-Failure is an _unrecoverable event_ at the task level:
-it causes the task to halt normal execution and unwind its control stack,
-freeing all task-local resources (the local heap as well as any task-owned values from the global heap)
-and running destructors (the `drop` method of the `Drop` trait)
-as frames are unwound and heap values destroyed.
-A failing task is not permitted to "catch" the unwinding during failure and recover,
-it is only allowed to clean up and exit.
-
-Failure has advantages:
-
- - Simple and non-verbose. Suitable for programs that can't reasonably continue past an error anyways.
- - _All_ errors (except memory-safety errors) can be uniformly trapped in a supervisory task outside the failing task.
- For a large program to be robust against a variety of errors,
- often some form of task-level partitioning to contain pervasive errors (arithmetic overflow, division by zero,
- logic bugs) is necessary anyways.
-
-As well as obvious disadvantages:
-
- - A blunt instrument, terminates the containing task entirely.
-
-Recall that in the first two approaches to error handling,
-the example program was only handling success cases, and ignoring error cases.
-That is, if the input is changed to contain a malformed line:
-
-~~~~ {.notrust}
-$ cat bad.txt
-1 2
-34 56
-ostrich
-789 123
-45 67
-~~~~
-
-Then the program would give the same output as if there was no error:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-0001, 0002
-0034, 0056
-0789, 0123
-0045, 0067
-~~~~
-
-If the example is rewritten to use failure, these error cases can be trapped.
-In this rewriting, failures are trapped by placing the I/O logic in a sub-task,
-and trapping its exit status using `task::try`:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-use std::task;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-fn main() {
-
- // Isolate failure within a subtask.
- let result = do task::try {
-
- // The protected logic.
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-
- };
- if result.is_err() {
- println("parsing failed");
- }
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- [a, b] => pairs.push((from_str::<int>(a).unwrap(),
- from_str::<int>(b).unwrap())),
-
- // Explicitly fail on malformed lines.
- _ => fail!()
- }
- }
- pairs
-}
-~~~~
-
-With these changes in place, running the program on malformed input gives a different answer:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-rust: task failed at 'explicit failure', ./example.rs:44
-parsing failed
-~~~~
-
-Note that while failure unwinds the sub-task performing I/O in `read_int_pairs`,
-control returns to `main` and can easily continue uninterrupted.
-In this case, control simply prints out `parsing failed` and then exits `main` (successfully).
-Failure of a (sub-)task is analogous to calling `exit(1)` or `abort()` in a unix C program:
-all the state of a sub-task is cleanly discarded on exit,
-and a supervisor task can take appropriate action
-without worrying about its own state having been corrupted.
-
-# Conditions
-
-The final mechanism for handling errors is called a "condition".
-Conditions are less blunt than failure, and less cumbersome than the `Option` or `Result` types;
-indeed they are designed to strike just the right balance between the two.
-Conditions require some care to use effectively, but give maximum flexibility with minimum verbosity.
-While conditions use exception-like terminology ("trap", "raise") they are significantly different:
-
- - Like exceptions and failure, conditions separate the site at which the error is raised from the site where it is trapped.
- - Unlike exceptions and unlike failure, when a condition is raised and trapped, _no unwinding occurs_.
- - A successfully trapped condition causes execution to continue _at the site of the error_, as though no error occurred.
-
-Conditions are declared with the `condition!` macro.
-Each condition has a name, an input type and an output type, much like a function.
-In fact, conditions are implemented as dynamically-scoped functions held in task local storage.
-
-The `condition!` macro declares a module with the name of the condition;
-the module contains a single static value called `cond`, of type `std::condition::Condition`.
-The `cond` value within the module is the rendezvous point
-between the site of error and the site that handles the error.
-It has two methods of interest: `raise` and `trap`.
-
-The `raise` method maps a value of the condition's input type to its output type.
-The input type should therefore convey all relevant information to the condition handler.
-The output type should convey all relevant information _for continuing execution at the site of error_.
-When the error site raises a condition handler,
-the `Condition::raise` method searches for the innermost installed task-local condition _handler_,
-and if any such handler is found, calls it with the provided input value.
-If no handler is found, `Condition::raise` will fail the task with an appropriate error message.
-
-Rewriting the example to use a condition in place of ignoring malformed lines makes it slightly longer,
-but similarly clear as the version that used `fail!` in the logic where the error occurs:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-// Introduce a new condition.
-condition! {
- pub malformed_line : ~str -> (int,int);
-}
-
-fn main() {
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- [a, b] => pairs.push((from_str::<int>(a).unwrap(),
- from_str::<int>(b).unwrap())),
- // On malformed lines, call the condition handler and
- // push whatever the condition handler returns.
- _ => pairs.push(malformed_line::cond.raise(line.clone()))
- }
- }
- pairs
-}
-~~~~
-
-When this is run on malformed input, it still fails,
-but with a slightly different failure message than before:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-rust: task failed at 'Unhandled condition: malformed_line: ~"ostrich"', .../libstd/condition.rs:43
-~~~~
-
-While this superficially resembles the trapped `fail!` call before,
-it is only because the example did not install a handler for the condition.
-The different failure message is indicating, among other things,
-that the condition-handling system is being invoked and failing
-only due to the absence of a _handler_ that traps the condition.
-
-# Trapping a condition
-
-To trap a condition, use `Condition::trap` in some caller of the site that calls `Condition::raise`.
-For example, this version of the program traps the `malformed_line` condition
-and replaces bad input lines with the pair `(-1,-1)`:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-condition! {
- pub malformed_line : ~str -> (int,int);
-}
-
-fn main() {
- // Trap the condition:
- malformed_line::cond.trap(|_| (-1,-1)).inside(|| {
-
- // The protected logic.
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-
- })
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- [a, b] => pairs.push((from_str::<int>(a).unwrap(),
- from_str::<int>(b).unwrap())),
- _ => pairs.push(malformed_line::cond.raise(line.clone()))
- }
- }
- pairs
-}
-~~~~
-
-Note that the remainder of the program is _unchanged_ with this trap in place;
-only the caller that installs the trap changed.
-Yet when the condition-trapping variant runs on the malformed input,
-it continues execution past the malformed line, substituting the handler's return value.
-
-~~~~ {.notrust}
-$ ./example bad.txt
-0001, 0002
-0034, 0056
--0001, -0001
-0789, 0123
-0045, 0067
-~~~~
-
-# Refining a condition
-
-As you work with a condition, you may find that the original set of options you present for recovery is insufficient.
-This is no different than any other issue of API design:
-a condition handler is an API for recovering from the condition, and sometimes APIs need to be enriched.
-In the example program, the first form of the `malformed_line` API implicitly assumes that recovery involves a substitute value.
-This assumption may not be correct; some callers may wish to skip malformed lines, for example.
-Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-// Modify the condition signature to return an Option.
-condition! {
- pub malformed_line : ~str -> Option<(int,int)>;
-}
-
-fn main() {
- // Trap the condition and return `None`
- malformed_line::cond.trap(|_| None).inside(|| {
-
- // The protected logic.
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-
- })
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- [a, b] => pairs.push((from_str::<int>(a).unwrap(),
- from_str::<int>(b).unwrap())),
-
- // On malformed lines, call the condition handler and
- // either ignore the line (if the handler returns `None`)
- // or push any `Some(pair)` value returned instead.
- _ => {
- match malformed_line::cond.raise(line.clone()) {
- Some(pair) => pairs.push(pair),
- None => ()
- }
- }
- }
- }
- pairs
-}
-~~~~
-
-Again, note that the remainder of the program is _unchanged_,
-in particular the signature of `read_int_pairs` is unchanged,
-even though the innermost part of its reading-loop has a new way of handling a malformed line.
-When the example is run with the `None` trap in place,
-the line is ignored as it was in the first example,
-but the choice of whether to ignore or use a substitute value has been moved to some caller,
-possibly a distant caller.
-
-~~~~ {.notrust}
-$ ./example bad.txt
-0001, 0002
-0034, 0056
-0789, 0123
-0045, 0067
-~~~~
-
-# Further refining a condition
-
-Like with any API, the process of refining argument and return types of a condition will continue,
-until all relevant combinations encountered in practice are encoded.
-In the example, suppose a third possible recovery form arose: reusing the previous value read.
-This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`.
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-// Introduce a new enum to convey condition-handling strategy to error site.
-pub enum MalformedLineFix {
- UsePair(int,int),
- IgnoreLine,
- UsePreviousLine
-}
-
-// Modify the condition signature to return the new enum.
-// Note: a condition introduces a new module, so the enum must be
-// named with the `super::` prefix to access it.
-condition! {
- pub malformed_line : ~str -> super::MalformedLineFix;
-}
-
-fn main() {
- // Trap the condition and return `UsePreviousLine`
- malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {
-
- // The protected logic.
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-
- })
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- [a, b] => pairs.push((from_str::<int>(a).unwrap(),
- from_str::<int>(b).unwrap())),
-
- // On malformed lines, call the condition handler and
- // take action appropriate to the enum value returned.
- _ => {
- match malformed_line::cond.raise(line.clone()) {
- UsePair(a,b) => pairs.push((a,b)),
- IgnoreLine => (),
- UsePreviousLine => {
- let prev = pairs[pairs.len() - 1];
- pairs.push(prev)
- }
- }
- }
- }
- }
- pairs
-}
-~~~~
-
-Running the example with `UsePreviousLine` as the fix code returned from the handler
-gives the expected result:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-0001, 0002
-0034, 0056
-0034, 0056
-0789, 0123
-0045, 0067
-~~~~
-
-At this point the example has a rich variety of recovery options,
-none of which is visible to casual users of the `read_int_pairs` function.
-This is intentional: part of the purpose of using a condition
-is to free intermediate callers from the burden of having to write repetitive error-propagation logic,
-and/or having to change function call and return types as error-handling strategies are refined.
-
-# Multiple conditions, intermediate callers
-
-So far the function trapping the condition and the function raising it have been immediately adjacent in the call stack.
-That is, the caller traps and its immediate callee raises.
-In most programs, the function that traps may be separated by very many function calls from the function that raises.
-Again, this is part of the point of using conditions:
-to support that separation without having to thread multiple error values and recovery strategies all the way through the program's main logic.
-
-Careful readers will notice that there is a remaining failure mode in the example program: the call to `.unwrap()` when parsing each integer.
-For example, when presented with a file that has the correct number of fields on a line,
-but a non-numeric value in one of them, such as this:
-
-~~~~ {.notrust}
-$ cat bad.txt
-1 2
-34 56
-7 marmot
-789 123
-45 67
-~~~~
-
-
-Then the program fails once more:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-task <unnamed> failed at 'called `Option::unwrap()` on a `None` value', .../libstd/option.rs:314
-~~~~
-
-To make the program robust — or at least flexible — in the face of this potential failure,
-a second condition and a helper function will suffice:
-
-~~~~
-# #[allow(unused_imports)];
-# extern mod extra;
-use std::io::buffered::BufferedReader;
-use std::io::File;
-# mod BufferedReader {
-# use std::io::File;
-# use std::io::mem::MemReader;
-# use std::io::buffered::BufferedReader;
-# static s : &'static [u8] = bytes!("1 2\n\
-# 34 56\n\
-# 789 123\n\
-# 45 67\n\
-# ");
-# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
-# BufferedReader::new(MemReader::new(s.to_owned()))
-# }
-# }
-
-pub enum MalformedLineFix {
- UsePair(int,int),
- IgnoreLine,
- UsePreviousLine
-}
-
-condition! {
- pub malformed_line : ~str -> ::MalformedLineFix;
-}
-
-// Introduce a second condition.
-condition! {
- pub malformed_int : ~str -> int;
-}
-
-fn main() {
- // Trap the `malformed_int` condition and return -1
- malformed_int::cond.trap(|_| -1).inside(|| {
-
- // Trap the `malformed_line` condition and return `UsePreviousLine`
- malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {
-
- // The protected logic.
- let pairs = read_int_pairs();
- for &(a,b) in pairs.iter() {
- println!("{:4.4d}, {:4.4d}", a, b);
- }
-
- })
- })
-}
-
-// Parse an int; if parsing fails, call the condition handler and
-// return whatever it returns.
-fn parse_int(x: &str) -> int {
- match from_str::<int>(x) {
- Some(v) => v,
- None => malformed_int::cond.raise(x.to_owned())
- }
-}
-
-fn read_int_pairs() -> ~[(int,int)] {
- let mut pairs = ~[];
-# let _g = std::io::ignore_io_error();
- let path = Path::new(&"foo.txt");
-
- let mut reader = BufferedReader::new(File::open(&path));
- for line in reader.lines() {
- match line.words().to_owned_vec() {
- // Delegate parsing ints to helper function that will
- // handle parse errors by calling `malformed_int`.
- [a, b] => pairs.push((parse_int(a), parse_int(b))),
-
- _ => {
- match malformed_line::cond.raise(line.clone()) {
- UsePair(a,b) => pairs.push((a,b)),
- IgnoreLine => (),
- UsePreviousLine => {
- let prev = pairs[pairs.len() - 1];
- pairs.push(prev)
- }
- }
- }
- }
- }
- pairs
-}
-~~~~
-
-Again, note that `read_int_pairs` has not changed signature,
-nor has any of the machinery for trapping or raising `malformed_line`,
-but now the program can handle the "right number of fields, non-integral field" form of bad input:
-
-~~~~ {.notrust}
-$ ./example bad.txt
-0001, 0002
-0034, 0056
-0007, -0001
-0789, 0123
-0045, 0067
-~~~~
-
-There are three other things to note in this variant of the example program:
-
- - It traps multiple conditions simultaneously,
- nesting the protected logic of one `trap` call inside the other.
-
- - There is a function in between the `trap` site and `raise` site for the `malformed_int` condition.
- There could be any number of calls between them:
- so long as the `raise` occurs within a callee (of any depth) of the logic protected by the `trap` call,
- it will invoke the handler.
-
- - This variant insulates callers from a design choice in the library:
- the `from_str` function was designed to return an `Option<int>`,
- but this program insulates callers from that choice,
- routing all `None` values that arise from parsing integers in this file into the condition.
-
-
-# When to use which technique
-
-This tutorial explored several techniques for handling errors.
-Each is appropriate to different circumstances:
-
- - If an error may be extremely frequent, expected, and very likely dealt with by an immediate caller,
- then returning an `Option` or `Result` type is best. These types force the caller to handle the error,
- and incur the lowest speed overhead, usually only returning one extra word to tag the return value.
- Between `Option` and `Result`: use an `Option` when there is only one kind of error,
- otherwise make an `enum FooErr` to represent the possible error codes and use `Result<T,FooErr>`.
-
- - If an error can reasonably be handled at the site it occurs by one of a few strategies — possibly including failure —
- and it is not clear which strategy a caller would want to use, a condition is best.
- For many errors, the only reasonable "non-stop" recovery strategies are to retry some number of times,
- create or substitute an empty or sentinel value, ignore the error, or fail.
-
- - If an error cannot reasonably be handled at the site it occurs,
- and the only reasonable response is to abandon a large set of operations in progress,
- then directly failing is best.
-
-Note that an unhandled condition will cause failure (along with a more-informative-than-usual message),
-so if there is any possibility that a caller might wish to "ignore and keep going",
-it is usually harmless to use a condition in place of a direct call to `fail!()`.
-
-
-[^why-no-exceptions]: Exceptions in languages like C++ and Java permit unwinding, like Rust's failure system,
-but with the option to halt unwinding partway through the process and continue execution.
-This behavior unfortunately means that the _heap_ may be left in an inconsistent but accessible state,
-if an exception is thrown part way through the process of initializing or modifying memory.
-To compensate for this risk, correct C++ and Java code must program in an extremely elaborate and difficult "exception-safe" style
-— effectively transactional style against heap structures —
-or else risk introducing silent and very difficult-to-debug errors due to control resuming in a corrupted heap after a caught exception.
-These errors are frequently memory-safety errors, which Rust strives to eliminate,
-and so Rust unwinding is unrecoverable within a single task:
-once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
+++ /dev/null
-% Containers and iterators
-
-# Containers
-
-The container traits are defined in the `std::container` module.
-
-## Unique vectors
-
-Vectors have `O(1)` indexing, push (to the end) and pop (from the end). Vectors
-are the most common container in Rust, and are flexible enough to fit many use
-cases.
-
-Vectors can also be sorted and used as efficient lookup tables with the
-`bsearch()` method, if all the elements are inserted at one time and
-deletions are unnecessary.
-
-## Maps and sets
-
-Maps are collections of unique keys with corresponding values, and sets are
-just unique keys without a corresponding value. The `Map` and `Set` traits in
-`std::container` define the basic interface.
-
-The standard library provides three owned map/set types:
-
-* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to
- implement `Eq` and `Hash`
-* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint`
-* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys
- to implement `TotalOrd`
-
-These maps do not use managed pointers so they can be sent between tasks as
-long as the key and value types are sendable. Neither the key or value type has
-to be copyable.
-
-The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
-order.
-
-Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
-making the order of a set of keys in a given hash table randomized. Rust
-provides a [SipHash](https://131002.net/siphash/) implementation for any type
-implementing the `IterBytes` trait.
-
-## Double-ended queues
-
-The `extra::ringbuf` module implements a double-ended queue with `O(1)`
-amortized inserts and removals from both ends of the container. It also has
-`O(1)` indexing like a vector. The contained elements are not required to be
-copyable, and the queue will be sendable if the contained type is sendable.
-Its interface `Deque` is defined in `extra::collections`.
-
-The `extra::dlist` module implements a double-ended linked list, also
-implementing the `Deque` trait, with `O(1)` removals and inserts at either end,
-and `O(1)` concatenation.
-
-## Priority queues
-
-The `extra::priority_queue` module implements a queue ordered by a key. The
-contained elements are not required to be copyable, and the queue will be
-sendable if the contained type is sendable.
-
-Insertions have `O(log n)` time complexity and checking or popping the largest
-element is `O(1)`. Converting a vector to a priority queue can be done
-in-place, and has `O(n)` complexity. A priority queue can also be converted to
-a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
-heapsort.
-
-# Iterators
-
-## Iteration protocol
-
-The iteration protocol is defined by the `Iterator` trait in the
-`std::iter` module. The minimal implementation of the trait is a `next`
-method, yielding the next element from an iterator object:
-
-~~~
-/// An infinite stream of zeroes
-struct ZeroStream;
-
-impl Iterator<int> for ZeroStream {
- fn next(&mut self) -> Option<int> {
- Some(0)
- }
-}
-~~~~
-
-Reaching the end of the iterator is signalled by returning `None` instead of
-`Some(item)`:
-
-~~~
-# fn main() {}
-/// A stream of N zeroes
-struct ZeroStream {
- priv remaining: uint
-}
-
-impl ZeroStream {
- fn new(n: uint) -> ZeroStream {
- ZeroStream { remaining: n }
- }
-}
-
-impl Iterator<int> for ZeroStream {
- fn next(&mut self) -> Option<int> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- Some(0)
- }
- }
-}
-~~~
-
-In general, you cannot rely on the behavior of the `next()` method after it has
-returned `None`. Some iterators may return `None` forever. Others may behave
-differently.
-
-## Container iterators
-
-Containers implement iteration over the contained elements by returning an
-iterator object. For example, vector slices several iterators available:
-
-* `iter()` and `rev_iter()`, for immutable references to the elements
-* `mut_iter()` and `mut_rev_iter()`, for mutable references to the elements
-* `move_iter()` and `move_rev_iter()`, to move the elements out by-value
-
-A typical mutable container will implement at least `iter()`, `mut_iter()` and
-`move_iter()` along with the reverse variants if it maintains an order.
-
-### Freezing
-
-Unlike most other languages with external iterators, Rust has no *iterator
-invalidation*. As long an iterator is still in scope, the compiler will prevent
-modification of the container through another handle.
-
-~~~
-let mut xs = [1, 2, 3];
-{
- let _it = xs.iter();
-
- // the vector is frozen for this scope, the compiler will statically
- // prevent modification
-}
-// the vector becomes unfrozen again at the end of the scope
-~~~
-
-These semantics are due to most container iterators being implemented with `&`
-and `&mut`.
-
-## Iterator adaptors
-
-The `Iterator` trait provides many common algorithms as default methods. For
-example, the `fold` method will accumulate the items yielded by an `Iterator`
-into a single value:
-
-~~~
-let xs = [1, 9, 2, 3, 14, 12];
-let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
-assert_eq!(result, -41);
-~~~
-
-Most adaptors return an adaptor object implementing the `Iterator` trait itself:
-
-~~~
-let xs = [1, 9, 2, 3, 14, 12];
-let ys = [5, 2, 1, 8];
-let sum = xs.iter().chain(ys.iter()).fold(0, |a, b| a + *b);
-assert_eq!(sum, 57);
-~~~
-
-Some iterator adaptors may return `None` before exhausting the underlying
-iterator. Additionally, if these iterator adaptors are called again after
-returning `None`, they may call their underlying iterator again even if the
-adaptor will continue to return `None` forever. This may not be desired if the
-underlying iterator has side-effects.
-
-In order to provide a guarantee about behavior once `None` has been returned, an
-iterator adaptor named `fuse()` is provided. This returns an iterator that will
-never call its underlying iterator again once `None` has been returned:
-
-~~~
-let xs = [1,2,3,4,5];
-let mut calls = 0;
-let it = xs.iter().scan((), |_, x| {
- calls += 1;
- if *x < 3 { Some(x) } else { None }});
-// the iterator will only yield 1 and 2 before returning None
-// If we were to call it 5 times, calls would end up as 5, despite only 2 values
-// being yielded (and therefore 3 unique calls being made). The fuse() adaptor
-// can fix this.
-let mut it = it.fuse();
-it.next();
-it.next();
-it.next();
-it.next();
-it.next();
-assert_eq!(calls, 3);
-~~~
-
-## For loops
-
-The function `range` (or `range_inclusive`) allows to simply iterate through a given range:
-
-~~~
-for i in range(0, 5) {
- print!("{} ", i) // prints "0 1 2 3 4"
-}
-
-for i in std::iter::range_inclusive(0, 5) { // needs explicit import
- print!("{} ", i) // prints "0 1 2 3 4 5"
-}
-~~~
-
-The `for` keyword can be used as sugar for iterating through any iterator:
-
-~~~
-let xs = [2u, 3, 5, 7, 11, 13, 17];
-
-// print out all the elements in the vector
-for x in xs.iter() {
- println(x.to_str())
-}
-
-// print out all but the first 3 elements in the vector
-for x in xs.iter().skip(3) {
- println(x.to_str())
-}
-~~~
-
-For loops are *often* used with a temporary iterator object, as above. They can
-also advance the state of an iterator in a mutable location:
-
-~~~
-let xs = [1, 2, 3, 4, 5];
-let ys = ["foo", "bar", "baz", "foobar"];
-
-// create an iterator yielding tuples of elements from both vectors
-let mut it = xs.iter().zip(ys.iter());
-
-// print out the pairs of elements up to (&3, &"baz")
-for (x, y) in it {
- println!("{} {}", *x, *y);
-
- if *x == 3 {
- break;
- }
-}
-
-// yield and print the last pair from the iterator
-println!("last: {:?}", it.next());
-
-// the iterator is now fully consumed
-assert!(it.next().is_none());
-~~~
-
-## Conversion
-
-Iterators offer generic conversion to containers with the `collect` adaptor:
-
-~~~
-let xs = [0, 1, 1, 2, 3, 5, 8];
-let ys = xs.rev_iter().skip(1).map(|&x| x * 2).collect::<~[int]>();
-assert_eq!(ys, ~[10, 6, 4, 2, 2, 0]);
-~~~
-
-The method requires a type hint for the container type, if the surrounding code
-does not provide sufficient information.
-
-Containers can provide conversion from iterators through `collect` by
-implementing the `FromIterator` trait. For example, the implementation for
-vectors is as follows:
-
-~~~ {.xfail-test}
-impl<A> FromIterator<A> for ~[A] {
- pub fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
- let (lower, _) = iterator.size_hint();
- let mut xs = with_capacity(lower);
- for x in iterator {
- xs.push(x);
- }
- xs
- }
-}
-~~~
-
-### Size hints
-
-The `Iterator` trait provides a `size_hint` default method, returning a lower
-bound and optionally on upper bound on the length of the iterator:
-
-~~~ {.xfail-test}
-fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
-~~~
-
-The vector implementation of `FromIterator` from above uses the lower bound
-to pre-allocate enough space to hold the minimum number of elements the
-iterator will yield.
-
-The default implementation is always correct, but it should be overridden if
-the iterator can provide better information.
-
-The `ZeroStream` from earlier can provide an exact lower and upper bound:
-
-~~~
-# fn main() {}
-/// A stream of N zeroes
-struct ZeroStream {
- priv remaining: uint
-}
-
-impl ZeroStream {
- fn new(n: uint) -> ZeroStream {
- ZeroStream { remaining: n }
- }
-
- fn size_hint(&self) -> (uint, Option<uint>) {
- (self.remaining, Some(self.remaining))
- }
-}
-
-impl Iterator<int> for ZeroStream {
- fn next(&mut self) -> Option<int> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- Some(0)
- }
- }
-}
-~~~
-
-## Double-ended iterators
-
-The `DoubleEndedIterator` trait represents an iterator able to yield elements
-from either end of a range. It inherits from the `Iterator` trait and extends
-it with the `next_back` function.
-
-A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning
-another `DoubleEndedIterator` with `next` and `next_back` exchanged.
-
-~~~
-let xs = [1, 2, 3, 4, 5, 6];
-let mut it = xs.iter();
-println!("{:?}", it.next()); // prints `Some(&1)`
-println!("{:?}", it.next()); // prints `Some(&2)`
-println!("{:?}", it.next_back()); // prints `Some(&6)`
-
-// prints `5`, `4` and `3`
-for &x in it.invert() {
- println!("{}", x)
-}
-~~~
-
-The `rev_iter` and `mut_rev_iter` methods on vectors just return an inverted
-version of the standard immutable and mutable vector iterators.
-
-The `chain`, `map`, `filter`, `filter_map` and `inspect` adaptors are
-`DoubleEndedIterator` implementations if the underlying iterators are.
-
-~~~
-let xs = [1, 2, 3, 4];
-let ys = [5, 6, 7, 8];
-let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
-
-println!("{:?}", it.next()); // prints `Some(2)`
-
-// prints `16`, `14`, `12`, `10`, `8`, `6`, `4`
-for x in it.invert() {
- println!("{}", x);
-}
-~~~
-
-The `reverse_` method is also available for any double-ended iterator yielding
-mutable references. It can be used to reverse a container in-place. Note that
-the trailing underscore is a workaround for issue #5898 and will be removed.
-
-~~~
-let mut ys = [1, 2, 3, 4, 5];
-ys.mut_iter().reverse_();
-assert_eq!(ys, [5, 4, 3, 2, 1]);
-~~~
-
-## Random-access iterators
-
-The `RandomAccessIterator` trait represents an iterator offering random access
-to the whole range. The `indexable` method retrieves the number of elements
-accessible with the `idx` method.
-
-The `chain` adaptor is an implementation of `RandomAccessIterator` if the
-underlying iterators are.
-
-~~~
-let xs = [1, 2, 3, 4, 5];
-let ys = ~[7, 9, 11];
-let mut it = xs.iter().chain(ys.iter());
-println!("{:?}", it.idx(0)); // prints `Some(&1)`
-println!("{:?}", it.idx(5)); // prints `Some(&7)`
-println!("{:?}", it.idx(7)); // prints `Some(&11)`
-println!("{:?}", it.idx(8)); // prints `None`
-
-// yield two elements from the beginning, and one from the end
-it.next();
-it.next();
-it.next_back();
-
-println!("{:?}", it.idx(0)); // prints `Some(&3)`
-println!("{:?}", it.idx(4)); // prints `Some(&9)`
-println!("{:?}", it.idx(6)); // prints `None`
-~~~
+++ /dev/null
-% Rust Foreign Function Interface Tutorial
-
-# Introduction
-
-This tutorial will use the [snappy](https://code.google.com/p/snappy/)
-compression/decompression library as an introduction to writing bindings for
-foreign code. Rust is currently unable to call directly into a C++ library, but
-snappy includes a C interface (documented in
-[`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)).
-
-The following is a minimal example of calling a foreign function which will
-compile if snappy is installed:
-
-~~~~ {.xfail-test}
-use std::libc::size_t;
-
-#[link(name = "snappy")]
-extern {
- fn snappy_max_compressed_length(source_length: size_t) -> size_t;
-}
-
-fn main() {
- let x = unsafe { snappy_max_compressed_length(100) };
- println!("max compressed length of a 100 byte buffer: {}", x);
-}
-~~~~
-
-The `extern` block is a list of function signatures in a foreign library, in
-this case with the platform's C ABI. The `#[link(...)]` attribute is used to
-instruct the linker to link against the snappy library so the symbols are
-resolved.
-
-Foreign functions are assumed to be unsafe so calls to them need to be wrapped
-with `unsafe {}` as a promise to the compiler that everything contained within
-truly is safe. C libraries often expose interfaces that aren't thread-safe, and
-almost any function that takes a pointer argument isn't valid for all possible
-inputs since the pointer could be dangling, and raw pointers fall outside of
-Rust's safe memory model.
-
-When declaring the argument types to a foreign function, the Rust compiler can
-not check if the declaration is correct, so specifying it correctly is part of
-keeping the binding correct at runtime.
-
-The `extern` block can be extended to cover the entire snappy API:
-
-~~~~ {.xfail-test}
-use std::libc::{c_int, size_t};
-
-#[link(name = "snappy")]
-extern {
- fn snappy_compress(input: *u8,
- input_length: size_t,
- compressed: *mut u8,
- compressed_length: *mut size_t) -> c_int;
- fn snappy_uncompress(compressed: *u8,
- compressed_length: size_t,
- uncompressed: *mut u8,
- uncompressed_length: *mut size_t) -> c_int;
- fn snappy_max_compressed_length(source_length: size_t) -> size_t;
- fn snappy_uncompressed_length(compressed: *u8,
- compressed_length: size_t,
- result: *mut size_t) -> c_int;
- fn snappy_validate_compressed_buffer(compressed: *u8,
- compressed_length: size_t) -> c_int;
-}
-~~~~
-
-# Creating a safe interface
-
-The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts
-like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe
-internal details.
-
-Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust
-vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The
-length is number of elements currently contained, and the capacity is the total size in elements of
-the allocated memory. The length is less than or equal to the capacity.
-
-~~~~ {.xfail-test}
-pub fn validate_compressed_buffer(src: &[u8]) -> bool {
- unsafe {
- snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
- }
-}
-~~~~
-
-The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the
-guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
-signature.
-
-The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
-allocated to hold the output too.
-
-The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum
-required capacity to hold the compressed output. The vector can then be passed to the
-`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
-the true length after compression for setting the length.
-
-~~~~ {.xfail-test}
-pub fn compress(src: &[u8]) -> ~[u8] {
- unsafe {
- let srclen = src.len() as size_t;
- let psrc = src.as_ptr();
-
- let mut dstlen = snappy_max_compressed_length(srclen);
- let mut dst = vec::with_capacity(dstlen as uint);
- let pdst = dst.as_mut_ptr();
-
- snappy_compress(psrc, srclen, pdst, &mut dstlen);
- dst.set_len(dstlen as uint);
- dst
- }
-}
-~~~~
-
-Decompression is similar, because snappy stores the uncompressed size as part of the compression
-format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
-
-~~~~ {.xfail-test}
-pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
- unsafe {
- let srclen = src.len() as size_t;
- let psrc = src.as_ptr();
-
- let mut dstlen: size_t = 0;
- snappy_uncompressed_length(psrc, srclen, &mut dstlen);
-
- let mut dst = vec::with_capacity(dstlen as uint);
- let pdst = dst.as_mut_ptr();
-
- if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
- dst.set_len(dstlen as uint);
- Some(dst)
- } else {
- None // SNAPPY_INVALID_INPUT
- }
- }
-}
-~~~~
-
-For reference, the examples used here are also available as an [library on
-GitHub](https://github.com/thestinger/rust-snappy).
-
-# Stack management
-
-Rust tasks by default run on a "large stack". This is actually implemented as a
-reserving a large segment of the address space and then lazily mapping in pages
-as they are needed. When calling an external C function, the code is invoked on
-the same stack as the rust stack. This means that there is no extra
-stack-switching mechanism in place because it is assumed that the large stack
-for the rust task is plenty for the C function to have.
-
-A planned future improvement (net yet implemented at the time of this writing)
-is to have a guard page at the end of every rust stack. No rust function will
-hit this guard page (due to Rust's usage of LLVM's `__morestack`). The intention
-for this unmapped page is to prevent infinite recursion in C from overflowing
-onto other rust stacks. If the guard page is hit, then the process will be
-terminated with a message saying that the guard page was hit.
-
-For normal external function usage, this all means that there shouldn't be any
-need for any extra effort on a user's perspective. The C stack naturally
-interleaves with the rust stack, and it's "large enough" for both to
-interoperate. If, however, it is determined that a larger stack is necessary,
-there are appropriate functions in the task spawning API to control the size of
-the stack of the task which is spawned.
-
-# Destructors
-
-Foreign libraries often hand off ownership of resources to the calling code.
-When this occurs, we must use Rust's destructors to provide safety and guarantee
-the release of these resources (especially in the case of failure).
-
-As an example, we give a reimplementation of owned boxes by wrapping `malloc`
-and `free`:
-
-~~~~
-use std::cast;
-use std::libc::{c_void, size_t, malloc, free};
-use std::ptr;
-use std::unstable::intrinsics;
-
-// Define a wrapper around the handle returned by the foreign code.
-// Unique<T> has the same semantics as ~T
-pub struct Unique<T> {
- // It contains a single raw, mutable pointer to the object in question.
- priv ptr: *mut T
-}
-
-// Implement methods for creating and using the values in the box.
-// NB: For simplicity and correctness, we require that T has kind Send
-// (owned boxes relax this restriction, and can contain managed (GC) boxes).
-// This is because, as implemented, the garbage collector would not know
-// about any shared boxes stored in the malloc'd region of memory.
-impl<T: Send> Unique<T> {
- pub fn new(value: T) -> Unique<T> {
- unsafe {
- let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
- assert!(!ptr::is_null(ptr));
- // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
- // move_val_init moves a value into this memory without
- // attempting to drop the original value.
- intrinsics::move_val_init(&mut *ptr, value);
- Unique{ptr: ptr}
- }
- }
-
- // the 'r lifetime results in the same semantics as `&*x` with ~T
- pub fn borrow<'r>(&'r self) -> &'r T {
- unsafe { cast::copy_lifetime(self, &*self.ptr) }
- }
-
- // the 'r lifetime results in the same semantics as `&mut *x` with ~T
- pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
- unsafe { cast::copy_mut_lifetime(self, &mut *self.ptr) }
- }
-}
-
-// The key ingredient for safety, we associate a destructor with
-// Unique<T>, making the struct manage the raw pointer: when the
-// struct goes out of scope, it will automatically free the raw pointer.
-// NB: This is an unsafe destructor, because rustc will not normally
-// allow destructors to be associated with parametrized types, due to
-// bad interaction with managed boxes. (With the Send restriction,
-// we don't have this problem.)
-#[unsafe_destructor]
-impl<T: Send> Drop for Unique<T> {
- fn drop(&mut self) {
- unsafe {
- let x = intrinsics::uninit(); // dummy value to swap in
- // We need to move the object out of the box, so that
- // the destructor is called (at the end of this scope.)
- ptr::replace_ptr(self.ptr, x);
- free(self.ptr as *c_void)
- }
- }
-}
-
-// A comparison between the built-in ~ and this reimplementation
-fn main() {
- {
- let mut x = ~5;
- *x = 10;
- } // `x` is freed here
-
- {
- let mut y = Unique::new(5);
- *y.borrow_mut() = 10;
- } // `y` is freed here
-}
-~~~~
-
-# Linking
-
-The `link` attribute on `extern` blocks provides the basic building block for
-instructing rustc how it will link to native libraries. There are two accepted
-forms of the link attribute today:
-
-* `#[link(name = "foo")]`
-* `#[link(name = "foo", kind = "bar")]`
-
-In both of these cases, `foo` is the name of the native library that we're
-linking to, and in the second case `bar` is the type of native library that the
-compiler is linking to. There are currently three known types of native
-libraries:
-
-* Dynamic - `#[link(name = "readline")]
-* Static - `#[link(name = "my_build_dependency", kind = "static")]
-* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]
-
-Note that frameworks are only available on OSX targets.
-
-The different `kind` values are meant to differentiate how the native library
-participates in linkage. From a linkage perspective, the rust compiler creates
-two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
-Native dynamic libraries and frameworks are propagated to the final artifact
-boundary, while static libraries are not propagated at all.
-
-A few examples of how this model can be used are:
-
-* A native build dependency. Sometimes some C/C++ glue is needed when writing
- some rust code, but distribution of the C/C++ code in a library format is just
- a burden. In this case, the code will be archived into `libfoo.a` and then the
- rust crate would declare a dependency via `#[link(name = "foo", kind =
- "static")]`.
-
- Regardless of the flavor of output for the crate, the native static library
- will be included in the output, meaning that distribution of the native static
- library is not necessary.
-
-* A normal dynamic dependency. Common system libraries (like `readline`) are
- available on a large number of systems, and often a static copy of these
- libraries cannot be found. When this dependency is included in a rust crate,
- partial targets (like rlibs) will not link to the library, but when the rlib
- is included in a final target (like a binary), the native library will be
- linked in.
-
-On OSX, frameworks behave with the same semantics as a dynamic library.
-
-## The `link_args` attribute
-
-There is one other way to tell rustc how to customize linking, and that is via
-the `link_args` attribute. This attribute is applied to `extern` blocks and
-specifies raw flags which need to get passed to the linker when producing an
-artifact. An example usage would be:
-
-~~~ {.xfail-test}
-#[link_args = "-foo -bar -baz"]
-extern {}
-~~~
-
-Note that this feature is currently hidden behind the `feature(link_args)` gate
-because this is not a sanctioned way of performing linking. Right now rustc
-shells out to the system linker, so it makes sense to provide extra command line
-arguments, but this will not always be the case. In the future rustc may use
-LLVM directly to link native libraries in which case `link_args` will have no
-meaning.
-
-It is highly recommended to *not* use this attribute, and rather use the more
-formal `#[link(...)]` attribute on `extern` blocks instead.
-
-# Unsafe blocks
-
-Some operations, like dereferencing unsafe pointers or calling functions that have been marked
-unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
-the compiler that the unsafety does not leak out of the block.
-
-Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
-this:
-
-~~~~
-unsafe fn kaboom(ptr: *int) -> int { *ptr }
-~~~~
-
-This function can only be called from an `unsafe` block or another `unsafe` function.
-
-# Accessing foreign globals
-
-Foreign APIs often export a global variable which could do something like track
-global state. In order to access these variables, you declare them in `extern`
-blocks with the `static` keyword:
-
-~~~{.xfail-test}
-use std::libc;
-
-#[link(name = "readline")]
-extern {
- static rl_readline_version: libc::c_int;
-}
-
-fn main() {
- println!("You have readline version {} installed.",
- rl_readline_version as int);
-}
-~~~
-
-Alternatively, you may need to alter global state provided by a foreign
-interface. To do this, statics can be declared with `mut` so rust can mutate
-them.
-
-~~~{.xfail-test}
-use std::libc;
-use std::ptr;
-
-#[link(name = "readline")]
-extern {
- static mut rl_prompt: *libc::c_char;
-}
-
-fn main() {
- do "[my-awesome-shell] $".as_c_str |buf| {
- unsafe { rl_prompt = buf; }
- // get a line, process it
- unsafe { rl_prompt = ptr::null(); }
- }
-}
-~~~
-
-# Foreign calling conventions
-
-Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
-calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
-conventions. Rust provides a way to tell the compiler which convention to use:
-
-~~~~
-#[cfg(target_os = "win32", target_arch = "x86")]
-#[link_name = "kernel32"]
-extern "stdcall" {
- fn SetEnvironmentVariableA(n: *u8, v: *u8) -> std::libc::c_int;
-}
-~~~~
-
-This applies to the entire `extern` block. The list of supported ABI constraints
-are:
-
-* `stdcall`
-* `aapcs`
-* `cdecl`
-* `fastcall`
-* `Rust`
-* `rust-intrinsic`
-* `system`
-* `C`
-
-Most of the abis in this list are self-explanatory, but the `system` abi may
-seem a little odd. This constraint selects whatever the appropriate ABI is for
-interoperating with the target's libraries. For example, on win32 with a x86
-architecture, this means that the abi used would be `stdcall`. On x86_64,
-however, windows uses the `C` calling convention, so `C` would be used. This
-means that in our previous example, we could have used `extern "system" { ... }`
-to define a block for all windows systems, not just x86 ones.
-
-# Interoperability with foreign code
-
-Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C.
-A `#[packed]` attribute is available, which will lay out the struct members without padding.
-However, there are currently no guarantees about the layout of an `enum`.
-
-Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained
-object. However, they should not be manually created because they are managed by internal
-allocators. Borrowed pointers can safely be assumed to be non-nullable pointers directly to the
-type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so
-prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions
-about them.
-
-Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and
-`str` modules for working with C APIs. However, strings are not terminated with `\0`. If you need a
-NUL-terminated string for interoperability with C, you should use the `c_str::to_c_str` function.
-
-The standard library includes type aliases and function definitions for the C standard library in
-the `libc` module, and Rust links against `libc` and `libm` by default.
+++ /dev/null
-% Rust Macros Tutorial
-
-# Introduction
-
-Functions are the primary tool that programmers can use to build abstractions.
-Sometimes, however, programmers want to abstract over compile-time syntax
-rather than run-time values.
-Macros provide syntactic abstraction.
-For an example of how this can be useful, consider the following two code fragments,
-which both pattern-match on their input and both return early in one case,
-doing nothing otherwise:
-
-~~~~
-# enum t { special_a(uint), special_b(uint) };
-# fn f() -> uint {
-# let input_1 = special_a(0);
-# let input_2 = special_a(0);
-match input_1 {
- special_a(x) => { return x; }
- _ => {}
-}
-// ...
-match input_2 {
- special_b(x) => { return x; }
- _ => {}
-}
-# return 0u;
-# }
-~~~~
-
-This code could become tiresome if repeated many times.
-However, no function can capture its functionality to make it possible
-to abstract the repetition away.
-Rust's macro system, however, can eliminate the repetition. Macros are
-lightweight custom syntax extensions, themselves defined using the
-`macro_rules!` syntax extension. The following `early_return` macro captures
-the pattern in the above code:
-
-~~~~
-# enum t { special_a(uint), special_b(uint) };
-# fn f() -> uint {
-# let input_1 = special_a(0);
-# let input_2 = special_a(0);
-macro_rules! early_return(
- ($inp:expr $sp:ident) => ( // invoke it like `(input_5 special_e)`
- match $inp {
- $sp(x) => { return x; }
- _ => {}
- }
- );
-)
-// ...
-early_return!(input_1 special_a);
-// ...
-early_return!(input_2 special_b);
-# return 0;
-# }
-~~~~
-
-Macros are defined in pattern-matching style: in the above example, the text
-`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
-*macro invocation syntax*, a pattern denoting how to write a call to the
-macro. The text on the right-hand side of the `=>`, beginning with `match
-$inp`, is the *macro transcription syntax*: what the macro expands to.
-
-# Invocation syntax
-
-The macro invocation syntax specifies the syntax for the arguments to the
-macro. It appears on the left-hand side of the `=>` in a macro definition. It
-conforms to the following rules:
-
-1. It must be surrounded by parentheses.
-2. `$` has special meaning (described below).
-3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
-forbidden.
-
-Otherwise, the invocation syntax is free-form.
-
-To take as an argument a fragment of Rust code, write `$` followed by a name
- (for use on the right-hand side), followed by a `:`, followed by a *fragment
- specifier*. The fragment specifier denotes the sort of fragment to match. The
- most common fragment specifiers are:
-
-* `ident` (an identifier, referring to a variable or item. Examples: `f`, `x`,
- `foo`.)
-* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
- `f(42)`.)
-* `ty` (a type. Examples: `int`, `~[(char, ~str)]`, `&T`.)
-* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
- a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
-* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
-
-The parser interprets any token that's not preceded by a `$` literally. Rust's usual
-rules of tokenization apply,
-
-So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
-that could be invoked like: `my_macro!(i->(( 2+2 )))`.
-
-## Invocation location
-
-A macro invocation may take the place of (and therefore expand to)
-an expression, an item, or a statement.
-The Rust parser will parse the macro invocation as a "placeholder"
-for whichever of those three nonterminals is appropriate for the location.
-
-At expansion time, the output of the macro will be parsed as whichever of the
-three nonterminals it stands in for. This means that a single macro might,
-for example, expand to an item or an expression, depending on its arguments
-(and cause a syntax error if it is called with the wrong argument for its
-location). Although this behavior sounds excessively dynamic, it is known to
-be useful under some circumstances.
-
-
-# Transcription syntax
-
-The right-hand side of the `=>` follows the same rules as the left-hand side,
-except that a `$` need only be followed by the name of the syntactic fragment
-to transcribe into the macro expansion; its type need not be repeated.
-
-The right-hand side must be enclosed by delimiters, which the transcriber ignores.
-Therefore `() => ((1,2,3))` is a macro that expands to a tuple expression,
-`() => (let $x=$val)` is a macro that expands to a statement,
-and `() => (1,2,3)` is a macro that expands to a syntax error
-(since the transcriber interprets the parentheses on the right-hand-size as delimiters,
-and `1,2,3` is not a valid Rust expression on its own).
-
-Except for permissibility of `$name` (and `$(...)*`, discussed below), the
-right-hand side of a macro definition is ordinary Rust syntax. In particular,
-macro invocations (including invocations of the macro currently being defined)
-are permitted in expression, statement, and item locations. However, nothing
-else about the code is examined or executed by the macro system; execution
-still has to wait until run-time.
-
-## Interpolation location
-
-The interpolation `$argument_name` may appear in any location consistent with
-its fragment specifier (i.e., if it is specified as `ident`, it may be used
-anywhere an identifier is permitted).
-
-# Multiplicity
-
-## Invocation
-
-Going back to the motivating example, recall that `early_return` expanded into
-a `match` that would `return` if the `match`'s scrutinee matched the
-"special case" identifier provided as the second argument to `early_return`,
-and do nothing otherwise. Now suppose that we wanted to write a
-version of `early_return` that could handle a variable number of "special"
-cases.
-
-The syntax `$(...)*` on the left-hand side of the `=>` in a macro definition
-accepts zero or more occurrences of its contents. It works much
-like the `*` operator in regular expressions. It also supports a
-separator token (a comma-separated list could be written `$(...),*`), and `+`
-instead of `*` to mean "at least one".
-
-~~~~
-# enum t { special_a(uint),special_b(uint),special_c(uint),special_d(uint)};
-# fn f() -> uint {
-# let input_1 = special_a(0);
-# let input_2 = special_a(0);
-macro_rules! early_return(
- ($inp:expr, [ $($sp:ident)|+ ]) => (
- match $inp {
- $(
- $sp(x) => { return x; }
- )+
- _ => {}
- }
- );
-)
-// ...
-early_return!(input_1, [special_a|special_c|special_d]);
-// ...
-early_return!(input_2, [special_b]);
-# return 0;
-# }
-~~~~
-
-### Transcription
-
-As the above example demonstrates, `$(...)*` is also valid on the right-hand
-side of a macro definition. The behavior of `*` in transcription,
-especially in cases where multiple `*`s are nested, and multiple different
-names are involved, can seem somewhat magical and intuitive at first. The
-system that interprets them is called "Macro By Example". The two rules to
-keep in mind are (1) the behavior of `$(...)*` is to walk through one "layer"
-of repetitions for all of the `$name`s it contains in lockstep, and (2) each
-`$name` must be under at least as many `$(...)*`s as it was matched against.
-If it is under more, it'll be repeated, as appropriate.
-
-## Parsing limitations
-
-
-For technical reasons, there are two limitations to the treatment of syntax
-fragments by the macro parser:
-
-1. The parser will always parse as much as possible of a Rust syntactic
-fragment. For example, if the comma were omitted from the syntax of
-`early_return!` above, `input_1 [` would've been interpreted as the beginning
-of an array index. In fact, invoking the macro would have been impossible.
-2. The parser must have eliminated all ambiguity by the time it reaches a
-`$name:fragment_specifier` declaration. This limitation can result in parse
-errors when declarations occur at the beginning of, or immediately after,
-a `$(...)*`. For example, the grammar `$($t:ty)* $e:expr` will always fail to
-parse because the parser would be forced to choose between parsing `t` and
-parsing `e`. Changing the invocation syntax to require a distinctive token in
-front can solve the problem. In the above example, `$(T $t:ty)* E $e:exp`
-solves the problem.
-
-# Macro argument pattern matching
-
-## Motivation
-
-Now consider code like the following:
-
-~~~~
-# enum t1 { good_1(t2, uint), bad_1 };
-# struct t2 { body: t3 }
-# enum t3 { good_2(uint), bad_2};
-# fn f(x: t1) -> uint {
-match x {
- good_1(g1, val) => {
- match g1.body {
- good_2(result) => {
- // complicated stuff goes here
- return result + val;
- },
- _ => fail!("Didn't get good_2")
- }
- }
- _ => return 0 // default value
-}
-# }
-~~~~
-
-All the complicated stuff is deeply indented, and the error-handling code is
-separated from matches that fail. We'd like to write a macro that performs
-a match, but with a syntax that suits the problem better. The following macro
-can solve the problem:
-
-~~~~
-macro_rules! biased_match (
- // special case: `let (x) = ...` is illegal, so use `let x = ...` instead
- ( ($e:expr) ~ ($p:pat) else $err:stmt ;
- binds $bind_res:ident
- ) => (
- let $bind_res = match $e {
- $p => ( $bind_res ),
- _ => { $err }
- };
- );
- // more than one name; use a tuple
- ( ($e:expr) ~ ($p:pat) else $err:stmt ;
- binds $( $bind_res:ident ),*
- ) => (
- let ( $( $bind_res ),* ) = match $e {
- $p => ( $( $bind_res ),* ),
- _ => { $err }
- };
- )
-)
-
-# enum t1 { good_1(t2, uint), bad_1 };
-# struct t2 { body: t3 }
-# enum t3 { good_2(uint), bad_2};
-# fn f(x: t1) -> uint {
-biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
- binds g1, val )
-biased_match!((g1.body) ~ (good_2(result) )
- else { fail!("Didn't get good_2") };
- binds result )
-// complicated stuff goes here
-return result + val;
-# }
-~~~~
-
-This solves the indentation problem. But if we have a lot of chained matches
-like this, we might prefer to write a single macro invocation. The input
-pattern we want is clear:
-~~~~
-# macro_rules! b(
- ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
- binds $( $bind_res:ident ),*
- )
-# => (0))
-~~~~
-
-However, it's not possible to directly expand to nested match statements. But
-there is a solution.
-
-## The recursive approach to macro writing
-
-A macro may accept multiple different input grammars. The first one to
-successfully match the actual argument to a macro invocation is the one that
-"wins".
-
-In the case of the example above, we want to write a recursive macro to
-process the semicolon-terminated lines, one-by-one. So, we want the following
-input patterns:
-
-~~~~
-# macro_rules! b(
- ( binds $( $bind_res:ident ),* )
-# => (0))
-~~~~
-...and:
-
-~~~~
-# macro_rules! b(
- ( ($e :expr) ~ ($p :pat) else $err :stmt ;
- $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
- binds $( $bind_res:ident ),*
- )
-# => (0))
-~~~~
-
-The resulting macro looks like this. Note that the separation into
-`biased_match!` and `biased_match_rec!` occurs only because we have an outer
-piece of syntax (the `let`) which we only want to transcribe once.
-
-~~~~
-
-macro_rules! biased_match_rec (
- // Handle the first layer
- ( ($e :expr) ~ ($p :pat) else $err :stmt ;
- $( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
- binds $( $bind_res:ident ),*
- ) => (
- match $e {
- $p => {
- // Recursively handle the next layer
- biased_match_rec!($( ($e_rest) ~ ($p_rest) else $err_rest ; )*
- binds $( $bind_res ),*
- )
- }
- _ => { $err }
- }
- );
- ( binds $( $bind_res:ident ),* ) => ( ($( $bind_res ),*) )
-)
-
-// Wrap the whole thing in a `let`.
-macro_rules! biased_match (
- // special case: `let (x) = ...` is illegal, so use `let x = ...` instead
- ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
- binds $bind_res:ident
- ) => (
- let ( $( $bind_res ),* ) = biased_match_rec!(
- $( ($e) ~ ($p) else $err ; )*
- binds $bind_res
- );
- );
- // more than one name: use a tuple
- ( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
- binds $( $bind_res:ident ),*
- ) => (
- let ( $( $bind_res ),* ) = biased_match_rec!(
- $( ($e) ~ ($p) else $err ; )*
- binds $( $bind_res ),*
- );
- )
-)
-
-
-# enum t1 { good_1(t2, uint), bad_1 };
-# struct t2 { body: t3 }
-# enum t3 { good_2(uint), bad_2};
-# fn f(x: t1) -> uint {
-biased_match!(
- (x) ~ (good_1(g1, val)) else { return 0 };
- (g1.body) ~ (good_2(result) ) else { fail!("Didn't get good_2") };
- binds val, result )
-// complicated stuff goes here
-return result + val;
-# }
-~~~~
-
-This technique applies to many cases where transcribing a result all at once is not possible.
-The resulting code resembles ordinary functional programming in some respects,
-but has some important differences from functional programming.
-
-The first difference is important, but also easy to forget: the transcription
-(right-hand) side of a `macro_rules!` rule is literal syntax, which can only
-be executed at run-time. If a piece of transcription syntax does not itself
-appear inside another macro invocation, it will become part of the final
-program. If it is inside a macro invocation (for example, the recursive
-invocation of `biased_match_rec!`), it does have the opportunity to affect
-transcription, but only through the process of attempted pattern matching.
-
-The second, related, difference is that the evaluation order of macros feels
-"backwards" compared to ordinary programming. Given an invocation
-`m1!(m2!())`, the expander first expands `m1!`, giving it as input the literal
-syntax `m2!()`. If it transcribes its argument unchanged into an appropriate
-position (in particular, not as an argument to yet another macro invocation),
-the expander will then proceed to evaluate `m2!()` (along with any other macro
-invocations `m1!(m2!())` produced).
-
-# A final note
-
-Macros, as currently implemented, are not for the faint of heart. Even
-ordinary syntax errors can be more difficult to debug when they occur inside a
-macro, and errors caused by parse problems in generated code can be very
-tricky. Invoking the `log_syntax!` macro can help elucidate intermediate
-states, invoking `trace_macros!(true)` will automatically print those
-intermediate states out, and passing the flag `--pretty expanded` as a
-command-line argument to the compiler will show the result of expansion.
+++ /dev/null
-% Rust Packaging Tutorial
-
-# Introduction
-
-Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
-package up your Rust code and share it with other people. This tutorial will
-get you started on all of the concepts and commands you need to give the gift
-of Rust code to someone else.
-
-# Installing External Packages
-
-First, let's try to use an external package somehow. I've made a sample package
-called `hello` to demonstrate how to do so. Here's how `hello` is used:
-
-~~~~
-extern mod hello;
-
-fn main() {
- hello::world();
-}
-~~~~
-
-Easy! But if you try to compile this, you'll get an error:
-
-~~~~ {.notrust}
-$ rustc main.rs
-main.rs:1:0: 1:17 error: can't find crate for `hello`
-main.rs:1 extern mod hello;
- ^~~~~~~~~~~~~~~~~
-~~~~
-
-This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
-`rustpkg` has an easy way to fetch others' code: the `install` command. It's
-used like this:
-
-~~~ {.notrust}
-$ rustpkg install PKG_ID
-~~~
-
-This will install a package named `PKG_ID` into your current Rust environment.
-I called it `PKG_ID` in this example because `rustpkg` calls this a 'package
-identifier.' When using it with an external package like this, it's often a
-URI fragment. You see, Rust has no central authority for packages. You can
-build your own `hello` library if you want, and that's fine. We'd both host
-them in different places and different projects would rely on whichever version
-they preferred.
-
-To install the `hello` library, simply run this in your terminal:
-
-~~~ {.notrust}
-$ rustpkg install github.com/steveklabnik/hello
-~~~
-
-You should see a message that looks like this:
-
-~~~ {.notrust}
-note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
-~~~
-
-Now, compiling our example should work:
-
-~~~ {.notrust}
-$ rustc main.rs
-$ ./main
-Hello, world.
-~~~
-
-Simple! That's all it takes.
-
-# Workspaces
-
-Before we can talk about how to make packages of your own, you have to
-understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
-a directory that has certain sub-directories that `rustpkg` expects. Different
-Rust projects will go into different workspaces.
-
-A workspace consists of any directory that has the following
-directories:
-
-* `src`: The directory where all the source code goes.
-* `build`: This directory contains all of the build output.
-* `lib`: The directory where any libraries distributed with the package go.
-* `bin`: This directory holds any binaries distributed with the package.
-
-There are also default file names you'll want to follow as well:
-
-* `main.rs`: A file that's going to become an executable.
-* `lib.rs`: A file that's going to become a library.
-
-# Building your own Package
-
-Now that you've got workspaces down, let's build your own copy of `hello`. Go
-to wherever you keep your personal projects, and let's make all of the
-directories we'll need. I'll refer to this personal project directory as
-`~/src` for the rest of this tutorial.
-
-## Creating our workspace
-
-~~~ {.notrust}
-$ cd ~/src
-$ mkdir -p hello/src/hello
-$ cd hello
-~~~
-
-Easy enough! Let's do one or two more things that are nice to do:
-
-~~~ {.notrust}
-$ git init .
-$ cat > README.md
-# hello
-
-A simple package for Rust.
-
-## Installation
-
-```
-$ rustpkg install github.com/YOUR_USERNAME/hello
-```
-^D
-$ cat > .gitignore
-.rust
-build
-^D
-$ git commit -am "Initial commit."
-~~~
-
-If you're not familliar with the `cat >` idiom, it will make files with the
-text you type inside. Control-D (`^D`) ends the text for the file.
-
-Anyway, we've got a README and a `.gitignore`. Let's talk about that
-`.gitignore` for a minute: we are ignoring two directories, `build` and
-`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
-want to check those into a repository. `.rust` is a directory that `rustpkg`
-uses to keep track of its own settings, as well as the source code of any other
-external packages that this workspace uses. This is where that `rustpkg
-install` puts all of its files. Those are also not to go into our repository,
-so we ignore it all as well.
-
-Next, let's add a source file:
-
-~~~
-#[desc = "A hello world Rust package."];
-#[license = "MIT"];
-
-pub fn world() {
- println("Hello, world.");
-}
-~~~
-
-Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
-
-## Crate attributes for packages
-
-`license` is equally simple: the license we want this code to have. I chose MIT
-here, but you should pick whatever license makes the most sense for you.
-
-`desc` is a description of the package and what it does. This should just be a
-sentence or two.
-
-## Building your package
-
-Building your package is simple:
-
-~~~ {.notrust}
-$ rustpkg build hello
-~~~
-
-This will compile `src/hello/lib.rs` into a library. After this process
-completes, you'll want to check out `build`:
-
-~~~ {.notrust}
-$ ls build/x86_64-unknown-linux-gnu/hello/
-libhello-ed8619dad9ce7d58-0.1.0.so
-~~~
-
-This directory naming structure is called a 'build triple,' and is because I'm
-on 64 bit Linux. Yours may differ based on platform.
-
-You'll also notice that `src/hello/lib.rs` turned into
-`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
-library name, a hash of its content, and the version.
-
-Now that your library builds, you'll want to commit:
-
-~~~ {.notrust}
-$ git add src
-$ git commit -m "Adding source code."
-~~~
-
-If you're using GitHub, after creating the project, do this:
-
-~~~ {.notrust}
-$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
-$ git push origin -u master
-~~~
-
-Now you can install and use it! Go anywhere else in your filesystem:
-
-~~~ {.notrust}
-$ cd ~/src/foo
-$ rustpkg install github.com/YOUR_USERNAME/hello
-WARNING: The Rust package manager is experimental and may be unstable
-note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
-~~~
-
-That's it!
-
-# Testing your Package
-
-Testing your package is simple as well. First, let's change `src/hello/lib.rs` to contain
-a function that can be sensibly tested:
-
-~~~
-#[desc = "A Rust package for determining whether unsigned integers are even."];
-#[license = "MIT"];
-
-pub fn is_even(i: uint) -> bool {
- i % 2 == 0
-}
-~~~
-
-Once you've edited `lib.rs`, you can create a second crate file, `src/hello/test.rs`,
-to put tests in:
-
-~~~
-#[license = "MIT"];
-extern mod hello;
-use hello::is_even;
-
-#[test]
-fn test_is_even() {
- assert!(is_even(0));
- assert!(!is_even(1));
- assert!(is_even(2));
-}
-~~~
-
-Note that you have to import the crate you just created in `lib.rs` with the
-`extern mod hello` directive. That's because you're putting the tests in a different
-crate from the main library that you created.
-
-Now, you can use the `rustpkg test` command to build this test crate (and anything else
-it depends on) and run the tests, all in one step:
-
-~~~ {.notrust}
-$ rustpkg test hello
-WARNING: The Rust package manager is experimental and may be unstable
-note: Installed package hello-0.1 to /Users/tjc/.rust
-
-running 1 test
-test test_is_even ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
-~~~
-
-# More resources
-
-There's a lot more going on with `rustpkg`, this is just to get you started.
-Check out [the rustpkg manual](rustpkg.html) for the full details on how to
-customize `rustpkg`.
-
-A tag was created on GitHub specifically for `rustpkg`-related issues. You can
-[see all the Issues for rustpkg
-here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
-with bugs as well as new feature plans. `rustpkg` is still under development,
-and so may be a bit flaky at the moment.
-
-You may also want to check out [this blog
-post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
-design decisions and justifications.
+++ /dev/null
-% Rust Tasks and Communication Tutorial
-
-# Introduction
-
-Rust provides safe concurrency through a combination
-of lightweight, memory-isolated tasks and message passing.
-This tutorial will describe the concurrency model in Rust, how it
-relates to the Rust type system, and introduce
-the fundamental library abstractions for constructing concurrent programs.
-
-Rust tasks are not the same as traditional threads: rather,
-they are considered _green threads_, lightweight units of execution that the Rust
-runtime schedules cooperatively onto a small number of operating system threads.
-On a multi-core system Rust tasks will be scheduled in parallel by default.
-Because tasks are significantly
-cheaper to create than traditional threads, Rust can create hundreds of
-thousands of concurrent tasks on a typical 32-bit system.
-In general, all Rust code executes inside a task, including the `main` function.
-
-In order to make efficient use of memory Rust tasks have dynamically sized stacks.
-A task begins its life with a small
-amount of stack space (currently in the low thousands of bytes, depending on
-platform), and acquires more stack as needed.
-Unlike in languages such as C, a Rust task cannot accidentally write to
-memory beyond the end of the stack, causing crashes or worse.
-
-Tasks provide failure isolation and recovery. When a fatal error occurs in Rust
-code as a result of an explicit call to `fail!()`, an assertion failure, or
-another invalid operation, the runtime system destroys the entire
-task. Unlike in languages such as Java and C++, there is no way to `catch` an
-exception. Instead, tasks may monitor each other for failure.
-
-Tasks use Rust's type system to provide strong memory safety guarantees. In
-particular, the type system guarantees that tasks cannot share mutable state
-with each other. Tasks communicate with each other by transferring _owned_
-data through the global _exchange heap_.
-
-## A note about the libraries
-
-While Rust's type system provides the building blocks needed for safe
-and efficient tasks, all of the task functionality itself is implemented
-in the standard and extra libraries, which are still under development
-and do not always present a consistent or complete interface.
-
-For your reference, these are the standard modules involved in Rust
-concurrency at this writing:
-
-* [`std::task`] - All code relating to tasks and task scheduling,
-* [`std::comm`] - The message passing interface,
-* [`extra::comm`] - Additional messaging types based on `std::comm`,
-* [`extra::sync`] - More exotic synchronization tools, including locks,
-* [`extra::arc`] - The Arc (atomically reference counted) type,
- for safely sharing immutable data,
-* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time.
-
-[`std::task`]: std/task/index.html
-[`std::comm`]: std/comm/index.html
-[`extra::comm`]: extra/comm/index.html
-[`extra::sync`]: extra/sync/index.html
-[`extra::arc`]: extra/arc/index.html
-[`extra::future`]: extra/future/index.html
-
-# Basics
-
-The programming interface for creating and managing tasks lives
-in the `task` module of the `std` library, and is thus available to all
-Rust code by default. At its simplest, creating a task is a matter of
-calling the `spawn` function with a closure argument. `spawn` executes the
-closure in the new task.
-
-~~~~
-# use std::task::spawn;
-
-// Print something profound in a different task using a named function
-fn print_message() { println("I am running in a different task!"); }
-spawn(print_message);
-
-// Print something more profound in a different task using a lambda expression
-spawn(proc() println("I am also running in a different task!") );
-
-// The canonical way to spawn is using `do` notation
-do spawn {
- println("I too am running in a different task!");
-}
-~~~~
-
-In Rust, there is nothing special about creating tasks: a task is not a
-concept that appears in the language semantics. Instead, Rust's type system
-provides all the tools necessary to implement safe concurrency: particularly,
-_owned types_. The language leaves the implementation details to the standard
-library.
-
-The `spawn` function has a very simple type signature: `fn spawn(f:
-proc())`. Because it accepts only owned closures, and owned closures
-contain only owned data, `spawn` can safely move the entire closure
-and all its associated state into an entirely different task for
-execution. Like any closure, the function passed to `spawn` may capture
-an environment that it carries across tasks.
-
-~~~
-# use std::task::spawn;
-# fn generate_task_number() -> int { 0 }
-// Generate some state locally
-let child_task_number = generate_task_number();
-
-do spawn {
- // Capture it in the remote task
- println!("I am child number {}", child_task_number);
-}
-~~~
-
-## Communication
-
-Now that we have spawned a new task, it would be nice if we could
-communicate with it. Recall that Rust does not have shared mutable
-state, so one task may not manipulate variables owned by another task.
-Instead we use *pipes*.
-
-A pipe is simply a pair of endpoints: one for sending messages and another for
-receiving messages. Pipes are low-level communication building-blocks and so
-come in a variety of forms, each one appropriate for a different use case. In
-what follows, we cover the most commonly used varieties.
-
-The simplest way to create a pipe is to use `Chan::new`
-function to create a `(Port, Chan)` pair. In Rust parlance, a *channel*
-is a sending endpoint of a pipe, and a *port* is the receiving
-endpoint. Consider the following example of calculating two results
-concurrently:
-
-~~~~
-# use std::task::spawn;
-
-let (port, chan): (Port<int>, Chan<int>) = Chan::new();
-
-do spawn || {
- let result = some_expensive_computation();
- chan.send(result);
-}
-
-some_other_expensive_computation();
-let result = port.recv();
-# fn some_expensive_computation() -> int { 42 }
-# fn some_other_expensive_computation() {}
-~~~~
-
-Let's examine this example in detail. First, the `let` statement creates a
-stream for sending and receiving integers (the left-hand side of the `let`,
-`(chan, port)`, is an example of a *destructuring let*: the pattern separates
-a tuple into its component parts).
-
-~~~~
-let (port, chan): (Port<int>, Chan<int>) = Chan::new();
-~~~~
-
-The child task will use the channel to send data to the parent task,
-which will wait to receive the data on the port. The next statement
-spawns the child task.
-
-~~~~
-# use std::task::spawn;
-# fn some_expensive_computation() -> int { 42 }
-# let (port, chan) = Chan::new();
-do spawn || {
- let result = some_expensive_computation();
- chan.send(result);
-}
-~~~~
-
-Notice that the creation of the task closure transfers `chan` to the child
-task implicitly: the closure captures `chan` in its environment. Both `Chan`
-and `Port` are sendable types and may be captured into tasks or otherwise
-transferred between them. In the example, the child task runs an expensive
-computation, then sends the result over the captured channel.
-
-Finally, the parent continues with some other expensive
-computation, then waits for the child's result to arrive on the
-port:
-
-~~~~
-# fn some_other_expensive_computation() {}
-# let (port, chan) = Chan::<int>::new();
-# chan.send(0);
-some_other_expensive_computation();
-let result = port.recv();
-~~~~
-
-The `Port` and `Chan` pair created by `Chan::new` enables efficient
-communication between a single sender and a single receiver, but multiple
-senders cannot use a single `Chan`, and multiple receivers cannot use a single
-`Port`. What if our example needed to compute multiple results across a number
-of tasks? The following program is ill-typed:
-
-~~~ {.xfail-test}
-# use std::task::{spawn};
-# fn some_expensive_computation() -> int { 42 }
-let (port, chan) = Chan::new();
-
-do spawn {
- chan.send(some_expensive_computation());
-}
-
-// ERROR! The previous spawn statement already owns the channel,
-// so the compiler will not allow it to be captured again
-do spawn {
- chan.send(some_expensive_computation());
-}
-~~~
-
-Instead we can use a `SharedChan`, a type that allows a single
-`Chan` to be shared by multiple senders.
-
-~~~
-# use std::task::spawn;
-
-let (port, chan) = SharedChan::new();
-
-for init_val in range(0u, 3) {
- // Create a new channel handle to distribute to the child task
- let child_chan = chan.clone();
- do spawn {
- child_chan.send(some_expensive_computation(init_val));
- }
-}
-
-let result = port.recv() + port.recv() + port.recv();
-# fn some_expensive_computation(_i: uint) -> int { 42 }
-~~~
-
-Here we transfer ownership of the channel into a new `SharedChan` value. Like
-`Chan`, `SharedChan` is a non-copyable, owned type (sometimes also referred to
-as an *affine* or *linear* type). Unlike with `Chan`, though, the programmer
-may duplicate a `SharedChan`, with the `clone()` method. A cloned
-`SharedChan` produces a new handle to the same channel, allowing multiple
-tasks to send data to a single port. Between `spawn`, `Chan` and
-`SharedChan`, we have enough tools to implement many useful concurrency
-patterns.
-
-Note that the above `SharedChan` example is somewhat contrived since
-you could also simply use three `Chan` pairs, but it serves to
-illustrate the point. For reference, written with multiple streams, it
-might look like the example below.
-
-~~~
-# use std::task::spawn;
-# use std::vec;
-
-// Create a vector of ports, one for each child task
-let ports = vec::from_fn(3, |init_val| {
- let (port, chan) = Chan::new();
- do spawn {
- chan.send(some_expensive_computation(init_val));
- }
- port
-});
-
-// Wait on each port, accumulating the results
-let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
-# fn some_expensive_computation(_i: uint) -> int { 42 }
-~~~
-
-## Backgrounding computations: Futures
-With `extra::future`, rust has a mechanism for requesting a computation and getting the result
-later.
-
-The basic example below illustrates this.
-~~~
-# fn make_a_sandwich() {};
-fn fib(n: u64) -> u64 {
- // lengthy computation returning an uint
- 12586269025
-}
-
-let mut delayed_fib = extra::future::Future::spawn(proc() fib(50));
-make_a_sandwich();
-println!("fib(50) = {:?}", delayed_fib.get())
-~~~
-
-The call to `future::spawn` returns immediately a `future` object regardless of how long it
-takes to run `fib(50)`. You can then make yourself a sandwich while the computation of `fib` is
-running. The result of the execution of the method is obtained by calling `get` on the future.
-This call will block until the value is available (*i.e.* the computation is complete). Note that
-the future needs to be mutable so that it can save the result for next time `get` is called.
-
-Here is another example showing how futures allow you to background computations. The workload will
-be distributed on the available cores.
-~~~
-# use std::vec;
-fn partial_sum(start: uint) -> f64 {
- let mut local_sum = 0f64;
- for num in range(start*100000, (start+1)*100000) {
- local_sum += (num as f64 + 1.0).pow(&-2.0);
- }
- local_sum
-}
-
-fn main() {
- let mut futures = vec::from_fn(1000, |ind| do extra::future::Future::spawn { partial_sum(ind) });
-
- let mut final_res = 0f64;
- for ft in futures.mut_iter() {
- final_res += ft.get();
- }
- println!("π^2/6 is not far from : {}", final_res);
-}
-~~~
-
-## Sharing immutable data without copy: Arc
-
-To share immutable data between tasks, a first approach would be to only use pipes as we have seen
-previously. A copy of the data to share would then be made for each task. In some cases, this would
-add up to a significant amount of wasted memory and would require copying the same data more than
-necessary.
-
-To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in
-the `extra` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
-acts as a reference to the shared data and only this reference is shared and cloned.
-
-Here is a small example showing how to use Arcs. We wish to run concurrently several computations on
-a single large vector of floats. Each task needs the full vector to perform its duty.
-~~~
-# use std::vec;
-# use std::rand;
-use extra::arc::Arc;
-
-fn pnorm(nums: &~[f64], p: uint) -> f64 {
- nums.iter().fold(0.0, |a,b| a+(*b).pow(&(p as f64)) ).pow(&(1.0 / (p as f64)))
-}
-
-fn main() {
- let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
- println!("Inf-norm = {}", *numbers.iter().max().unwrap());
-
- let numbers_arc = Arc::new(numbers);
-
- for num in range(1u, 10) {
- let (port, chan) = Chan::new();
- chan.send(numbers_arc.clone());
-
- do spawn {
- let local_arc : Arc<~[f64]> = port.recv();
- let task_numbers = local_arc.get();
- println!("{}-norm = {}", num, pnorm(task_numbers, num));
- }
- }
-}
-~~~
-
-The function `pnorm` performs a simple computation on the vector (it computes the sum of its items
-at the power given as argument and takes the inverse power of this value). The Arc on the vector is
-created by the line
-~~~
-# use extra::arc::Arc;
-# use std::vec;
-# use std::rand;
-# let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
-let numbers_arc=Arc::new(numbers);
-~~~
-and a clone of it is sent to each task
-~~~
-# use extra::arc::Arc;
-# use std::vec;
-# use std::rand;
-# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
-# let numbers_arc = Arc::new(numbers);
-# let (port, chan) = Chan::new();
-chan.send(numbers_arc.clone());
-~~~
-copying only the wrapper and not its contents.
-
-Each task recovers the underlying data by
-~~~
-# use extra::arc::Arc;
-# use std::vec;
-# use std::rand;
-# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
-# let numbers_arc=Arc::new(numbers);
-# let (port, chan) = Chan::new();
-# chan.send(numbers_arc.clone());
-# let local_arc : Arc<~[f64]> = port.recv();
-let task_numbers = local_arc.get();
-~~~
-and can use it as if it were local.
-
-The `arc` module also implements Arcs around mutable data that are not covered here.
-
-# Handling task failure
-
-Rust has a built-in mechanism for raising exceptions. The `fail!()` macro
-(which can also be written with an error string as an argument: `fail!(
-~reason)`) and the `assert!` construct (which effectively calls `fail!()`
-if a boolean expression is false) are both ways to raise exceptions. When a
-task raises an exception the task unwinds its stack---running destructors and
-freeing memory along the way---and then exits. Unlike exceptions in C++,
-exceptions in Rust are unrecoverable within a single task: once a task fails,
-there is no way to "catch" the exception.
-
-While it isn't possible for a task to recover from failure, tasks may notify
-each other of failure. The simplest way of handling task failure is with the
-`try` function, which is similar to `spawn`, but immediately blocks waiting
-for the child task to finish. `try` returns a value of type `Result<T,
-()>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this
-case, because the type arguments to `Result` are `int` and `()`, callers can
-pattern-match on a result to check whether it's an `Ok` result with an `int`
-field (representing a successful result) or an `Err` result (representing
-termination with an error).
-
-~~~{.xfail-test .linked-failure}
-# use std::task;
-# fn some_condition() -> bool { false }
-# fn calculate_result() -> int { 0 }
-let result: Result<int, ()> = do task::try {
- if some_condition() {
- calculate_result()
- } else {
- fail!("oops!");
- }
-};
-assert!(result.is_err());
-~~~
-
-Unlike `spawn`, the function spawned using `try` may return a value,
-which `try` will dutifully propagate back to the caller in a [`Result`]
-enum. If the child task terminates successfully, `try` will
-return an `Ok` result; if the child task fails, `try` will return
-an `Error` result.
-
-[`Result`]: std/result/index.html
-
-> ***Note:*** A failed task does not currently produce a useful error
-> value (`try` always returns `Err(())`). In the
-> future, it may be possible for tasks to intercept the value passed to
-> `fail!()`.
-
-TODO: Need discussion of `future_result` in order to make failure
-modes useful.
-
-But not all failures are created equal. In some cases you might need to
-abort the entire program (perhaps you're writing an assert which, if
-it trips, indicates an unrecoverable logic error); in other cases you
-might want to contain the failure at a certain boundary (perhaps a
-small piece of input from the outside world, which you happen to be
-processing in parallel, is malformed and its processing task can't
-proceed).
-
-## Creating a task with a bi-directional communication path
-
-A very common thing to do is to spawn a child task where the parent
-and child both need to exchange messages with each other. The
-function `extra::comm::DuplexStream()` supports this pattern. We'll
-look briefly at how to use it.
-
-To see how `DuplexStream()` works, we will create a child task
-that repeatedly receives a `uint` message, converts it to a string, and sends
-the string in response. The child terminates when it receives `0`.
-Here is the function that implements the child task:
-
-~~~{.xfail-test .linked-failure}
-# use extra::comm::DuplexStream;
-# use std::uint;
-fn stringifier(channel: &DuplexStream<~str, uint>) {
- let mut value: uint;
- loop {
- value = channel.recv();
- channel.send(uint::to_str(value));
- if value == 0 { break; }
- }
-}
-~~~~
-
-The implementation of `DuplexStream` supports both sending and
-receiving. The `stringifier` function takes a `DuplexStream` that can
-send strings (the first type parameter) and receive `uint` messages
-(the second type parameter). The body itself simply loops, reading
-from the channel and then sending its response back. The actual
-response itself is simply the stringified version of the received value,
-`uint::to_str(value)`.
-
-Here is the code for the parent task:
-
-~~~{.xfail-test .linked-failure}
-# use std::task::spawn;
-# use std::uint;
-# use extra::comm::DuplexStream;
-# fn stringifier(channel: &DuplexStream<~str, uint>) {
-# let mut value: uint;
-# loop {
-# value = channel.recv();
-# channel.send(uint::to_str(value));
-# if value == 0u { break; }
-# }
-# }
-# fn main() {
-
-let (from_child, to_child) = DuplexStream::new();
-
-do spawn {
- stringifier(&to_child);
-};
-
-from_child.send(22);
-assert!(from_child.recv() == ~"22");
-
-from_child.send(23);
-from_child.send(0);
-
-assert!(from_child.recv() == ~"23");
-assert!(from_child.recv() == ~"0");
-
-# }
-~~~~
-
-The parent task first calls `DuplexStream` to create a pair of bidirectional
-endpoints. It then uses `task::spawn` to create the child task, which captures
-one end of the communication channel. As a result, both parent and child can
-send and receive data to and from the other.
+++ /dev/null
-% Rust Testing Tutorial
-
-# Quick start
-
-To create test functions, add a `#[test]` attribute like this:
-
-```rust
-fn return_two() -> int {
- 2
-}
-
-#[test]
-fn return_two_test() {
- let x = return_two();
- assert!(x == 2);
-}
-```
-
-To run these tests, use `rustc --test`:
-
-```
-$ rustc --test foo.rs; ./foo
-running 1 test
-test return_two_test ... ok
-
-test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
-```
-
-`rustc foo.rs` will *not* compile the tests, since `#[test]` implies
-`#[cfg(test)]`. The `--test` flag to `rustc` implies `--cfg test`.
-
-
-# Unit testing in Rust
-
-Rust has built in support for simple unit testing. Functions can be
-marked as unit tests using the 'test' attribute.
-
-```rust
-#[test]
-fn return_none_if_empty() {
- // ... test code ...
-}
-```
-
-A test function's signature must have no arguments and no return
-value. To run the tests in a crate, it must be compiled with the
-'--test' flag: `rustc myprogram.rs --test -o myprogram-tests`. Running
-the resulting executable will run all the tests in the crate. A test
-is considered successful if its function returns; if the task running
-the test fails, through a call to `fail!`, a failed `check` or
-`assert`, or some other (`assert_eq`, `assert_approx_eq`, ...) means,
-then the test fails.
-
-When compiling a crate with the '--test' flag '--cfg test' is also
-implied, so that tests can be conditionally compiled.
-
-```rust
-#[cfg(test)]
-mod tests {
- #[test]
- fn return_none_if_empty() {
- // ... test code ...
- }
-}
-```
-
-Additionally #[test] items behave as if they also have the
-#[cfg(test)] attribute, and will not be compiled when the --test flag
-is not used.
-
-Tests that should not be run can be annotated with the 'ignore'
-attribute. The existence of these tests will be noted in the test
-runner output, but the test will not be run. Tests can also be ignored
-by configuration so, for example, to ignore a test on windows you can
-write `#[ignore(cfg(target_os = "win32"))]`.
-
-Tests that are intended to fail can be annotated with the
-'should_fail' attribute. The test will be run, and if it causes its
-task to fail then the test will be counted as successful; otherwise it
-will be counted as a failure. For example:
-
-```rust
-#[test]
-#[should_fail]
-fn test_out_of_bounds_failure() {
- let v: [int] = [];
- v[0];
-}
-```
-
-A test runner built with the '--test' flag supports a limited set of
-arguments to control which tests are run: the first free argument
-passed to a test runner specifies a filter used to narrow down the set
-of tests being run; the '--ignored' flag tells the test runner to run
-only tests with the 'ignore' attribute.
-
-## Parallelism
-
-By default, tests are run in parallel, which can make interpreting
-failure output difficult. In these cases you can set the
-`RUST_TEST_TASKS` environment variable to 1 to make the tests run
-sequentially.
-
-## Benchmarking
-
-The test runner also understands a simple form of benchmark execution.
-Benchmark functions are marked with the `#[bench]` attribute, rather
-than `#[test]`, and have a different form and meaning. They are
-compiled along with `#[test]` functions when a crate is compiled with
-`--test`, but they are not run by default. To run the benchmark
-component of your testsuite, pass `--bench` to the compiled test
-runner.
-
-The type signature of a benchmark function differs from a unit test:
-it takes a mutable reference to type `test::BenchHarness`. Inside the
-benchmark function, any time-variable or "setup" code should execute
-first, followed by a call to `iter` on the benchmark harness, passing
-a closure that contains the portion of the benchmark you wish to
-actually measure the per-iteration speed of.
-
-For benchmarks relating to processing/generating data, one can set the
-`bytes` field to the number of bytes consumed/produced in each
-iteration; this will used to show the throughput of the benchmark.
-This must be the amount used in each iteration, *not* the total
-amount.
-
-For example:
-
-```rust
-extern mod extra;
-use std::vec;
-
-#[bench]
-fn bench_sum_1024_ints(b: &mut extra::test::BenchHarness) {
- let v = vec::from_fn(1024, |n| n);
- b.iter(|| {v.iter().fold(0, |old, new| old + *new);} );
-}
-
-#[bench]
-fn initialise_a_vector(b: &mut extra::test::BenchHarness) {
- b.iter(|| {vec::from_elem(1024, 0u64);} );
- b.bytes = 1024 * 8;
-}
-```
-
-The benchmark runner will calibrate measurement of the benchmark
-function to run the `iter` block "enough" times to get a reliable
-measure of the per-iteration speed.
-
-Advice on writing benchmarks:
-
- - Move setup code outside the `iter` loop; only put the part you
- want to measure inside
- - Make the code do "the same thing" on each iteration; do not
- accumulate or change state
- - Make the outer function idempotent too; the benchmark runner is
- likely to run it many times
- - Make the inner `iter` loop short and fast so benchmark runs are
- fast and the calibrator can adjust the run-length at fine
- resolution
- - Make the code in the `iter` loop do something simple, to assist in
- pinpointing performance improvements (or regressions)
-
-To run benchmarks, pass the `--bench` flag to the compiled
-test-runner. Benchmarks are compiled-in but not executed by default.
-
-## Examples
-
-### Typical test run
-
-```
-> mytests
-
-running 30 tests
-running driver::tests::mytest1 ... ok
-running driver::tests::mytest2 ... ignored
-... snip ...
-running driver::tests::mytest30 ... ok
-
-result: ok. 28 passed; 0 failed; 2 ignored
-```
-
-### Test run with failures
-
-```
-> mytests
-
-running 30 tests
-running driver::tests::mytest1 ... ok
-running driver::tests::mytest2 ... ignored
-... snip ...
-running driver::tests::mytest30 ... FAILED
-
-result: FAILED. 27 passed; 1 failed; 2 ignored
-```
-
-### Running ignored tests
-
-```
-> mytests --ignored
-
-running 2 tests
-running driver::tests::mytest2 ... failed
-running driver::tests::mytest10 ... ok
-
-result: FAILED. 1 passed; 1 failed; 0 ignored
-```
-
-### Running a subset of tests
-
-```
-> mytests mytest1
-
-running 11 tests
-running driver::tests::mytest1 ... ok
-running driver::tests::mytest10 ... ignored
-... snip ...
-running driver::tests::mytest19 ... ok
-
-result: ok. 11 passed; 0 failed; 1 ignored
-```
-
-### Running benchmarks
-
-```
-> mytests --bench
-
-running 2 tests
-test bench_sum_1024_ints ... bench: 709 ns/iter (+/- 82)
-test initialise_a_vector ... bench: 424 ns/iter (+/- 99) = 19320 MB/s
-
-test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured
-```
-
-## Saving and ratcheting metrics
-
-When running benchmarks or other tests, the test runner can record
-per-test "metrics". Each metric is a scalar `f64` value, plus a noise
-value which represents uncertainty in the measurement. By default, all
-`#[bench]` benchmarks are recorded as metrics, which can be saved as
-JSON in an external file for further reporting.
-
-In addition, the test runner supports _ratcheting_ against a metrics
-file. Ratcheting is like saving metrics, except that after each run,
-if the output file already exists the results of the current run are
-compared against the contents of the existing file, and any regression
-_causes the testsuite to fail_. If the comparison passes -- if all
-metrics stayed the same (within noise) or improved -- then the metrics
-file is overwritten with the new values. In this way, a metrics file
-in your workspace can be used to ensure your work does not regress
-performance.
-
-Test runners take 3 options that are relevant to metrics:
-
- - `--save-metrics=<file.json>` will save the metrics from a test run
- to `file.json`
- - `--ratchet-metrics=<file.json>` will ratchet the metrics against
- the `file.json`
- - `--ratchet-noise-percent=N` will override the noise measurements
- in `file.json`, and consider a metric change less than `N%` to be
- noise. This can be helpful if you are testing in a noisy
- environment where the benchmark calibration loop cannot acquire a
- clear enough signal.
extern mod rust = "github.com/mozilla/rust"; // pretend Rust is a simple library
~~~
-[rustpkg]: rustpkg.html
-
## Crate metadata and settings
For every crate you can define a number of metadata items, such as link name, version or author.
# What next?
Now that you know the essentials, check out any of the additional
-tutorials on individual topics.
+guides on individual topics.
* [Borrowed pointers][borrow]
* [Tasks and communication][tasks]
There is further documentation on the [wiki], however those tend to be even
more out of date than this document.
-[borrow]: tutorial-borrowed-ptr.html
-[tasks]: tutorial-tasks.html
-[macros]: tutorial-macros.html
-[ffi]: tutorial-ffi.html
-[container]: tutorial-container.html
-[conditions]: tutorial-conditions.html
-[rustpkg]: tutorial-rustpkg.html
-[testing]: tutorial-testing.html
+[borrow]: guide-borrowed-ptr.html
+[tasks]: guide-tasks.html
+[macros]: guide-macros.html
+[ffi]: guide-ffi.html
+[container]: guide-container.html
+[conditions]: guide-conditions.html
+[rustpkg]: guide-rustpkg.html
+[testing]: guide-testing.html
[rustdoc]: rustdoc.html
[wiki]: https://github.com/mozilla/rust/wiki/Docs
DOCS_L10N :=
BASE_DOC_OPTS := --from=markdown --standalone --toc --number-sections
-HTML_OPTS = $(BASE_DOC_OPTS) --to=html5 --section-divs --css=rust.css --include-before-body=doc/version_info.html --include-in-header=doc/favicon.inc
+
+HTML_OPTS = $(BASE_DOC_OPTS) --to=html5 --section-divs --css=rust.css \
+ --include-before-body=doc/version_info.html \
+ --include-in-header=doc/favicon.inc
+
TEX_OPTS = $(BASE_DOC_OPTS) --to=latex
EPUB_OPTS = $(BASE_DOC_OPTS) --to=epub
--include-before-body=doc/version_info.html \
--output=$@
-DOCS += doc/tutorial-macros.html
-doc/tutorial-macros.html: tutorial-macros.md doc/version_info.html doc/rust.css \
+# Guides
+
+DOCS += doc/guide-macros.html
+doc/guide-macros.html: $(S)doc/guide-macros.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-container.html
-doc/tutorial-container.html: tutorial-container.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-container.html
+doc/guide-container.html: $(S)doc/guide-container.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-ffi.html
-doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-ffi.html
+doc/guide-ffi.html: $(S)doc/guide-ffi.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-testing.html
-doc/tutorial-testing.html: tutorial-testing.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-testing.html
+doc/guide-testing.html: $(S)doc/guide-testing.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-borrowed-ptr.html
-doc/tutorial-borrowed-ptr.html: tutorial-borrowed-ptr.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-borrowed-ptr.html
+doc/guide-borrowed-ptr.html: $(S)doc/guide-borrowed-ptr.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-tasks.html
-doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-tasks.html
+doc/guide-tasks.html: $(S)doc/guide-tasks.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-conditions.html
-doc/tutorial-conditions.html: tutorial-conditions.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-conditions.html
+doc/guide-conditions.html: $(S)doc/guide-conditions.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
-DOCS += doc/tutorial-rustpkg.html
-doc/tutorial-rustpkg.html: tutorial-rustpkg.md doc/version_info.html doc/rust.css \
+DOCS += doc/guide-rustpkg.html
+doc/guide-rustpkg.html: $(S)doc/guide-rustpkg.md doc/version_info.html doc/rust.css \
doc/favicon.inc
@$(call E, pandoc: $@)
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
# Markdown files under doc/ that should have their code extracted and run
-DOC_TEST_NAMES = tutorial tutorial-ffi tutorial-macros tutorial-borrowed-ptr \
- tutorial-tasks tutorial-conditions tutorial-container rust
+DOC_TEST_NAMES = tutorial guide-ffi guide-macros guide-borrowed-ptr \
+ guide-tasks guide-conditions guide-container rust
######################################################################
# Environment configuration