]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #23939: nikomatsakis/fn-box
authorAlex Crichton <alex@alexcrichton.com>
Wed, 1 Apr 2015 20:30:51 +0000 (13:30 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 1 Apr 2015 20:30:51 +0000 (13:30 -0700)
Conflicts:
src/liballoc/boxed.rs

17 files changed:
src/compiletest/compiletest.rs
src/liballoc/boxed.rs
src/librustdoc/test.rs
src/libstd/lib.rs
src/libstd/rt/at_exit_imp.rs
src/libstd/rt/mod.rs
src/libstd/sync/future.rs
src/libstd/sys/common/thread.rs
src/libstd/thread/mod.rs
src/libstd/thunk.rs
src/libtest/lib.rs
src/test/run-pass/issue-11709.rs
src/test/run-pass/issue-11958.rs
src/test/run-pass/issue-17897.rs
src/test/run-pass/issue-18188.rs
src/test/run-pass/issue-2190-1.rs
src/test/run-pass/issue-3609.rs

index 7fd09f9e1f5b0b9e0310b26d9efd76c346efc457..f00ff9bcbe5e5c4bec3ad7fbbd4336a72f1a2c55 100644 (file)
@@ -31,7 +31,6 @@
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::thunk::Thunk;
 use getopts::{optopt, optflag, reqopt};
 use common::Config;
 use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
@@ -351,7 +350,7 @@ fn shorten(path: &Path) -> String {
 pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
     let config = (*config).clone();
     let testfile = testfile.to_path_buf();
-    test::DynTestFn(Thunk::new(move || {
+    test::DynTestFn(Box::new(move || {
         runtest::run(config, &testfile)
     }))
 }
index bbf5d7a6042f2e4540899310d07933a273572d21..2801cf38cb75529d94912551a60a5eab51597235 100644 (file)
@@ -300,3 +300,74 @@ fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
 
+
+/// `FnBox` is a version of the `FnOnce` intended for use with boxed
+/// closure objects. The idea is that where one would normally store a
+/// `Box<FnOnce()>` in a data structure, you should use
+/// `Box<FnBox()>`. The two traits behave essentially the same, except
+/// that a `FnBox` closure can only be called if it is boxed. (Note
+/// that `FnBox` may be deprecated in the future if `Box<FnOnce()>`
+/// closures become directly usable.)
+///
+/// ### Example
+///
+/// Here is a snippet of code which creates a hashmap full of boxed
+/// once closures and then removes them one by one, calling each
+/// closure as it is removed. Note that the type of the closures
+/// stored in the map is `Box<FnBox() -> i32>` and not `Box<FnOnce()
+/// -> i32>`.
+///
+/// ```
+/// #![feature(core)]
+///
+/// use std::boxed::FnBox;
+/// use std::collections::HashMap;
+///
+/// fn make_map() -> HashMap<i32, Box<FnBox() -> i32>> {
+///     let mut map: HashMap<i32, Box<FnBox() -> i32>> = HashMap::new();
+///     map.insert(1, Box::new(|| 22));
+///     map.insert(2, Box::new(|| 44));
+///     map
+/// }
+///
+/// fn main() {
+///     let mut map = make_map();
+///     for i in &[1, 2] {
+///         let f = map.remove(&i).unwrap();
+///         assert_eq!(f(), i * 22);
+///     }
+/// }
+/// ```
+#[rustc_paren_sugar]
+#[unstable(feature = "core", reason = "Newly introduced")]
+pub trait FnBox<A> {
+    type Output;
+
+    fn call_box(self: Box<Self>, args: A) -> Self::Output;
+}
+
+impl<A,F> FnBox<A> for F
+    where F: FnOnce<A>
+{
+    type Output = F::Output;
+
+    fn call_box(self: Box<F>, args: A) -> F::Output {
+        self.call_once(args)
+    }
+}
+
+impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+'a> {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, args: A) -> R {
+        self.call_box(args)
+    }
+}
+
+impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, args: A) -> R {
+        self.call_box(args)
+    }
+}
index babbe15b17df51ad1beeaa06f6540f6c2c951e74..f5bee6240d46c80dc5ee321742b500cb958ec3c0 100644 (file)
@@ -19,7 +19,6 @@
 use std::process::Command;
 use std::str;
 use std::sync::{Arc, Mutex};
-use std::thunk::Thunk;
 
 use testing;
 use rustc_lint;
@@ -366,7 +365,7 @@ pub fn add_test(&mut self, test: String,
                 ignore: should_ignore,
                 should_panic: testing::ShouldPanic::No, // compiler failures are test failures
             },
-            testfn: testing::DynTestFn(Thunk::new(move|| {
+            testfn: testing::DynTestFn(Box::new(move|| {
                 runtest(&test,
                         &cratename,
                         libs,
index 807f0c5753e6b59e600ff06d0c4d2fa3f7fa5e2e..5c9ff544fa3e8f3380b0876f87bf8e6495a4ef5e 100644 (file)
 #[path = "num/f64.rs"]   pub mod f64;
 
 pub mod ascii;
+
 pub mod thunk;
 
 /* Common traits */
index 9079c0aaffb7d3669e6bd57ecce4dde8d7b8c6c2..beb2870807a7e1aab75edf77b704879eb78e50ca 100644 (file)
@@ -64,7 +64,7 @@ pub fn cleanup() {
             if queue as usize != 0 {
                 let queue: Box<Queue> = Box::from_raw(queue);
                 for to_run in *queue {
-                    to_run.invoke(());
+                    to_run();
                 }
             }
         }
index 696c7960c3e6f4e11b71aa268c932c47ceabf6c2..632d964721239661442c9bb1cba5b78d66bd8360 100644 (file)
@@ -21,7 +21,6 @@
 
 use prelude::v1::*;
 use sys;
-use thunk::Thunk;
 use usize;
 
 // Reexport some of our utilities which are expected by other crates.
@@ -153,7 +152,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
 /// that the closure could not be registered, meaning that it is not scheduled
 /// to be rune.
 pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
-    if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())}
+    if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
 }
 
 /// One-time runtime cleanup.
index b2afe28fed46d5d30352caedbf7a00611490d365..2cdde1aca9e682c7696d67ffad62c8f45adaa043 100644 (file)
@@ -36,6 +36,7 @@
 use core::prelude::*;
 use core::mem::replace;
 
+use boxed::Box;
 use self::FutureState::*;
 use sync::mpsc::{Receiver, channel};
 use thunk::Thunk;
@@ -84,7 +85,7 @@ pub fn get_ref<'a>(&'a mut self) -> &'a A {
                 match replace(&mut self.state, Evaluating) {
                     Forced(_) | Evaluating => panic!("Logic error."),
                     Pending(f) => {
-                        self.state = Forced(f.invoke(()));
+                        self.state = Forced(f());
                         self.get_ref()
                     }
                 }
@@ -114,7 +115,7 @@ pub fn from_fn<F>(f: F) -> Future<A>
          * function. It is not spawned into another task.
          */
 
-        Future {state: Pending(Thunk::new(f))}
+        Future {state: Pending(Box::new(f))}
     }
 }
 
index f45daea18a21f3f2bc65e763f6cb6fdf648c54d2..1845b6266ed8d1aa405ad7581278205ef5a30546 100644 (file)
@@ -25,6 +25,7 @@ pub fn start_thread(main: *mut libc::c_void) {
     unsafe {
         stack::record_os_managed_stack_bounds(0, usize::MAX);
         let _handler = stack_overflow::Handler::new();
-        Box::from_raw(main as *mut Thunk).invoke(());
+        let main: Box<Thunk> = Box::from_raw(main as *mut Thunk);
+        main();
     }
 }
index 1202b353317cdb4c28cd7ac2cb6b0f7900c65d5d..9ab35382845b9172bad37a4999fc36a9d05655a5 100644 (file)
@@ -257,7 +257,7 @@ pub fn stack_size(mut self, size: usize) -> Builder {
     pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
         F: FnOnce(), F: Send + 'static
     {
-        self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i))
+        self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i))
     }
 
     /// Spawn a new child thread that must be joined within a given
@@ -279,7 +279,7 @@ pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
     pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
         T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
     {
-        self.spawn_inner(Thunk::new(f)).map(|inner| {
+        self.spawn_inner(Box::new(f)).map(|inner| {
             JoinGuard { inner: inner, _marker: PhantomData }
         })
     }
@@ -315,7 +315,7 @@ fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
                 thread_info::set(imp::guard::current(), their_thread);
             }
 
-            let mut output = None;
+            let mut output: Option<T> = None;
             let try_result = {
                 let ptr = &mut output;
 
@@ -327,7 +327,11 @@ fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
                 // 'unwinding' flag in the thread itself. For these reasons,
                 // this unsafety should be ok.
                 unsafe {
-                    unwind::try(move || *ptr = Some(f.invoke(())))
+                    unwind::try(move || {
+                        let f: Thunk<(), T> = f;
+                        let v: T = f();
+                        *ptr = Some(v)
+                    })
                 }
             };
             unsafe {
@@ -340,7 +344,7 @@ fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
         };
 
         Ok(JoinInner {
-            native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }),
+            native: try!(unsafe { imp::create(stack_size, Box::new(main)) }),
             thread: my_thread,
             packet: my_packet,
             joined: false,
@@ -820,7 +824,7 @@ fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Thunk<'static>) {
         let x: Box<_> = box 1;
         let x_in_parent = (&*x) as *const i32 as usize;
 
-        spawnfn(Thunk::new(move|| {
+        spawnfn(Box::new(move|| {
             let x_in_child = (&*x) as *const i32 as usize;
             tx.send(x_in_child).unwrap();
         }));
@@ -832,7 +836,7 @@ fn avoid_copying_the_body<F>(spawnfn: F) where F: FnOnce(Thunk<'static>) {
     #[test]
     fn test_avoid_copying_the_body_spawn() {
         avoid_copying_the_body(|v| {
-            thread::spawn(move || v.invoke(()));
+            thread::spawn(move || v());
         });
     }
 
@@ -840,7 +844,7 @@ fn test_avoid_copying_the_body_spawn() {
     fn test_avoid_copying_the_body_thread_spawn() {
         avoid_copying_the_body(|f| {
             thread::spawn(move|| {
-                f.invoke(());
+                f();
             });
         })
     }
@@ -849,7 +853,7 @@ fn test_avoid_copying_the_body_thread_spawn() {
     fn test_avoid_copying_the_body_join() {
         avoid_copying_the_body(|f| {
             let _ = thread::spawn(move|| {
-                f.invoke(())
+                f()
             }).join();
         })
     }
@@ -862,13 +866,13 @@ fn test_child_doesnt_ref_parent() {
         // valgrind-friendly. try this at home, instead..!)
         const GENERATIONS: u32 = 16;
         fn child_no(x: u32) -> Thunk<'static> {
-            return Thunk::new(move|| {
+            return Box::new(move|| {
                 if x < GENERATIONS {
-                    thread::spawn(move|| child_no(x+1).invoke(()));
+                    thread::spawn(move|| child_no(x+1)());
                 }
             });
         }
-        thread::spawn(|| child_no(0).invoke(()));
+        thread::spawn(|| child_no(0)());
     }
 
     #[test]
index a9cb05b368f02a200acd64526b82dee685153639..6091794ed428660162d848512845e186a1b075a9 100644 (file)
 #![allow(missing_docs)]
 #![unstable(feature = "std_misc")]
 
-use alloc::boxed::Box;
+use alloc::boxed::{Box, FnBox};
 use core::marker::Send;
-use core::ops::FnOnce;
 
-pub struct Thunk<'a, A=(),R=()> {
-    invoke: Box<Invoke<A,R>+Send + 'a>,
-}
+pub type Thunk<'a, A=(), R=()> =
+    Box<FnBox<A,Output=R> + Send + 'a>;
 
-impl<'a, R> Thunk<'a,(),R> {
-    pub fn new<F>(func: F) -> Thunk<'a,(),R>
-        where F : FnOnce() -> R, F : Send + 'a
-    {
-        Thunk::with_arg(move|()| func())
-    }
-}
-
-impl<'a,A,R> Thunk<'a,A,R> {
-    pub fn with_arg<F>(func: F) -> Thunk<'a,A,R>
-        where F : FnOnce(A) -> R, F : Send + 'a
-    {
-        Thunk {
-            invoke: Box::<F>::new(func)
-        }
-    }
-
-    pub fn invoke(self, arg: A) -> R {
-        self.invoke.invoke(arg)
-    }
-}
-
-pub trait Invoke<A=(),R=()> {
-    fn invoke(self: Box<Self>, arg: A) -> R;
-}
-
-impl<A,R,F> Invoke<A,R> for F
-    where F : FnOnce(A) -> R
-{
-    fn invoke(self: Box<F>, arg: A) -> R {
-        let f = *self;
-        f(arg)
-    }
-}
index f7e5c9f1deedc1ef21634c3a5adbb47540ad8d44..00117775eee38cba26a42819eb05960cda19c2b2 100644 (file)
@@ -62,6 +62,7 @@
 use stats::Stats;
 use getopts::{OptGroup, optflag, optopt};
 use serialize::Encodable;
+use std::boxed::FnBox;
 use term::Terminal;
 use term::color::{Color, RED, YELLOW, GREEN, CYAN};
 
@@ -79,7 +80,7 @@
 use std::sync::mpsc::{channel, Sender};
 use std::sync::{Arc, Mutex};
 use std::thread;
-use std::thunk::{Thunk, Invoke};
+use std::thunk::Thunk;
 use std::time::Duration;
 
 // to be used by rustc to compile tests in libtest
@@ -158,7 +159,7 @@ pub enum TestFn {
     StaticBenchFn(fn(&mut Bencher)),
     StaticMetricFn(fn(&mut MetricMap)),
     DynTestFn(Thunk<'static>),
-    DynMetricFn(Box<for<'a> Invoke<&'a mut MetricMap>+'static>),
+    DynMetricFn(Box<FnBox(&mut MetricMap)+Send>),
     DynBenchFn(Box<TDynBenchFn+'static>)
 }
 
@@ -936,7 +937,7 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
                     io::set_print(box Sink(data2.clone()));
                     io::set_panic(box Sink(data2));
                 }
-                testfn.invoke(())
+                testfn()
             }).unwrap();
             let test_result = calc_result(&desc, result_guard.join());
             let stdout = data.lock().unwrap().to_vec();
@@ -957,7 +958,7 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
         }
         DynMetricFn(f) => {
             let mut mm = MetricMap::new();
-            f.invoke(&mut mm);
+            f.call_box((&mut mm,));
             monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap();
             return;
         }
@@ -969,7 +970,7 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) }
         }
         DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f),
         StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture,
-                                          Thunk::new(move|| f()))
+                                          Box::new(move|| f()))
     }
 }
 
@@ -1185,7 +1186,7 @@ pub fn do_not_run_ignored_tests() {
                 ignore: true,
                 should_panic: ShouldPanic::No,
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1202,7 +1203,7 @@ fn f() { }
                 ignore: true,
                 should_panic: ShouldPanic::No,
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1219,7 +1220,7 @@ fn test_should_panic() {
                 ignore: false,
                 should_panic: ShouldPanic::Yes(None)
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1236,7 +1237,7 @@ fn test_should_panic_good_message() {
                 ignore: false,
                 should_panic: ShouldPanic::Yes(Some("error message"))
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1253,7 +1254,7 @@ fn test_should_panic_bad_message() {
                 ignore: false,
                 should_panic: ShouldPanic::Yes(Some("foobar"))
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1270,7 +1271,7 @@ fn f() { }
                 ignore: false,
                 should_panic: ShouldPanic::Yes(None)
             },
-            testfn: DynTestFn(Thunk::new(move|| f())),
+            testfn: DynTestFn(Box::new(move|| f())),
         };
         let (tx, rx) = channel();
         run_test(&TestOpts::new(), false, desc, tx);
@@ -1306,7 +1307,7 @@ pub fn filter_for_ignored_option() {
                     ignore: true,
                     should_panic: ShouldPanic::No,
                 },
-                testfn: DynTestFn(Thunk::new(move|| {})),
+                testfn: DynTestFn(Box::new(move|| {})),
             },
             TestDescAndFn {
                 desc: TestDesc {
@@ -1314,7 +1315,7 @@ pub fn filter_for_ignored_option() {
                     ignore: false,
                     should_panic: ShouldPanic::No,
                 },
-                testfn: DynTestFn(Thunk::new(move|| {})),
+                testfn: DynTestFn(Box::new(move|| {})),
             });
         let filtered = filter_tests(&opts, tests);
 
@@ -1350,7 +1351,7 @@ fn testfn() { }
                         ignore: false,
                         should_panic: ShouldPanic::No,
                     },
-                    testfn: DynTestFn(Thunk::new(testfn)),
+                    testfn: DynTestFn(Box::new(testfn)),
                 };
                 tests.push(test);
             }
index da3efb4fea8cac85ca6c1d5557ba8810547586a5..3ad78f088f9c9f5fe26e92187f40e0cee21218d7 100644 (file)
@@ -25,7 +25,7 @@ fn test(slot: &mut Option<Thunk<(),Thunk>>) -> () {
   let a = slot.take();
   let _a = match a {
     // `{let .. a(); }` would break
-    Some(a) => { let _a = a.invoke(()); },
+    Some(a) => { let _a = a(); },
     None => (),
   };
 }
index ed2009dab1bafe73dc01579b4420ed77a2245017..def85b4766783ff499e58efd9a8859a995968c03 100644 (file)
@@ -23,5 +23,5 @@
 
 pub fn main() {
     let mut x = 1;
-    let _thunk = Thunk::new(move|| { x = 2; });
+    let _thunk = Box::new(move|| { x = 2; });
 }
index 3fbdb92e906172564053987806902bcbcf860dca..cf8c54fdd808667afc3262f7791369e8746e8ec6 100644 (file)
 
 use std::thunk::Thunk;
 
-fn action(cb: Thunk<usize, usize>) -> usize {
-    cb.invoke(1)
+fn action(cb: Thunk<(usize,), usize>) -> usize {
+    cb(1)
 }
 
 pub fn main() {
-    println!("num: {}", action(Thunk::with_arg(move |u| u)));
+    println!("num: {}", action(Box::new(move |u| u)));
 }
index cd28d6425516dbe61fd2d95f32bb78a401884341..059d25173c2ad75e57f88fa3f2b979a13092eeb2 100644 (file)
 
 pub trait Promisable: Send + Sync {}
 impl<T: Send + Sync> Promisable for T {}
-pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a,Result<T, E>, Result<T, E>>
+pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a, (Result<T, E>,), Result<T, E>>
     where
         T: Promisable + Clone + 'a,
         E: Promisable + Clone + 'a,
         F: FnOnce(&T) -> Result<T, E> + Send + 'a,
         G: FnOnce(Result<T, E>) -> Result<T, E> + 'a {
-    Thunk::with_arg(move |result: Result<T, E>| {
+    Box::new(move |result: Result<T, E>| {
         match result {
             Ok(ref t) => action(t),
             Err(ref e) => Err(e.clone()),
index b2c21a274cb83c07a6ea7a7bcae92b940dc4968e..5c84c30aa7fa3631a7fc277f4697f3cb8def9f1e 100644 (file)
 static generations: usize = 1024+256+128+49;
 
 fn spawn(f: Thunk<'static>) {
-    Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(()));
+    Builder::new().stack_size(32 * 1024).spawn(move|| f());
 }
 
 fn child_no(x: usize) -> Thunk<'static> {
-    Thunk::new(move|| {
+    Box::new(move|| {
         if x < generations {
             spawn(child_no(x+1));
         }
index 45eb21374e2981aab7a5b84bdfc5e93f966587f0..2167a3df9766ffd471abad9e07e154448ae16308 100644 (file)
@@ -13,7 +13,6 @@
 
 use std::thread;
 use std::sync::mpsc::Sender;
-use std::thunk::Invoke;
 
 type RingBuffer = Vec<f64> ;
 type SamplesFn = Box<FnMut(&RingBuffer) + Send>;