]> git.lizzy.rs Git - rust.git/blob - src/libcore/finally.rs
librustc: Remove the fallback to `int` from typechecking.
[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 /*!
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::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::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                           drop: U,
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 = 0i;
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 = 0i;
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 }