(index<- )        ./libstd/unstable/finally.rs

    git branch:    * master           c7553ea auto merge of #13609 : richo/rust/str-type-vim, r=alexcrichton
    modified:    Sat Apr 19 11:22:39 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  use ops::Drop;
  34  
  35  #[cfg(test)] use task::failing;
  36  
  37  pub trait Finally<T> {
  38      fn finally(&self, dtor: ||) -> T;
  39  }
  40  
  41  impl<'a,T> Finally<T> for ||: 'a -> T {
  42      fn finally(&self, dtor||) -> T {
  43          try_finally(&mut (), (),
  44                      |_, _| (*self)(),
  45                      |_| dtor())
  46      }
  47  }
  48  
  49  impl<T> Finally<T> for fn() -> T {
  50      fn finally(&self, dtor||) -> T {
  51          try_finally(&mut (), (),
  52                      |_, _| (*self)(),
  53                      |_| dtor())
  54      }
  55  }
  56  
  57  /**
  58   * The most general form of the `finally` functions. The function
  59   * `try_fn` will be invoked first; whether or not it fails, the
  60   * function `finally_fn` will be invoked next. The two parameters
  61   * `mutate` and `drop` are used to thread state through the two
  62   * closures. `mutate` is used for any shared, mutable state that both
  63   * closures require access to; `drop` is used for any state that the
  64   * `try_fn` requires ownership of.
  65   *
  66   * **WARNING:** While shared, mutable state between the try and finally
  67   * function is often necessary, one must be very careful; the `try`
  68   * function could have failed at any point, so the values of the shared
  69   * state may be inconsistent.
  70   *
  71   * # Example
  72   *
  73   * ```
  74   * use std::unstable::finally::try_finally;
  75   *
  76   * struct State<'a> { buffer: &'a mut [u8], len: uint }
  77   * # let mut buf = [];
  78   * let mut state = State { buffer: buf, len: 0 };
  79   * try_finally(
  80   *     &mut state, (),
  81   *     |state, ()| {
  82   *         // use state.buffer, state.len
  83   *     },
  84   *     |state| {
  85   *         // use state.buffer, state.len to cleanup
  86   *     })
  87   * ```
  88   */
  89  pub fn try_finally<T,U,R>(mutate&mut T,
  90                            dropU,
  91                            try_fn|&mut T, U-> R,
  92                            finally_fn|&mut T|)
  93                            -> R {
  94      let f = Finallyalizer {
  95          mutate: mutate,
  96          dtor: finally_fn,
  97      };
  98      try_fn(&mut *f.mutate, drop)
  99  }
 100  
 101  struct Finallyalizer<'a,A> {
 102      mutate: &'a mut A,
 103      dtor: |&mut A|: 'a
 104  }
 105  
 106  #[unsafe_destructor]
 107  impl<'a,A> Drop for Finallyalizer<'a,A> {
 108      #[inline]
 109      fn drop(&mut self) {
 110          (self.dtor)(self.mutate);
 111      }
 112  }
 113  
 114  #[test]
 115  fn test_success() {
 116      let mut i = 0;
 117      try_finally(
 118          &mut i, (),
 119          |i, (){
 120              *i = 10;
 121          },
 122          |i| {
 123              assert!(!failing());
 124              assert_eq!(*i, 10);
 125              *i = 20;
 126          });
 127      assert_eq!(i, 20);
 128  }
 129  
 130  #[test]
 131  #[should_fail]
 132  fn test_fail() {
 133      let mut i = 0;
 134      try_finally(
 135          &mut i, (),
 136          |i, (){
 137              *i = 10;
 138              fail!();
 139          },
 140          |i| {
 141              assert!(failing());
 142              assert_eq!(*i, 10);
 143          })
 144  }
 145  
 146  #[test]
 147  fn test_retval() {
 148      let closure: || -> int = || 10;
 149      let i = closure.finally(|| { });
 150      assert_eq!(i, 10);
 151  }
 152  
 153  #[test]
 154  fn test_compact() {
 155      fn do_some_fallible_work() {}
 156      fn but_always_run_this_function() { }
 157      do_some_fallible_work.finally(
 158          but_always_run_this_function);
 159  }