]> git.lizzy.rs Git - rust.git/blob - src/libstd/unstable/finally.rs
Honor hidden doc attribute of derivable trait methods
[rust.git] / src / libstd / unstable / 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::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                           drop: U,
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 }