This is the function I am trying to call:
#[inline]
pub fn spawn<F>(f: F) -> Handle
where F: FnOnce(&mut Coroutine) + Send + 'static
{
Self::spawn_opts_impl(Box::new(f), Options::default())
}
I then created an enum because I actually want to send it from one thread to another, which is also why I have boxed the function. I have also matched the trait constraints.
enum Message {
Task(Box<FnOnce(&mut Coroutine) + Send + 'static>),
}
But if I try to extract the function from a Message
:
fn main(){
let m = Message::Task(Box::new(|me| {
}));
let c = match m{
Message::Task(f) => Coroutine::spawn(f)
};
}
I get the following error:
src/main.rs:168:29: 168:45 error: the trait bound `for<'r> Box<for<'r> std::ops::FnOnce(&'r mut coroutine::asymmetric::Coroutine) + Send>: std::ops::FnOnce<(&'r mut coroutine::asymmetric::Coroutine,)>` is not satisfied [E0277]
src/main.rs:168 Message::Task(f) => Coroutine::spawn(f)
^~~~~~~~~~~~~~~~
src/main.rs:168:29: 168:45 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:168:29: 168:45 help: the following implementations were found:
src/main.rs:168:29: 168:45 help: <Box<std::boxed::FnBox<A, Output=R> + 'a> as std::ops::FnOnce<A>>
src/main.rs:168:29: 168:45 help: <Box<std::boxed::FnBox<A, Output=R> + Send + 'a> as std::ops::FnOnce<A>>
src/main.rs:168:29: 168:45 note: required by `coroutine::asymmetric::Coroutine::spawn`
I have no idea what Rust is trying to tell me here. I assume that the problem is that spawn
expects a non boxed function, but I get the same error if I try to deref the boxed function.
Note that at the time this question was asked, coroutine-rs doesn't build, and I fixed the errors in this fork.
Let's read the error message carefully:
Basically, you are trying to pass a
Box<FnOnce>
to a function that expects a type that implementsFnOnce
.However, you cannot call a function that is in a
Box<FnOnce>
, because in order to call it, you need to passself
by value, which means that you need to dereference theBox
, but that yields an unsized type, which cannot be passed by value (as of Rust 1.9).The current workaround is to use the unstable
FnBox
trait instead ofFnOnce
.FnBox
is automatically implemented for all types that implementFnOnce
. Here's how we can use it:Note that the call to
Command::spawn
receives a closure that calls theFnBox
, because we can't pass theFnBox
directly toCommand::spawn
for the reasons mentioned above. Also, I had to explicitly annotate the argument type on the first closure, otherwise the compiler complained (expected concrete lifetime, found bound lifetime parameter
, which I think is a bug in the compiler).