about summary refs log tree commit diff
path: root/src/libstd/condition.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-09-17 19:42:07 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-17 20:50:23 -0700
commit88bc11e646c8d1db7ac7894f74e2f660d9a82c54 (patch)
treee0dfde7157dadefae8bb2420e8e93f9eefc95bfa /src/libstd/condition.rs
parent0efc4822e93221714aa7d142de44a057bdbad2ca (diff)
downloadrust-88bc11e646c8d1db7ac7894f74e2f660d9a82c54.tar.gz
rust-88bc11e646c8d1db7ac7894f74e2f660d9a82c54.zip
Document a few undocumented modules in libstd
Hopefull this will make our libstd docs appear a little more "full".
Diffstat (limited to 'src/libstd/condition.rs')
-rw-r--r--src/libstd/condition.rs175
1 files changed, 142 insertions, 33 deletions
diff --git a/src/libstd/condition.rs b/src/libstd/condition.rs
index 954b8bd7330..c47dcfe3de6 100644
--- a/src/libstd/condition.rs
+++ b/src/libstd/condition.rs
@@ -8,71 +8,179 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/*! Condition handling */
+/*!
 
-#[allow(missing_doc)];
+Condition handling
+
+Conditions are a utility used to deal with handling error conditions. The syntax
+of a condition handler strikes a resemblance to try/catch blocks in other
+languages, but condition handlers are *not* a form of exception handling in the
+same manner.
+
+A condition is declared through the `condition!` macro provided by the compiler:
+
+~~~{.rust}
+condition! {
+    pub my_error: int -> ~str;
+}
+~~~
+
+This macro declares an inner module called `my_error` with one static variable,
+`cond` that is a static `Condition` instance. To help understand what the other
+parameters are used for, an example usage of this condition would be:
+
+~~~{.rust}
+do my_error::cond.trap(|raised_int| {
+
+    // the condition `my_error` was raised on, and the value it raised is stored
+    // in `raised_int`. This closure must return a `~str` type (as specified in
+    // the declaration of the condition
+    if raised_int == 3 { ~"three" } else { ~"oh well" }
+
+}).inside {
+
+    // The condition handler above is installed for the duration of this block.
+    // That handler will override any previous handler, but the previous handler
+    // is restored when this block returns (handlers nest)
+    //
+    // If any code from this block (or code from another block) raises on the
+    // condition, then the above handler will be invoked (so long as there's no
+    // other nested handler).
+
+    println(my_error::cond.raise(3)); // prints "three"
+    println(my_error::cond.raise(4)); // prints "oh well"
+
+}
+~~~
+
+Condition handling is useful in cases where propagating errors is either to
+cumbersome or just not necessary in the first place. It should also be noted,
+though, that if there is not handler installed when a condition is raised, then
+the task invokes `fail!()` and will terminate.
+
+## More Info
+
+Condition handlers as an error strategy is well explained in the [conditions
+tutorial](http://static.rust-lang.org/doc/master/tutorial-conditions.html),
+along with comparing and contrasting it with other error handling strategies.
+
+*/
 
 use local_data;
 use prelude::*;
+use unstable::raw::Closure;
 
-// helper for transmutation, shown below.
-type RustClosure = (int, int);
-
+#[doc(hidden)]
 pub struct Handler<T, U> {
-    handle: RustClosure,
-    prev: Option<@Handler<T, U>>,
+    priv handle: Closure,
+    priv prev: Option<@Handler<T, U>>,
 }
 
+/// This struct represents the state of a condition handler. It contains a key
+/// into TLS which holds the currently install handler, along with the name of
+/// the condition (useful for debugging).
+///
+/// This struct should never be created directly, but rather only through the
+/// `condition!` macro provided to all libraries using libstd.
 pub struct Condition<T, U> {
+    /// Name of the condition handler
     name: &'static str,
+    /// TLS key used to insert/remove values in TLS.
     key: local_data::Key<@Handler<T, U>>
 }
 
 impl<T, U> Condition<T, U> {
+    /// Creates an object which binds the specified handler. This will also save
+    /// the current handler *on creation* such that when the `Trap` is consumed,
+    /// it knows which handler to restore.
+    ///
+    /// # Example
+    ///
+    /// ~~~{.rust}
+    /// condition! { my_error: int -> int; }
+    ///
+    /// let trap = my_error::cond.trap(|error| error + 3);
+    ///
+    /// // use `trap`'s inside method to register the handler and then run a
+    /// // block of code with the handler registered
+    /// ~~~
     pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
-        unsafe {
-            let p : *RustClosure = ::cast::transmute(&h);
-            let prev = local_data::get(self.key, |k| k.map(|&x| *x));
-            let h = @Handler { handle: *p, prev: prev };
-            Trap { cond: self, handler: h }
-        }
+        let h: Closure = unsafe { ::cast::transmute(h) };
+        let prev = local_data::get(self.key, |k| k.map(|&x| *x));
+        let h = @Handler { handle: h, prev: prev };
+        Trap { cond: self, handler: h }
     }
 
+    /// Raises on this condition, invoking any handler if one has been
+    /// registered, or failing the current task otherwise.
+    ///
+    /// While a condition handler is being run, the condition will have no
+    /// handler listed, so a task failure will occur if the condition is
+    /// re-raised during the handler.
+    ///
+    /// # Arguments
+    ///
+    /// * t - The argument to pass along to the condition handler.
+    ///
+    /// # Return value
+    ///
+    /// If a handler is found, its return value is returned, otherwise this
+    /// function will not return.
     pub fn raise(&self, t: T) -> U {
         let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
         self.raise_default(t, || fail!(msg.clone()))
     }
 
+    /// Performs the same functionality as `raise`, except that when no handler
+    /// is found the `default` argument is called instead of failing the task.
     pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
-        unsafe {
-            match local_data::pop(self.key) {
-                None => {
-                    debug!("Condition.raise: found no handler");
-                    default()
-                }
-                Some(handler) => {
-                    debug!("Condition.raise: found handler");
-                    match handler.prev {
-                        None => {}
-                        Some(hp) => local_data::set(self.key, hp)
-                    }
-                    let handle : &fn(T) -> U =
-                        ::cast::transmute(handler.handle);
-                    let u = handle(t);
-                    local_data::set(self.key, handler);
-                    u
+        match local_data::pop(self.key) {
+            None => {
+                debug!("Condition.raise: found no handler");
+                default()
+            }
+            Some(handler) => {
+                debug!("Condition.raise: found handler");
+                match handler.prev {
+                    None => {}
+                    Some(hp) => local_data::set(self.key, hp)
                 }
+                let handle : &fn(T) -> U = unsafe {
+                    ::cast::transmute(handler.handle)
+                };
+                let u = handle(t);
+                local_data::set(self.key, handler);
+                u
             }
         }
     }
 }
 
+/// A `Trap` is created when the `trap` method is invoked on a `Condition`, and
+/// it is used to actually bind a handler into the TLS slot reserved for this
+/// condition.
+///
+/// Normally this object is not dealt with directly, but rather it's directly
+/// used after being returned from `trap`
 struct Trap<'self, T, U> {
-    cond: &'self Condition<T, U>,
-    handler: @Handler<T, U>
+    priv cond: &'self Condition<T, U>,
+    priv handler: @Handler<T, U>
 }
 
 impl<'self, T, U> Trap<'self, T, U> {
+    /// Execute a block of code with this trap handler's exception handler
+    /// registered.
+    ///
+    /// # Example
+    ///
+    /// ~~~{.rust}
+    /// condition! { my_error: int -> int; }
+    ///
+    /// let result = do my_error::cond.trap(|error| error + 3).inside {
+    ///     my_error::cond.raise(4)
+    /// };
+    /// assert_eq!(result, 7);
+    /// ~~~
     pub fn inside<V>(&self, inner: &'self fn() -> V) -> V {
         let _g = Guard { cond: self.cond };
         debug!("Trap: pushing handler to TLS");
@@ -81,8 +189,9 @@ impl<'self, T, U> Trap<'self, T, U> {
     }
 }
 
+#[doc(hidden)]
 struct Guard<'self, T, U> {
-    cond: &'self Condition<T, U>
+    priv cond: &'self Condition<T, U>
 }
 
 #[unsafe_destructor]