From ff6b71f78bd00a93a91691bb297d6a379cdc50fa Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 14 Feb 2012 16:39:20 -0800 Subject: [PATCH] core: Add core::future Futures will be required for upcoming changes to the task API --- src/libcore/core.rc | 5 +- src/libcore/future.rs | 153 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/libcore/future.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 181e54a95a4c0..868762a090f06 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -80,9 +80,12 @@ mod math; mod cmath; mod sys; mod unsafe; +mod logging; + +// Concurrency mod comm; mod task; -mod logging; +mod future; // Compiler support modules diff --git a/src/libcore/future.rs b/src/libcore/future.rs new file mode 100644 index 0000000000000..ae90b9035188c --- /dev/null +++ b/src/libcore/future.rs @@ -0,0 +1,153 @@ +#[doc = " + +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_sandwitch(); +> io::println(#fmt(\"fib(5000) = %?\", delayed_fib.get())) + +"]; + +export future; +export future::{}; +export from_value; +export from_port; +export get; +export with; +export spawn; + +import either = either::t; + +#[doc = "The future type"] +enum future = { + mutable v: either<@A, comm::port> +}; + +#[doc = "Methods on the `future` type"] +impl future for future { + + fn get() -> A { + #[doc = "Get the value of the future"]; + + get(self) + } + + fn with(blk: fn(A) -> B) -> B { + #[doc = "Work with the value without copying it"]; + + with(self, blk) + } +} + +fn from_value(+val: A) -> future { + #[doc = " + + Create a future from a value. The value is immediately available + and calling `get` later will not block. + + "]; + + future({ + mutable v: either::left(@val) + }) +} + +fn from_port(-port: comm::port) -> future { + #[doc = " + + 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({ + mutable v: either::right(port) + }) +} + +fn get(future: future) -> A { + #[doc = "Get the value of the future"]; + + with(future) {|v| v } +} + +fn with(future: future, blk: fn(A) -> B) -> B { + #[doc = "Work with the value without copying it"]; + + let v = alt future.v { + either::left(v) { v } + either::right(po) { + let v = @comm::recv(po); + future.v = either::left(v); + v + } + }; + blk(*v) +} + +fn spawn(+blk: fn~() -> A) -> future { + #[doc = " + + 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 po = comm::port(); + let ch = comm::chan(po); + task::spawn {|| + comm::send(ch, blk()) + }; + from_port(po) +} + +#[test] +fn test_from_value() { + let f = from_value("snail"); + assert get(f) == "snail"; +} + +#[test] +fn test_from_port() { + let po = comm::port(); + let ch = comm::chan(po); + comm::send(ch, "whale"); + let f = from_port(po); + assert get(f) == "whale"; +} + +#[test] +fn test_iface_get() { + let f = from_value("fail"); + assert f.get() == "fail"; +} + +#[test] +fn test_with() { + let f = from_value("nail"); + assert with(f) {|v| v} == "nail"; +} + +#[test] +fn test_iface_with() { + let f = from_value("kale"); + assert f.with {|v| v} == "kale"; +} + +#[test] +fn test_spawn() { + let f = spawn {|| "bale" }; + assert get(f) == "bale"; +} + +#[test] +#[should_fail] +#[ignore(cfg(target_os = "win32"))] +fn test_futurefail() { + let f = spawn {|| fail }; + let _x: str = get(f); +} \ No newline at end of file