diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-06-07 11:13:26 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-06-11 10:00:43 -0700 |
| commit | b1c9ce9c6f0eb7d4a7df1aad6b6799f4b548181c (patch) | |
| tree | 219196013c141f0f2110ac1df21db05433a71e4b /src/libstd/sync/future.rs | |
| parent | c690191a84728c289a4b3dc17b07934a66311d9d (diff) | |
sync: Move underneath libstd
This commit is the final step in the libstd facade, #13851. The purpose of this commit is to move libsync underneath the standard library, behind the facade. This will allow core primitives like channels, queues, and atomics to all live in the same location. There were a few notable changes and a few breaking changes as part of this movement: * The `Vec` and `String` types are reexported at the top level of libcollections * The `unreachable!()` macro was copied to libcore * The `std::rt::thread` module was moved to librustrt, but it is still reexported at the same location. * The `std::comm` module was moved to libsync * The `sync::comm` module was moved under `sync::comm`, and renamed to `duplex`. It is now a private module with types/functions being reexported under `sync::comm`. This is a breaking change for any existing users of duplex streams. * All concurrent queues/deques were moved directly under libsync. They are also all marked with #![experimental] for now if they are public. * The `task_pool` and `future` modules no longer live in libsync, but rather live under `std::sync`. They will forever live at this location, but they may move to libsync if the `std::task` module moves as well. [breaking-change]
Diffstat (limited to 'src/libstd/sync/future.rs')
| -rw-r--r-- | src/libstd/sync/future.rs | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs new file mode 100644 index 00000000000..bc748324fcd --- /dev/null +++ b/src/libstd/sync/future.rs @@ -0,0 +1,209 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * A type representing values that may be computed concurrently and + * operations for working with them. + * + * # Example + * + * ```rust + * use std::sync::Future; + * # fn fib(n: uint) -> uint {42}; + * # fn make_a_sandwich() {}; + * let mut delayed_fib = Future::spawn(proc() { fib(5000) }); + * make_a_sandwich(); + * println!("fib(5000) = {}", delayed_fib.get()) + * ``` + */ + +#![allow(missing_doc)] + +use core::prelude::*; +use core::mem::replace; + +use comm::{Receiver, channel}; +use task::spawn; + +/// A type encapsulating the result of a computation which may not be complete +pub struct Future<A> { + state: FutureState<A>, +} + +enum FutureState<A> { + Pending(proc():Send -> A), + Evaluating, + Forced(A) +} + +/// Methods on the `future` type +impl<A:Clone> Future<A> { + pub fn get(&mut self) -> A { + //! Get the value of the future. + (*(self.get_ref())).clone() + } +} + +impl<A> Future<A> { + /// Gets the value from this future, forcing evaluation. + pub fn unwrap(mut self) -> A { + self.get_ref(); + let state = replace(&mut self.state, Evaluating); + match state { + Forced(v) => v, + _ => fail!( "Logic error." ), + } + } + + pub fn get_ref<'a>(&'a mut self) -> &'a A { + /*! + * Executes the future's closure and then returns a reference + * to the result. The reference lasts as long as + * the future. + */ + match self.state { + Forced(ref v) => return v, + Evaluating => fail!("Recursive forcing of future!"), + Pending(_) => { + match replace(&mut self.state, Evaluating) { + Forced(_) | Evaluating => fail!("Logic error."), + Pending(f) => { + self.state = Forced(f()); + self.get_ref() + } + } + } + } + } + + pub fn from_value(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(val)} + } + + pub fn from_fn(f: proc():Send -> A) -> Future<A> { + /*! + * Create a future from a function. + * + * The first time that the value is requested it will be retrieved by + * calling the function. Note that this function is a local + * function. It is not spawned into another task. + */ + + Future {state: Pending(f)} + } +} + +impl<A:Send> Future<A> { + pub fn from_receiver(rx: Receiver<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. + */ + + Future::from_fn(proc() { + rx.recv() + }) + } + + pub fn spawn(blk: proc():Send -> 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 (tx, rx) = channel(); + + spawn(proc() { + tx.send(blk()); + }); + + Future::from_receiver(rx) + } +} + +#[cfg(test)] +mod test { + use prelude::*; + use sync::Future; + use task; + + #[test] + fn test_from_value() { + let mut f = Future::from_value("snail".to_string()); + assert_eq!(f.get(), "snail".to_string()); + } + + #[test] + fn test_from_receiver() { + let (tx, rx) = channel(); + tx.send("whale".to_string()); + let mut f = Future::from_receiver(rx); + assert_eq!(f.get(), "whale".to_string()); + } + + #[test] + fn test_from_fn() { + let mut f = Future::from_fn(proc() "brail".to_string()); + assert_eq!(f.get(), "brail".to_string()); + } + + #[test] + fn test_interface_get() { + let mut f = Future::from_value("fail".to_string()); + assert_eq!(f.get(), "fail".to_string()); + } + + #[test] + fn test_interface_unwrap() { + let f = Future::from_value("fail".to_string()); + assert_eq!(f.unwrap(), "fail".to_string()); + } + + #[test] + fn test_get_ref_method() { + let mut f = Future::from_value(22); + assert_eq!(*f.get_ref(), 22); + } + + #[test] + fn test_spawn() { + let mut f = Future::spawn(proc() "bale".to_string()); + assert_eq!(f.get(), "bale".to_string()); + } + + #[test] + #[should_fail] + fn test_futurefail() { + let mut f = Future::spawn(proc() fail!()); + let _x: String = f.get(); + } + + #[test] + fn test_sendable_future() { + let expected = "schlorf"; + let f = Future::spawn(proc() { expected }); + task::spawn(proc() { + let mut f = f; + let actual = f.get(); + assert_eq!(actual, expected); + }); + } +} |
