From 2df5a13334449c26204333e8b2cdce2dd0cf90eb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 17 Sep 2013 23:23:20 -0700 Subject: [PATCH 1/4] Removed future's destructor It was only there to prevent Future from being copyable, but it's noncopyable anyways since it contains a ~fn. --- src/libextra/future.rs | 9 --------- src/test/compile-fail/future_not_copyable.rs | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/test/compile-fail/future_not_copyable.rs diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 74a551c6f6d5..55e003de9da7 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -37,15 +37,6 @@ pub struct Future { priv state: FutureState, } -// n.b. It should be possible to get rid of this. -// Add a test, though -- tjc -// FIXME(#2829) -- futures should not be copyable, because they close -// over ~fn's that have pipes and so forth within! -#[unsafe_destructor] -impl Drop for Future { - fn drop(&mut self) {} -} - enum FutureState { Pending(~fn() -> A), Evaluating, diff --git a/src/test/compile-fail/future_not_copyable.rs b/src/test/compile-fail/future_not_copyable.rs new file mode 100644 index 000000000000..7ffa76d4096d --- /dev/null +++ b/src/test/compile-fail/future_not_copyable.rs @@ -0,0 +1,19 @@ +// Copyright 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. + +extern mod extra; + +use extra::future; + +fn main() { + let f = future::from_value(()); + let g = f; + f.unwrap(); //~ ERROR use of moved value +} From ff85389344d6fe4a318559b66b97c24b8fddf1e4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 17 Sep 2013 23:48:56 -0700 Subject: [PATCH 2/4] Modernize extra::future API --- doc/tutorial-tasks.md | 4 +- src/libextra/future.rs | 134 +++++++++---------- src/libextra/par.rs | 4 +- src/librustdoc/markdown_writer.rs | 6 +- src/test/bench/msgsend-ring-mutex-arcs.rs | 4 +- src/test/bench/msgsend-ring-rw-arcs.rs | 4 +- src/test/compile-fail/future_not_copyable.rs | 4 +- 7 files changed, 76 insertions(+), 84 deletions(-) diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index aa63a0112d02..e1f70a19e52e 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -280,7 +280,7 @@ fn fib(n: uint) -> uint { 12586269025 } -let mut delayed_fib = extra::future::spawn (|| fib(50) ); +let mut delayed_fib = extra::future::Future::spawn (|| fib(50) ); make_a_sandwich(); println(fmt!("fib(50) = %?", delayed_fib.get())) ~~~ @@ -304,7 +304,7 @@ fn partial_sum(start: uint) -> f64 { } fn main() { - let mut futures = vec::from_fn(1000, |ind| do extra::future::spawn { partial_sum(ind) }); + let mut futures = vec::from_fn(1000, |ind| do extra::future::Future::spawn { partial_sum(ind) }); let mut final_res = 0f64; for ft in futures.mut_iter() { diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 55e003de9da7..2d68cca4adcd 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -32,7 +32,7 @@ use std::comm::{PortOne, oneshot}; use std::task; use std::util::replace; -#[doc = "The future type"] +/// A type encapsulating the result of a computation which may not be complete pub struct Future { priv state: FutureState, } @@ -62,96 +62,88 @@ impl Future { _ => fail!( "Logic error." ), } } -} -impl Future { 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. */ - unsafe { - { - match self.state { - Forced(ref mut v) => { return cast::transmute(v); } - Evaluating => fail!("Recursive forcing of future!"), - Pending(_) => {} - } - } - { - let state = replace(&mut self.state, Evaluating); - match state { + 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()); - cast::transmute(self.get_ref()) + 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. - */ + 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)} -} + Future {state: Forced(val)} + } -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. - */ + 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. + */ - let port = Cell::new(port); - do from_fn { - port.take().recv() + Future {state: Pending(f)} } } -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. - */ +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. + */ - Future {state: Pending(f)} -} - -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(); - - let chan = Cell::new(chan); - do task::spawn { - let chan = chan.take(); - chan.send(blk()); + let port = Cell::new(port); + do Future::from_fn { + port.take().recv() + } } - return from_port(port); + 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) + } } #[cfg(test)] mod test { - use future::*; + use future::Future; use std::cell::Cell; use std::comm::oneshot; @@ -159,7 +151,7 @@ mod test { #[test] fn test_from_value() { - let mut f = from_value(~"snail"); + let mut f = Future::from_value(~"snail"); assert_eq!(f.get(), ~"snail"); } @@ -167,51 +159,51 @@ mod test { fn test_from_port() { let (po, ch) = oneshot(); ch.send(~"whale"); - let mut f = from_port(po); + let mut f = Future::from_port(po); assert_eq!(f.get(), ~"whale"); } #[test] fn test_from_fn() { - let mut f = from_fn(|| ~"brail"); + let mut f = Future::from_fn(|| ~"brail"); assert_eq!(f.get(), ~"brail"); } #[test] fn test_interface_get() { - let mut f = from_value(~"fail"); + let mut f = Future::from_value(~"fail"); assert_eq!(f.get(), ~"fail"); } #[test] fn test_interface_unwrap() { - let f = from_value(~"fail"); + let f = Future::from_value(~"fail"); assert_eq!(f.unwrap(), ~"fail"); } #[test] fn test_get_ref_method() { - let mut f = from_value(22); + let mut f = Future::from_value(22); assert_eq!(*f.get_ref(), 22); } #[test] fn test_spawn() { - let mut f = spawn(|| ~"bale"); + let mut f = Future::spawn(|| ~"bale"); assert_eq!(f.get(), ~"bale"); } #[test] #[should_fail] fn test_futurefail() { - let mut f = spawn(|| fail!()); + let mut f = Future::spawn(|| fail!()); let _x: ~str = f.get(); } #[test] fn test_sendable_future() { let expected = "schlorf"; - let f = Cell::new(do spawn { expected }); + let f = Cell::new(do Future::spawn { expected }); do task::spawn { let mut f = f.take(); let actual = f.get(); diff --git a/src/libextra/par.rs b/src/libextra/par.rs index 71dddc481ae3..b55143152269 100644 --- a/src/libextra/par.rs +++ b/src/libextra/par.rs @@ -14,7 +14,7 @@ use std::num; use std::ptr; use std::sys; use std::vec; -use future_spawn = future::spawn; +use future::Future; /** * The maximum number of tasks this module will spawn for a single @@ -55,7 +55,7 @@ fn map_slices( do xs.as_imm_buf |p, _len| { let f = f(); let base = base; - let f = do future_spawn() || { + let f = do Future::spawn() || { unsafe { let len = end - base; let slice = (ptr::offset(p, base as int), diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs index a1ea5a68c827..fb58e5c2bf02 100644 --- a/src/librustdoc/markdown_writer.rs +++ b/src/librustdoc/markdown_writer.rs @@ -20,7 +20,7 @@ use std::result; use std::run; use std::str; use std::task; -use extra::future; +use extra::future::Future; #[deriving(Clone)] pub enum WriteInstr { @@ -207,10 +207,10 @@ pub fn future_writer_factory( (writer_factory, markdown_po) } -fn future_writer() -> (Writer, future::Future<~str>) { +fn future_writer() -> (Writer, Future<~str>) { let (port, chan) = comm::stream(); let writer: ~fn(instr: WriteInstr) = |instr| chan.send(instr.clone()); - let future = do future::from_fn || { + let future = do Future::from_fn || { let mut res = ~""; loop { match port.recv() { diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index dd56d550e61c..b52ba154f435 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -18,7 +18,7 @@ extern mod extra; use extra::arc; -use extra::future; +use extra::future::Future; use extra::time; use std::cell::Cell; use std::os; @@ -94,7 +94,7 @@ fn main() { let (new_chan, num_port) = init(); let num_chan2 = Cell::new(num_chan.take()); let num_port = Cell::new(num_port); - let new_future = do future::spawn() { + let new_future = do Future::spawn() { let num_chan = num_chan2.take(); let num_port1 = num_port.take(); thread_ring(i, msg_per_task, num_chan, num_port1) diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs index 130bd4e7d16a..e3d0b4912f97 100644 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ b/src/test/bench/msgsend-ring-rw-arcs.rs @@ -18,7 +18,7 @@ extern mod extra; use extra::arc; -use extra::future; +use extra::future::Future; use extra::time; use std::cell::Cell; use std::os; @@ -90,7 +90,7 @@ fn main() { let (new_chan, num_port) = init(); let num_chan2 = Cell::new(num_chan.take()); let num_port = Cell::new(num_port); - let new_future = do future::spawn { + let new_future = do Future::spawn { let num_chan = num_chan2.take(); let num_port1 = num_port.take(); thread_ring(i, msg_per_task, num_chan, num_port1) diff --git a/src/test/compile-fail/future_not_copyable.rs b/src/test/compile-fail/future_not_copyable.rs index 7ffa76d4096d..aef5d0f9b04a 100644 --- a/src/test/compile-fail/future_not_copyable.rs +++ b/src/test/compile-fail/future_not_copyable.rs @@ -10,10 +10,10 @@ extern mod extra; -use extra::future; +use extra::future::Future; fn main() { - let f = future::from_value(()); + let f = Future::from_value(()); let g = f; f.unwrap(); //~ ERROR use of moved value } From 48d5b4b8e163a4eb4a8290bfed6786b333f49117 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 17 Sep 2013 23:56:02 -0700 Subject: [PATCH 3/4] Add Future::spawn_with --- src/libextra/future.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 2d68cca4adcd..40ed56855f25 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -139,6 +139,23 @@ impl Future { 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)] @@ -193,6 +210,12 @@ mod test { 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() { From 963707f45d935e938adde9e37b56355a915660bd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 18 Sep 2013 00:12:22 -0700 Subject: [PATCH 4/4] Clean up unused imports --- src/libextra/fileinput.rs | 1 - src/libextra/future.rs | 2 -- src/libextra/glob.rs | 4 +--- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs index 25d11d413c06..3ce58b58db6d 100644 --- a/src/libextra/fileinput.rs +++ b/src/libextra/fileinput.rs @@ -420,7 +420,6 @@ mod test { use std::rt::io; use std::rt::io::Writer; use std::rt::io::file; - use std::uint; use std::vec; fn make_file(path : &Path, contents: &[~str]) { diff --git a/src/libextra/future.rs b/src/libextra/future.rs index 40ed56855f25..4e8bc37891dc 100644 --- a/src/libextra/future.rs +++ b/src/libextra/future.rs @@ -25,8 +25,6 @@ #[allow(missing_doc)]; - -use std::cast; use std::cell::Cell; use std::comm::{PortOne, oneshot}; use std::task; diff --git a/src/libextra/glob.rs b/src/libextra/glob.rs index 43a4ecf56168..934943f6fbb4 100644 --- a/src/libextra/glob.rs +++ b/src/libextra/glob.rs @@ -512,10 +512,8 @@ impl MatchOptions { #[cfg(test)] mod test { - use std::{io, os, unstable}; - use std::unstable::finally::Finally; + use std::os; use super::*; - use tempfile; #[test] fn test_absolute_pattern() {