Coroutine-rs
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:
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]
Basically, you are trying to pass a Box<FnOnce>
to a function that expects a type that implements FnOnce
.
However, you cannot call a function that is in a Box<FnOnce>
, because in order to call it, you need to pass self
by value, which means that you need to dereference the Box
, 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 of FnOnce
. FnBox
is automatically implemented for all types that implement FnOnce
. Here's how we can use it:
#![feature(fnbox)]
use std::boxed::FnBox;
enum Message {
Task(Box<FnBox(&mut Coroutine) + Send + 'static>),
}
fn main() {
let m = Message::Task(Box::new(|me: &mut Coroutine| {
}));
let c = match m {
Message::Task(f) => Coroutine::spawn(|me| f.call_box((me,)))
};
}
Note that the call to Command::spawn
receives a closure that calls the FnBox
, because we can't pass the FnBox
directly to Command::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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With