// 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 or the MIT license // , 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 * # fn fib(n: uint) -> uint {42}; * # fn make_a_sandwich() {}; * let mut delayed_fib = extra::future::spawn (|| fib(5000) ); * make_a_sandwich(); * println!("fib(5000) = {}", delayed_fib.get()) * ``` */ #[allow(missing_doc)]; use std::cell::Cell; use std::comm::{PortOne, oneshot}; use std::task; use std::util::replace; /// A type encapsulating the result of a computation which may not be complete pub struct Future { priv state: FutureState, } enum FutureState { Pending(~fn() -> A), Evaluating, Forced(A) } /// Methods on the `future` type impl Future { pub fn get(&mut self) -> A { //! Get the value of the future. (*(self.get_ref())).clone() } } impl Future { /// Gets the value from this future, forcing evaluation. pub fn unwrap(self) -> A { let mut this = self; this.get_ref(); let state = replace(&mut this.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 borrowed * pointer to the result. The borrowed pointer 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 { /*! * 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: ~fn() -> A) -> Future { /*! * 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 Future { pub fn from_port(port: PortOne) -> Future { /*! * 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 = Cell::new(port); do Future::from_fn { port.take().recv() } } pub fn spawn(blk: ~fn() -> A) -> Future { /*! * 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 (port, chan) = oneshot(); do task::spawn_with(chan) |chan| { chan.send(blk()); } Future::from_port(port) } pub fn spawn_with(v: B, blk: ~fn(B) -> A) -> Future { /*! * Create a future from a unique closure taking one argument. * * The closure and its argument will be moved into a new task. The * closure will be run and its result used as the value of the future. */ let (port, chan) = oneshot(); do task::spawn_with((v, chan)) |(v, chan)| { chan.send(blk(v)); } Future::from_port(port) } } #[cfg(test)] mod test { use future::Future; use std::cell::Cell; use std::comm::oneshot; use std::task; #[test] fn test_from_value() { let mut f = Future::from_value(~"snail"); assert_eq!(f.get(), ~"snail"); } #[test] fn test_from_port() { let (po, ch) = oneshot(); ch.send(~"whale"); let mut f = Future::from_port(po); assert_eq!(f.get(), ~"whale"); } #[test] fn test_from_fn() { let mut f = Future::from_fn(|| ~"brail"); assert_eq!(f.get(), ~"brail"); } #[test] fn test_interface_get() { let mut f = Future::from_value(~"fail"); assert_eq!(f.get(), ~"fail"); } #[test] fn test_interface_unwrap() { let f = Future::from_value(~"fail"); assert_eq!(f.unwrap(), ~"fail"); } #[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(|| ~"bale"); assert_eq!(f.get(), ~"bale"); } #[test] fn test_spawn_with() { let mut f = Future::spawn_with(~"gale", |s| { s }); assert_eq!(f.get(), ~"gale"); } #[test] #[should_fail] fn test_futurefail() { let mut f = Future::spawn(|| fail!()); let _x: ~str = f.get(); } #[test] fn test_sendable_future() { let expected = "schlorf"; let f = Cell::new(do Future::spawn { expected }); do task::spawn { let mut f = f.take(); let actual = f.get(); assert_eq!(actual, expected); } } }