]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | //! A type representing values that may be computed concurrently and operations | |
12 | //! for working with them. | |
13 | //! | |
85aaf69f | 14 | //! # Examples |
1a4d82fc | 15 | //! |
85aaf69f | 16 | //! ``` |
c1a9b12d SL |
17 | //! #![feature(future)] |
18 | //! | |
1a4d82fc | 19 | //! use std::sync::Future; |
85aaf69f SL |
20 | //! |
21 | //! // a fake, for now | |
22 | //! fn fib(n: u32) -> u32 { 42 }; | |
23 | //! | |
24 | //! let mut delayed_fib = Future::spawn(move || fib(5000)); | |
25 | //! | |
26 | //! // do stuff... | |
27 | //! | |
1a4d82fc JJ |
28 | //! println!("fib(5000) = {}", delayed_fib.get()) |
29 | //! ``` | |
30 | ||
31 | #![allow(missing_docs)] | |
62682a34 | 32 | #![unstable(feature = "future", |
85aaf69f SL |
33 | reason = "futures as-is have yet to be deeply reevaluated with recent \ |
34 | core changes to Rust's synchronization story, and will likely \ | |
35 | become stable in the future but are unstable until that time")] | |
62682a34 SL |
36 | #![deprecated(since = "1.2.0", |
37 | reason = "implementation does not match the quality of the \ | |
38 | standard library and this will likely be prototyped \ | |
39 | outside in crates.io first")] | |
40 | #![allow(deprecated)] | |
1a4d82fc JJ |
41 | |
42 | use core::prelude::*; | |
43 | use core::mem::replace; | |
44 | ||
c34b1796 | 45 | use boxed::Box; |
1a4d82fc JJ |
46 | use self::FutureState::*; |
47 | use sync::mpsc::{Receiver, channel}; | |
c34b1796 | 48 | use thunk::Thunk; |
85aaf69f | 49 | use thread; |
1a4d82fc JJ |
50 | |
51 | /// A type encapsulating the result of a computation which may not be complete | |
52 | pub struct Future<A> { | |
53 | state: FutureState<A>, | |
54 | } | |
55 | ||
56 | enum FutureState<A> { | |
85aaf69f | 57 | Pending(Thunk<'static,(),A>), |
1a4d82fc JJ |
58 | Evaluating, |
59 | Forced(A) | |
60 | } | |
61 | ||
62 | /// Methods on the `future` type | |
63 | impl<A:Clone> Future<A> { | |
64 | pub fn get(&mut self) -> A { | |
65 | //! Get the value of the future. | |
66 | (*(self.get_ref())).clone() | |
67 | } | |
68 | } | |
69 | ||
70 | impl<A> Future<A> { | |
71 | /// Gets the value from this future, forcing evaluation. | |
72 | pub fn into_inner(mut self) -> A { | |
73 | self.get_ref(); | |
74 | let state = replace(&mut self.state, Evaluating); | |
75 | match state { | |
76 | Forced(v) => v, | |
77 | _ => panic!( "Logic error." ), | |
78 | } | |
79 | } | |
80 | ||
81 | pub fn get_ref<'a>(&'a mut self) -> &'a A { | |
82 | /*! | |
83 | * Executes the future's closure and then returns a reference | |
84 | * to the result. The reference lasts as long as | |
85 | * the future. | |
86 | */ | |
87 | match self.state { | |
88 | Forced(ref v) => return v, | |
89 | Evaluating => panic!("Recursive forcing of future!"), | |
90 | Pending(_) => { | |
91 | match replace(&mut self.state, Evaluating) { | |
92 | Forced(_) | Evaluating => panic!("Logic error."), | |
93 | Pending(f) => { | |
c34b1796 | 94 | self.state = Forced(f()); |
1a4d82fc JJ |
95 | self.get_ref() |
96 | } | |
97 | } | |
98 | } | |
99 | } | |
100 | } | |
101 | ||
102 | pub fn from_value(val: A) -> Future<A> { | |
103 | /*! | |
104 | * Create a future from a value. | |
105 | * | |
106 | * The value is immediately available and calling `get` later will | |
107 | * not block. | |
108 | */ | |
109 | ||
110 | Future {state: Forced(val)} | |
111 | } | |
112 | ||
113 | pub fn from_fn<F>(f: F) -> Future<A> | |
85aaf69f | 114 | where F : FnOnce() -> A, F : Send + 'static |
1a4d82fc JJ |
115 | { |
116 | /*! | |
117 | * Create a future from a function. | |
118 | * | |
119 | * The first time that the value is requested it will be retrieved by | |
120 | * calling the function. Note that this function is a local | |
121 | * function. It is not spawned into another task. | |
122 | */ | |
123 | ||
c34b1796 | 124 | Future {state: Pending(Box::new(f))} |
1a4d82fc JJ |
125 | } |
126 | } | |
127 | ||
85aaf69f | 128 | impl<A:Send+'static> Future<A> { |
1a4d82fc JJ |
129 | pub fn from_receiver(rx: Receiver<A>) -> Future<A> { |
130 | /*! | |
131 | * Create a future from a port | |
132 | * | |
133 | * The first time that the value is requested the task will block | |
134 | * waiting for the result to be received on the port. | |
135 | */ | |
136 | ||
85aaf69f | 137 | Future::from_fn(move || { |
1a4d82fc JJ |
138 | rx.recv().unwrap() |
139 | }) | |
140 | } | |
141 | ||
142 | pub fn spawn<F>(blk: F) -> Future<A> | |
85aaf69f | 143 | where F : FnOnce() -> A, F : Send + 'static |
1a4d82fc JJ |
144 | { |
145 | /*! | |
146 | * Create a future from a unique closure. | |
147 | * | |
148 | * The closure will be run in a new task and its result used as the | |
149 | * value of the future. | |
150 | */ | |
151 | ||
152 | let (tx, rx) = channel(); | |
153 | ||
85aaf69f | 154 | thread::spawn(move || { |
1a4d82fc JJ |
155 | // Don't panic if the other end has hung up |
156 | let _ = tx.send(blk()); | |
157 | }); | |
158 | ||
159 | Future::from_receiver(rx) | |
160 | } | |
161 | } | |
162 | ||
163 | #[cfg(test)] | |
d9579d0f | 164 | mod tests { |
1a4d82fc JJ |
165 | use prelude::v1::*; |
166 | use sync::mpsc::channel; | |
167 | use sync::Future; | |
85aaf69f | 168 | use thread; |
1a4d82fc JJ |
169 | |
170 | #[test] | |
171 | fn test_from_value() { | |
172 | let mut f = Future::from_value("snail".to_string()); | |
173 | assert_eq!(f.get(), "snail"); | |
174 | } | |
175 | ||
176 | #[test] | |
177 | fn test_from_receiver() { | |
178 | let (tx, rx) = channel(); | |
179 | tx.send("whale".to_string()).unwrap(); | |
180 | let mut f = Future::from_receiver(rx); | |
181 | assert_eq!(f.get(), "whale"); | |
182 | } | |
183 | ||
184 | #[test] | |
185 | fn test_from_fn() { | |
186 | let mut f = Future::from_fn(move|| "brail".to_string()); | |
187 | assert_eq!(f.get(), "brail"); | |
188 | } | |
189 | ||
190 | #[test] | |
191 | fn test_interface_get() { | |
192 | let mut f = Future::from_value("fail".to_string()); | |
193 | assert_eq!(f.get(), "fail"); | |
194 | } | |
195 | ||
196 | #[test] | |
197 | fn test_interface_unwrap() { | |
198 | let f = Future::from_value("fail".to_string()); | |
199 | assert_eq!(f.into_inner(), "fail"); | |
200 | } | |
201 | ||
202 | #[test] | |
203 | fn test_get_ref_method() { | |
85aaf69f | 204 | let mut f = Future::from_value(22); |
1a4d82fc JJ |
205 | assert_eq!(*f.get_ref(), 22); |
206 | } | |
207 | ||
208 | #[test] | |
209 | fn test_spawn() { | |
210 | let mut f = Future::spawn(move|| "bale".to_string()); | |
211 | assert_eq!(f.get(), "bale"); | |
212 | } | |
213 | ||
214 | #[test] | |
c34b1796 | 215 | #[should_panic] |
1a4d82fc JJ |
216 | fn test_future_panic() { |
217 | let mut f = Future::spawn(move|| panic!()); | |
218 | let _x: String = f.get(); | |
219 | } | |
220 | ||
221 | #[test] | |
222 | fn test_sendable_future() { | |
223 | let expected = "schlorf"; | |
224 | let (tx, rx) = channel(); | |
225 | let f = Future::spawn(move|| { expected }); | |
85aaf69f | 226 | let _t = thread::spawn(move|| { |
1a4d82fc JJ |
227 | let mut f = f; |
228 | tx.send(f.get()).unwrap(); | |
229 | }); | |
230 | assert_eq!(rx.recv().unwrap(), expected); | |
231 | } | |
232 | } |