Skip to content

Commit 9bb05fd

Browse files
committed
rollup merge of rust-lang#23939: nikomatsakis/fn-box
Conflicts: src/liballoc/boxed.rs
2 parents e9bacba + 8eed73f commit 9bb05fd

File tree

17 files changed

+124
-85
lines changed

17 files changed

+124
-85
lines changed

src/compiletest/compiletest.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ extern crate log;
3131
use std::env;
3232
use std::fs;
3333
use std::path::{Path, PathBuf};
34-
use std::thunk::Thunk;
3534
use getopts::{optopt, optflag, reqopt};
3635
use common::Config;
3736
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
@@ -351,7 +350,7 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
351350
pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
352351
let config = (*config).clone();
353352
let testfile = testfile.to_path_buf();
354-
test::DynTestFn(Thunk::new(move || {
353+
test::DynTestFn(Box::new(move || {
355354
runtest::run(config, &testfile)
356355
}))
357356
}

src/liballoc/boxed.rs

+71
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,74 @@ impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
300300
#[stable(feature = "rust1", since = "1.0.0")]
301301
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
302302

303+
304+
/// `FnBox` is a version of the `FnOnce` intended for use with boxed
305+
/// closure objects. The idea is that where one would normally store a
306+
/// `Box<FnOnce()>` in a data structure, you should use
307+
/// `Box<FnBox()>`. The two traits behave essentially the same, except
308+
/// that a `FnBox` closure can only be called if it is boxed. (Note
309+
/// that `FnBox` may be deprecated in the future if `Box<FnOnce()>`
310+
/// closures become directly usable.)
311+
///
312+
/// ### Example
313+
///
314+
/// Here is a snippet of code which creates a hashmap full of boxed
315+
/// once closures and then removes them one by one, calling each
316+
/// closure as it is removed. Note that the type of the closures
317+
/// stored in the map is `Box<FnBox() -> i32>` and not `Box<FnOnce()
318+
/// -> i32>`.
319+
///
320+
/// ```
321+
/// #![feature(core)]
322+
///
323+
/// use std::boxed::FnBox;
324+
/// use std::collections::HashMap;
325+
///
326+
/// fn make_map() -> HashMap<i32, Box<FnBox() -> i32>> {
327+
/// let mut map: HashMap<i32, Box<FnBox() -> i32>> = HashMap::new();
328+
/// map.insert(1, Box::new(|| 22));
329+
/// map.insert(2, Box::new(|| 44));
330+
/// map
331+
/// }
332+
///
333+
/// fn main() {
334+
/// let mut map = make_map();
335+
/// for i in &[1, 2] {
336+
/// let f = map.remove(&i).unwrap();
337+
/// assert_eq!(f(), i * 22);
338+
/// }
339+
/// }
340+
/// ```
341+
#[rustc_paren_sugar]
342+
#[unstable(feature = "core", reason = "Newly introduced")]
343+
pub trait FnBox<A> {
344+
type Output;
345+
346+
fn call_box(self: Box<Self>, args: A) -> Self::Output;
347+
}
348+
349+
impl<A,F> FnBox<A> for F
350+
where F: FnOnce<A>
351+
{
352+
type Output = F::Output;
353+
354+
fn call_box(self: Box<F>, args: A) -> F::Output {
355+
self.call_once(args)
356+
}
357+
}
358+
359+
impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+'a> {
360+
type Output = R;
361+
362+
extern "rust-call" fn call_once(self, args: A) -> R {
363+
self.call_box(args)
364+
}
365+
}
366+
367+
impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
368+
type Output = R;
369+
370+
extern "rust-call" fn call_once(self, args: A) -> R {
371+
self.call_box(args)
372+
}
373+
}

src/librustdoc/test.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use std::path::PathBuf;
1919
use std::process::Command;
2020
use std::str;
2121
use std::sync::{Arc, Mutex};
22-
use std::thunk::Thunk;
2322

2423
use testing;
2524
use rustc_lint;
@@ -366,7 +365,7 @@ impl Collector {
366365
ignore: should_ignore,
367366
should_panic: testing::ShouldPanic::No, // compiler failures are test failures
368367
},
369-
testfn: testing::DynTestFn(Thunk::new(move|| {
368+
testfn: testing::DynTestFn(Box::new(move|| {
370369
runtest(&test,
371370
&cratename,
372371
libs,

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ mod uint_macros;
243243
#[path = "num/f64.rs"] pub mod f64;
244244

245245
pub mod ascii;
246+
246247
pub mod thunk;
247248

248249
/* Common traits */

src/libstd/rt/at_exit_imp.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub fn cleanup() {
6464
if queue as usize != 0 {
6565
let queue: Box<Queue> = Box::from_raw(queue);
6666
for to_run in *queue {
67-
to_run.invoke(());
67+
to_run();
6868
}
6969
}
7070
}

src/libstd/rt/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
use prelude::v1::*;
2323
use sys;
24-
use thunk::Thunk;
2524
use usize;
2625

2726
// 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 {
153152
/// that the closure could not be registered, meaning that it is not scheduled
154153
/// to be rune.
155154
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
156-
if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())}
155+
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
157156
}
158157

159158
/// One-time runtime cleanup.

src/libstd/sync/future.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use core::prelude::*;
3737
use core::mem::replace;
3838

39+
use boxed::Box;
3940
use self::FutureState::*;
4041
use sync::mpsc::{Receiver, channel};
4142
use thunk::Thunk;
@@ -84,7 +85,7 @@ impl<A> Future<A> {
8485
match replace(&mut self.state, Evaluating) {
8586
Forced(_) | Evaluating => panic!("Logic error."),
8687
Pending(f) => {
87-
self.state = Forced(f.invoke(()));
88+
self.state = Forced(f());
8889
self.get_ref()
8990
}
9091
}
@@ -114,7 +115,7 @@ impl<A> Future<A> {
114115
* function. It is not spawned into another task.
115116
*/
116117

117-
Future {state: Pending(Thunk::new(f))}
118+
Future {state: Pending(Box::new(f))}
118119
}
119120
}
120121

src/libstd/sys/common/thread.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub fn start_thread(main: *mut libc::c_void) {
2525
unsafe {
2626
stack::record_os_managed_stack_bounds(0, usize::MAX);
2727
let _handler = stack_overflow::Handler::new();
28-
Box::from_raw(main as *mut Thunk).invoke(());
28+
let main: Box<Thunk> = Box::from_raw(main as *mut Thunk);
29+
main();
2930
}
3031
}

src/libstd/thread/mod.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ impl Builder {
257257
pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
258258
F: FnOnce(), F: Send + 'static
259259
{
260-
self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i))
260+
self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i))
261261
}
262262

263263
/// Spawn a new child thread that must be joined within a given
@@ -279,7 +279,7 @@ impl Builder {
279279
pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
280280
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
281281
{
282-
self.spawn_inner(Thunk::new(f)).map(|inner| {
282+
self.spawn_inner(Box::new(f)).map(|inner| {
283283
JoinGuard { inner: inner, _marker: PhantomData }
284284
})
285285
}
@@ -315,7 +315,7 @@ impl Builder {
315315
thread_info::set(imp::guard::current(), their_thread);
316316
}
317317

318-
let mut output = None;
318+
let mut output: Option<T> = None;
319319
let try_result = {
320320
let ptr = &mut output;
321321

@@ -327,7 +327,11 @@ impl Builder {
327327
// 'unwinding' flag in the thread itself. For these reasons,
328328
// this unsafety should be ok.
329329
unsafe {
330-
unwind::try(move || *ptr = Some(f.invoke(())))
330+
unwind::try(move || {
331+
let f: Thunk<(), T> = f;
332+
let v: T = f();
333+
*ptr = Some(v)
334+
})
331335
}
332336
};
333337
unsafe {
@@ -340,7 +344,7 @@ impl Builder {
340344
};
341345

342346
Ok(JoinInner {
343-
native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }),
347+
native: try!(unsafe { imp::create(stack_size, Box::new(main)) }),
344348
thread: my_thread,
345349
packet: my_packet,
346350
joined: false,
@@ -820,7 +824,7 @@ mod test {
820824
let x: Box<_> = box 1;
821825
let x_in_parent = (&*x) as *const i32 as usize;
822826

823-
spawnfn(Thunk::new(move|| {
827+
spawnfn(Box::new(move|| {
824828
let x_in_child = (&*x) as *const i32 as usize;
825829
tx.send(x_in_child).unwrap();
826830
}));
@@ -832,15 +836,15 @@ mod test {
832836
#[test]
833837
fn test_avoid_copying_the_body_spawn() {
834838
avoid_copying_the_body(|v| {
835-
thread::spawn(move || v.invoke(()));
839+
thread::spawn(move || v());
836840
});
837841
}
838842

839843
#[test]
840844
fn test_avoid_copying_the_body_thread_spawn() {
841845
avoid_copying_the_body(|f| {
842846
thread::spawn(move|| {
843-
f.invoke(());
847+
f();
844848
});
845849
})
846850
}
@@ -849,7 +853,7 @@ mod test {
849853
fn test_avoid_copying_the_body_join() {
850854
avoid_copying_the_body(|f| {
851855
let _ = thread::spawn(move|| {
852-
f.invoke(())
856+
f()
853857
}).join();
854858
})
855859
}
@@ -862,13 +866,13 @@ mod test {
862866
// valgrind-friendly. try this at home, instead..!)
863867
const GENERATIONS: u32 = 16;
864868
fn child_no(x: u32) -> Thunk<'static> {
865-
return Thunk::new(move|| {
869+
return Box::new(move|| {
866870
if x < GENERATIONS {
867-
thread::spawn(move|| child_no(x+1).invoke(()));
871+
thread::spawn(move|| child_no(x+1)());
868872
}
869873
});
870874
}
871-
thread::spawn(|| child_no(0).invoke(()));
875+
thread::spawn(|| child_no(0)());
872876
}
873877

874878
#[test]

src/libstd/thunk.rs

+3-39
Original file line numberDiff line numberDiff line change
@@ -12,45 +12,9 @@
1212
#![allow(missing_docs)]
1313
#![unstable(feature = "std_misc")]
1414

15-
use alloc::boxed::Box;
15+
use alloc::boxed::{Box, FnBox};
1616
use core::marker::Send;
17-
use core::ops::FnOnce;
1817

19-
pub struct Thunk<'a, A=(),R=()> {
20-
invoke: Box<Invoke<A,R>+Send + 'a>,
21-
}
18+
pub type Thunk<'a, A=(), R=()> =
19+
Box<FnBox<A,Output=R> + Send + 'a>;
2220

23-
impl<'a, R> Thunk<'a,(),R> {
24-
pub fn new<F>(func: F) -> Thunk<'a,(),R>
25-
where F : FnOnce() -> R, F : Send + 'a
26-
{
27-
Thunk::with_arg(move|()| func())
28-
}
29-
}
30-
31-
impl<'a,A,R> Thunk<'a,A,R> {
32-
pub fn with_arg<F>(func: F) -> Thunk<'a,A,R>
33-
where F : FnOnce(A) -> R, F : Send + 'a
34-
{
35-
Thunk {
36-
invoke: Box::<F>::new(func)
37-
}
38-
}
39-
40-
pub fn invoke(self, arg: A) -> R {
41-
self.invoke.invoke(arg)
42-
}
43-
}
44-
45-
pub trait Invoke<A=(),R=()> {
46-
fn invoke(self: Box<Self>, arg: A) -> R;
47-
}
48-
49-
impl<A,R,F> Invoke<A,R> for F
50-
where F : FnOnce(A) -> R
51-
{
52-
fn invoke(self: Box<F>, arg: A) -> R {
53-
let f = *self;
54-
f(arg)
55-
}
56-
}

0 commit comments

Comments
 (0)