]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/future.rs
librustc: Remove the fallback to `int` from typechecking.
[rust.git] / src / libstd / sync / future.rs
1 // Copyright 2012-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  * A type representing values that may be computed concurrently and
13  * operations for working with them.
14  *
15  * # Example
16  *
17  * ```rust
18  * use std::sync::Future;
19  * # fn fib(n: uint) -> uint {42};
20  * # fn make_a_sandwich() {};
21  * let mut delayed_fib = Future::spawn(proc() { fib(5000) });
22  * make_a_sandwich();
23  * println!("fib(5000) = {}", delayed_fib.get())
24  * ```
25  */
26
27 #![allow(missing_doc)]
28
29 use core::prelude::*;
30 use core::mem::replace;
31
32 use comm::{Receiver, channel};
33 use task::spawn;
34
35 /// A type encapsulating the result of a computation which may not be complete
36 pub struct Future<A> {
37     state: FutureState<A>,
38 }
39
40 enum FutureState<A> {
41     Pending(proc():Send -> A),
42     Evaluating,
43     Forced(A)
44 }
45
46 /// Methods on the `future` type
47 impl<A:Clone> Future<A> {
48     pub fn get(&mut self) -> A {
49         //! Get the value of the future.
50         (*(self.get_ref())).clone()
51     }
52 }
53
54 impl<A> Future<A> {
55     /// Gets the value from this future, forcing evaluation.
56     pub fn unwrap(mut self) -> A {
57         self.get_ref();
58         let state = replace(&mut self.state, Evaluating);
59         match state {
60             Forced(v) => v,
61             _ => fail!( "Logic error." ),
62         }
63     }
64
65     pub fn get_ref<'a>(&'a mut self) -> &'a A {
66         /*!
67         * Executes the future's closure and then returns a reference
68         * to the result.  The reference lasts as long as
69         * the future.
70         */
71         match self.state {
72             Forced(ref v) => return v,
73             Evaluating => fail!("Recursive forcing of future!"),
74             Pending(_) => {
75                 match replace(&mut self.state, Evaluating) {
76                     Forced(_) | Evaluating => fail!("Logic error."),
77                     Pending(f) => {
78                         self.state = Forced(f());
79                         self.get_ref()
80                     }
81                 }
82             }
83         }
84     }
85
86     pub fn from_value(val: A) -> Future<A> {
87         /*!
88          * Create a future from a value.
89          *
90          * The value is immediately available and calling `get` later will
91          * not block.
92          */
93
94         Future {state: Forced(val)}
95     }
96
97     pub fn from_fn(f: proc():Send -> A) -> Future<A> {
98         /*!
99          * Create a future from a function.
100          *
101          * The first time that the value is requested it will be retrieved by
102          * calling the function.  Note that this function is a local
103          * function. It is not spawned into another task.
104          */
105
106         Future {state: Pending(f)}
107     }
108 }
109
110 impl<A:Send> Future<A> {
111     pub fn from_receiver(rx: Receiver<A>) -> Future<A> {
112         /*!
113          * Create a future from a port
114          *
115          * The first time that the value is requested the task will block
116          * waiting for the result to be received on the port.
117          */
118
119         Future::from_fn(proc() {
120             rx.recv()
121         })
122     }
123
124     pub fn spawn(blk: proc():Send -> A) -> Future<A> {
125         /*!
126          * Create a future from a unique closure.
127          *
128          * The closure will be run in a new task and its result used as the
129          * value of the future.
130          */
131
132         let (tx, rx) = channel();
133
134         spawn(proc() {
135             // Don't fail if the other end has hung up
136             let _ = tx.send_opt(blk());
137         });
138
139         Future::from_receiver(rx)
140     }
141 }
142
143 #[cfg(test)]
144 mod test {
145     use prelude::*;
146     use sync::Future;
147     use task;
148     use comm::{channel, Sender};
149
150     #[test]
151     fn test_from_value() {
152         let mut f = Future::from_value("snail".to_string());
153         assert_eq!(f.get(), "snail".to_string());
154     }
155
156     #[test]
157     fn test_from_receiver() {
158         let (tx, rx) = channel();
159         tx.send("whale".to_string());
160         let mut f = Future::from_receiver(rx);
161         assert_eq!(f.get(), "whale".to_string());
162     }
163
164     #[test]
165     fn test_from_fn() {
166         let mut f = Future::from_fn(proc() "brail".to_string());
167         assert_eq!(f.get(), "brail".to_string());
168     }
169
170     #[test]
171     fn test_interface_get() {
172         let mut f = Future::from_value("fail".to_string());
173         assert_eq!(f.get(), "fail".to_string());
174     }
175
176     #[test]
177     fn test_interface_unwrap() {
178         let f = Future::from_value("fail".to_string());
179         assert_eq!(f.unwrap(), "fail".to_string());
180     }
181
182     #[test]
183     fn test_get_ref_method() {
184         let mut f = Future::from_value(22i);
185         assert_eq!(*f.get_ref(), 22);
186     }
187
188     #[test]
189     fn test_spawn() {
190         let mut f = Future::spawn(proc() "bale".to_string());
191         assert_eq!(f.get(), "bale".to_string());
192     }
193
194     #[test]
195     #[should_fail]
196     fn test_futurefail() {
197         let mut f = Future::spawn(proc() fail!());
198         let _x: String = f.get();
199     }
200
201     #[test]
202     fn test_sendable_future() {
203         let expected = "schlorf";
204         let f = Future::spawn(proc() { expected });
205         task::spawn(proc() {
206             let mut f = f;
207             let actual = f.get();
208             assert_eq!(actual, expected);
209         });
210     }
211
212     #[test]
213     fn test_dropped_future_doesnt_fail() {
214         struct Bomb(Sender<bool>);
215
216         local_data_key!(LOCAL: Bomb)
217
218         impl Drop for Bomb {
219             fn drop(&mut self) {
220                 let Bomb(ref tx) = *self;
221                 tx.send(task::failing());
222             }
223         }
224
225         // Spawn a future, but drop it immediately. When we receive the result
226         // later on, we should never view the task as having failed.
227         let (tx, rx) = channel();
228         drop(Future::spawn(proc() {
229             LOCAL.replace(Some(Bomb(tx)));
230         }));
231
232         // Make sure the future didn't fail the task.
233         assert!(!rx.recv());
234     }
235 }