diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-10-23 14:20:57 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-10-23 14:46:49 -0700 |
| commit | d29962f0eb2772c208a299efae86ad16bc25f7de (patch) | |
| tree | fe1b53ced7fa23e80a7382874c4f1e915c26c6d4 /src/libstd | |
| parent | f500f3f1fb4092bf7993170d755377268943e94b (diff) | |
| download | rust-d29962f0eb2772c208a299efae86ad16bc25f7de.tar.gz rust-d29962f0eb2772c208a299efae86ad16bc25f7de.zip | |
Move futures to std
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/future.rs | 246 | ||||
| -rw-r--r-- | src/libstd/std.rc | 1 |
2 files changed, 247 insertions, 0 deletions
diff --git a/src/libstd/future.rs b/src/libstd/future.rs new file mode 100644 index 00000000000..503e915cf87 --- /dev/null +++ b/src/libstd/future.rs @@ -0,0 +1,246 @@ +// NB: transitionary, de-mode-ing. +// tjc: allowing deprecated modes due to function issue. +// can re-forbid them after snapshot +#[forbid(deprecated_pattern)]; + +/*! + * A type representing values that may be computed concurrently and + * operations for working with them. + * + * # Example + * + * ~~~ + * let delayed_fib = future::spawn {|| fib(5000) }; + * make_a_sandwich(); + * io::println(fmt!("fib(5000) = %?", delayed_fib.get())) + * ~~~ + */ + +use either::Either; +use pipes::{recv, oneshot, ChanOne, PortOne, send_one, recv_one}; +use cast::copy_lifetime; + +#[doc = "The future type"] +pub struct Future<A> { + /*priv*/ mut state: FutureState<A>, + + // FIXME(#2829) -- futures should not be copyable, because they close + // over fn~'s that have pipes and so forth within! + drop {} +} + +priv enum FutureState<A> { + Pending(fn~() -> A), + Evaluating, + Forced(~A) +} + +/// Methods on the `future` type +impl<A:Copy> Future<A> { + fn get() -> A { + //! Get the value of the future + + get(&self) + } +} + +impl<A> Future<A> { + fn get_ref(&self) -> &self/A { + get_ref(self) + } + + fn with<B>(blk: fn((&A)) -> B) -> B { + //! Work with the value without copying it + + with(&self, blk) + } +} + +pub fn from_value<A>(val: A) -> Future<A> { + /*! + * Create a future from a value + * + * The value is immediately available and calling `get` later will + * not block. + */ + + Future {state: Forced(~(move val))} +} + +pub fn from_port<A:Send>(port: PortOne<A>) -> + Future<A> { + /*! + * Create a future from a port + * + * The first time that the value is requested the task will block + * waiting for the result to be received on the port. + */ + + let port = ~mut Some(move port); + do from_fn |move port| { + let mut port_ = None; + port_ <-> *port; + let port = option::unwrap(move port_); + match recv(move port) { + oneshot::send(move data) => move data + } + } +} + +pub fn from_fn<A>(f: ~fn() -> A) -> Future<A> { + /*! + * Create a future from a function. + * + * The first time that the value is requested it will be retreived by + * calling the function. Note that this function is a local + * function. It is not spawned into another task. + */ + + Future {state: Pending(move f)} +} + +pub fn spawn<A:Send>(blk: fn~() -> A) -> Future<A> { + /*! + * Create a future from a unique closure. + * + * The closure will be run in a new task and its result used as the + * value of the future. + */ + + let (chan, port) = oneshot::init(); + + let chan = ~mut Some(move chan); + do task::spawn |move blk, move chan| { + let chan = option::swap_unwrap(&mut *chan); + send_one(move chan, blk()); + } + + return from_port(move port); +} + +pub fn get_ref<A>(future: &r/Future<A>) -> &r/A { + /*! + * Executes the future's closure and then returns a borrowed + * pointer to the result. The borrowed pointer lasts as long as + * the future. + */ + + // The unsafety here is to hide the aliases from borrowck, which + // would otherwise be concerned that someone might reassign + // `future.state` and cause the value of the future to be freed. + // But *we* know that once `future.state` is `Forced()` it will + // never become "unforced"---so we can safely return a pointer + // into the interior of the Forced() variant which will last as + // long as the future itself. + + match future.state { + Forced(ref v) => { // v here has type &A, but with a shorter lifetime. + return unsafe{ copy_lifetime(future, &**v) }; // ...extend it. + } + Evaluating => { + fail ~"Recursive forcing of future!"; + } + Pending(_) => {} + } + + let mut state = Evaluating; + state <-> future.state; + match move state { + Forced(_) | Evaluating => { + fail ~"Logic error."; + } + Pending(move f) => { + future.state = Forced(~f()); + return get_ref(future); + } + } +} + +pub fn get<A:Copy>(future: &Future<A>) -> A { + //! Get the value of the future + + *get_ref(future) +} + +pub fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B { + //! Work with the value without copying it + + blk(get_ref(future)) +} + +#[allow(non_implicitly_copyable_typarams)] +pub mod test { + #[test] + pub fn test_from_value() { + let f = from_value(~"snail"); + assert get(&f) == ~"snail"; + } + + #[test] + pub fn test_from_port() { + let (ch, po) = oneshot::init(); + send_one(move ch, ~"whale"); + let f = from_port(move po); + assert get(&f) == ~"whale"; + } + + #[test] + pub fn test_from_fn() { + let f = from_fn(|| ~"brail"); + assert get(&f) == ~"brail"; + } + + #[test] + pub fn test_interface_get() { + let f = from_value(~"fail"); + assert f.get() == ~"fail"; + } + + #[test] + pub fn test_with() { + let f = from_value(~"nail"); + assert with(&f, |v| copy *v) == ~"nail"; + } + + #[test] + pub fn test_get_ref_method() { + let f = from_value(22); + assert *f.get_ref() == 22; + } + + #[test] + pub fn test_get_ref_fn() { + let f = from_value(22); + assert *get_ref(&f) == 22; + } + + #[test] + pub fn test_interface_with() { + let f = from_value(~"kale"); + assert f.with(|v| copy *v) == ~"kale"; + } + + #[test] + pub fn test_spawn() { + let f = spawn(|| ~"bale"); + assert get(&f) == ~"bale"; + } + + #[test] + #[should_fail] + #[ignore(cfg(target_os = "win32"))] + pub fn test_futurefail() { + let f = spawn(|| fail); + let _x: ~str = get(&f); + } + + #[test] + pub fn test_sendable_future() { + let expected = ~"schlorf"; + let f = do spawn |copy expected| { copy expected }; + do task::spawn |move f, move expected| { + let actual = get(&f); + assert actual == expected; + } + } +} diff --git a/src/libstd/std.rc b/src/libstd/std.rc index bbffde40948..0c48cd7ce00 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -53,6 +53,7 @@ pub mod cell; pub mod sync; pub mod arc; pub mod comm; +pub mod future; // Collections |
