]> git.lizzy.rs Git - rust.git/blob - src/libcore/finally.rs
/*! -> //!
[rust.git] / src / libcore / finally.rs
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 //! The Finally trait provides a method, `finally` on
12 //! stack closures that emulates Java-style try/finally blocks.
13 //!
14 //! Using the `finally` method is sometimes convenient, but the type rules
15 //! prohibit any shared, mutable state between the "try" case and the
16 //! "finally" case. For advanced cases, the `try_finally` function can
17 //! also be used. See that function for more details.
18 //!
19 //! # Example
20 //!
21 //! ```
22 //! use std::finally::Finally;
23 //!
24 //! (|| {
25 //!     // ...
26 //! }).finally(|| {
27 //!     // this code is always run
28 //! })
29 //! ```
30
31 #![experimental]
32
33 use ops::Drop;
34
35 /// A trait for executing a destructor unconditionally after a block of code,
36 /// regardless of whether the blocked fails.
37 pub trait Finally<T> {
38     /// Executes this object, unconditionally running `dtor` after this block of
39     /// code has run.
40     fn finally(&mut self, dtor: ||) -> T;
41 }
42
43 impl<'a,T> Finally<T> for ||: 'a -> T {
44     fn finally(&mut self, dtor: ||) -> T {
45         try_finally(&mut (), self,
46                     |_, f| (*f)(),
47                     |_| dtor())
48     }
49 }
50
51 impl<T> Finally<T> for fn() -> T {
52     fn finally(&mut self, dtor: ||) -> T {
53         try_finally(&mut (), (),
54                     |_, _| (*self)(),
55                     |_| dtor())
56     }
57 }
58
59 /**
60  * The most general form of the `finally` functions. The function
61  * `try_fn` will be invoked first; whether or not it panics, the
62  * function `finally_fn` will be invoked next. The two parameters
63  * `mutate` and `drop` are used to thread state through the two
64  * closures. `mutate` is used for any shared, mutable state that both
65  * closures require access to; `drop` is used for any state that the
66  * `try_fn` requires ownership of.
67  *
68  * **WARNING:** While shared, mutable state between the try and finally
69  * function is often necessary, one must be very careful; the `try`
70  * function could have panicked at any point, so the values of the shared
71  * state may be inconsistent.
72  *
73  * # Example
74  *
75  * ```
76  * use std::finally::try_finally;
77  *
78  * struct State<'a> { buffer: &'a mut [u8], len: uint }
79  * # let mut buf = [];
80  * let mut state = State { buffer: &mut buf, len: 0 };
81  * try_finally(
82  *     &mut state, (),
83  *     |state, ()| {
84  *         // use state.buffer, state.len
85  *     },
86  *     |state| {
87  *         // use state.buffer, state.len to cleanup
88  *     })
89  * ```
90  */
91 pub fn try_finally<T,U,R>(mutate: &mut T,
92                           drop: U,
93                           try_fn: |&mut T, U| -> R,
94                           finally_fn: |&mut T|)
95                           -> R {
96     let f = Finallyalizer {
97         mutate: mutate,
98         dtor: finally_fn,
99     };
100     try_fn(&mut *f.mutate, drop)
101 }
102
103 struct Finallyalizer<'a,A:'a> {
104     mutate: &'a mut A,
105     dtor: |&mut A|: 'a
106 }
107
108 #[unsafe_destructor]
109 impl<'a,A> Drop for Finallyalizer<'a,A> {
110     #[inline]
111     fn drop(&mut self) {
112         (self.dtor)(self.mutate);
113     }
114 }
115