rollup merge of #23939: nikomatsakis/fn-box
Conflicts: src/liballoc/boxed.rs
This commit is contained in:
commit
9bb05fd414
@ -31,7 +31,6 @@ extern crate log;
|
||||
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 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName {
|
||||
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)
|
||||
}))
|
||||
}
|
||||
|
@ -300,3 +300,74 @@ impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ use std::path::PathBuf;
|
||||
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 @@ impl Collector {
|
||||
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,
|
||||
|
@ -243,6 +243,7 @@ mod uint_macros;
|
||||
#[path = "num/f64.rs"] pub mod f64;
|
||||
|
||||
pub mod ascii;
|
||||
|
||||
pub mod thunk;
|
||||
|
||||
/* Common traits */
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 @@ impl<A> Future<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 @@ impl<A> Future<A> {
|
||||
* function. It is not spawned into another task.
|
||||
*/
|
||||
|
||||
Future {state: Pending(Thunk::new(f))}
|
||||
Future {state: Pending(Box::new(f))}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ impl 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 @@ impl Builder {
|
||||
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 @@ impl Builder {
|
||||
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 @@ impl Builder {
|
||||
// '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 @@ impl Builder {
|
||||
};
|
||||
|
||||
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 @@ mod test {
|
||||
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 @@ mod test {
|
||||
#[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 @@ mod test {
|
||||
fn test_avoid_copying_the_body_thread_spawn() {
|
||||
avoid_copying_the_body(|f| {
|
||||
thread::spawn(move|| {
|
||||
f.invoke(());
|
||||
f();
|
||||
});
|
||||
})
|
||||
}
|
||||
@ -849,7 +853,7 @@ mod test {
|
||||
fn test_avoid_copying_the_body_join() {
|
||||
avoid_copying_the_body(|f| {
|
||||
let _ = thread::spawn(move|| {
|
||||
f.invoke(())
|
||||
f()
|
||||
}).join();
|
||||
})
|
||||
}
|
||||
@ -862,13 +866,13 @@ mod test {
|
||||
// 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]
|
||||
|
@ -12,45 +12,9 @@
|
||||
#![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)
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ use self::OutputLocation::*;
|
||||
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::path::PathBuf;
|
||||
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 @@ pub fn run_test(opts: &TestOpts,
|
||||
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 @@ pub fn run_test(opts: &TestOpts,
|
||||
}
|
||||
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 @@ pub fn run_test(opts: &TestOpts,
|
||||
}
|
||||
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 @@ mod 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 @@ mod 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);
|
||||
@ -1219,7 +1220,7 @@ mod tests {
|
||||
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 @@ mod tests {
|
||||
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 @@ mod tests {
|
||||
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 @@ mod tests {
|
||||
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 @@ mod tests {
|
||||
ignore: true,
|
||||
should_panic: ShouldPanic::No,
|
||||
},
|
||||
testfn: DynTestFn(Thunk::new(move|| {})),
|
||||
testfn: DynTestFn(Box::new(move|| {})),
|
||||
},
|
||||
TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
@ -1314,7 +1315,7 @@ mod tests {
|
||||
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 @@ mod tests {
|
||||
ignore: false,
|
||||
should_panic: ShouldPanic::No,
|
||||
},
|
||||
testfn: DynTestFn(Thunk::new(testfn)),
|
||||
testfn: DynTestFn(Box::new(testfn)),
|
||||
};
|
||||
tests.push(test);
|
||||
}
|
||||
|
@ -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 => (),
|
||||
};
|
||||
}
|
||||
|
@ -23,5 +23,5 @@ use std::thunk::Thunk;
|
||||
|
||||
pub fn main() {
|
||||
let mut x = 1;
|
||||
let _thunk = Thunk::new(move|| { x = 2; });
|
||||
let _thunk = Box::new(move|| { x = 2; });
|
||||
}
|
||||
|
@ -12,10 +12,10 @@
|
||||
|
||||
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)));
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ use std::thunk::Thunk;
|
||||
|
||||
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()),
|
||||
|
@ -18,11 +18,11 @@ use std::thunk::Thunk;
|
||||
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));
|
||||
}
|
||||
|
@ -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>;
|
||||
|
Loading…
Reference in New Issue
Block a user