(index<- )        ./libcore/finally.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*!
  12  The Finally trait provides a method, `finally` on
  13  stack closures that emulates Java-style try/finally blocks.
  14  
  15  Using the `finally` method is sometimes convenient, but the type rules
  16  prohibit any shared, mutable state between the "try" case and the
  17  "finally" case. For advanced cases, the `try_finally` function can
  18  also be used. See that function for more details.
  19  
  20  # Example
  21  
  22  ```
  23  use std::unstable::finally::Finally;
  24  
  25  (|| {
  26      // ...
  27  }).finally(|| {
  28      // this code is always run
  29  })
  30  ```
  31  */
  32  
  33  #![experimental]
  34  
  35  use ops::Drop;
  36  
  37  /// A trait for executing a destructor unconditionally after a block of code,
  38  /// regardless of whether the blocked fails.
  39  pub trait Finally<T> {
  40      /// Executes this object, unconditionally running `dtor` after this block of
  41      /// code has run.
  42      fn finally(&mut self, dtor: ||) -> T;
  43  }
  44  
  45  impl<'a,T> Finally<T> for ||: 'a -> T {
  46      fn finally(&mut self, dtor||) -> T {
  47          try_finally(&mut (), self,
  48                      |_, f| (*f)(),
  49                      |_| dtor())
  50      }
  51  }
  52  
  53  impl<T> Finally<T> for fn() -> T {
  54      fn finally(&mut self, dtor||) -> T {
  55          try_finally(&mut (), (),
  56                      |_, _| (*self)(),
  57                      |_| dtor())
  58      }
  59  }
  60  
  61  /**
  62   * The most general form of the `finally` functions. The function
  63   * `try_fn` will be invoked first; whether or not it fails, the
  64   * function `finally_fn` will be invoked next. The two parameters
  65   * `mutate` and `drop` are used to thread state through the two
  66   * closures. `mutate` is used for any shared, mutable state that both
  67   * closures require access to; `drop` is used for any state that the
  68   * `try_fn` requires ownership of.
  69   *
  70   * **WARNING:** While shared, mutable state between the try and finally
  71   * function is often necessary, one must be very careful; the `try`
  72   * function could have failed at any point, so the values of the shared
  73   * state may be inconsistent.
  74   *
  75   * # Example
  76   *
  77   * ```
  78   * use std::unstable::finally::try_finally;
  79   *
  80   * struct State<'a> { buffer: &'a mut [u8], len: uint }
  81   * # let mut buf = [];
  82   * let mut state = State { buffer: buf, len: 0 };
  83   * try_finally(
  84   *     &mut state, (),
  85   *     |state, ()| {
  86   *         // use state.buffer, state.len
  87   *     },
  88   *     |state| {
  89   *         // use state.buffer, state.len to cleanup
  90   *     })
  91   * ```
  92   */
  93  pub fn try_finally<T,U,R>(mutate: &mut T,
  94                            dropU,
  95                            try_fn: |&mut T, U-> R,
  96                            finally_fn: |&mut T|)
  97                            -> R {
  98      let f = Finallyalizer {
  99          mutate: mutate,
 100          dtor: finally_fn,
 101      };
 102      try_fn(&mut *f.mutate, drop)
 103  }
 104  
 105  struct Finallyalizer<'a,A> {
 106      mutate: &'a mut A,
 107      dtor: |&mut A|: 'a
 108  }
 109  
 110  #[unsafe_destructor]
 111  impl<'a,A> Drop for Finallyalizer<'a,A> {
 112      #[inline]
 113      fn drop(&mut self) {
 114          (self.dtor)(self.mutate);
 115      }
 116  }
 117  
 118  #[cfg(test)]
 119  mod test {
 120      use super::{try_finally, Finally};
 121      use realstd::task::failing;
 122  
 123      #[test]
 124      fn test_success() {
 125          let mut i = 0;
 126          try_finally(
 127              &mut i, (),
 128              |i, (){
 129                  *i = 10;
 130              },
 131              |i| {
 132                  assert!(!failing());
 133                  assert_eq!(*i, 10);
 134                  *i = 20;
 135              });
 136          assert_eq!(i, 20);
 137      }
 138  
 139      #[test]
 140      #[should_fail]
 141      fn test_fail() {
 142          let mut i = 0;
 143          try_finally(
 144              &mut i, (),
 145              |i, (){
 146                  *i = 10;
 147                  fail!();
 148              },
 149              |i| {
 150                  assert!(failing());
 151                  assert_eq!(*i, 10);
 152              })
 153      }
 154  
 155      #[test]
 156      fn test_retval() {
 157          let mut closure: || -> int = || 10;
 158          let i = closure.finally(|| { });
 159          assert_eq!(i, 10);
 160      }
 161  
 162      #[test]
 163      fn test_compact() {
 164          fn do_some_fallible_work() {}
 165          fn but_always_run_this_function() { }
 166          let mut f = do_some_fallible_work;
 167          f.finally(but_always_run_this_function);
 168      }
 169  }