I have 2 pieces of code, one is compiling and other does not. I do not understand the difference. I suspect It has something to do with variance, but I am not sure:
This one uses tokio's oneshot, and it compiles.
use std::{future::{Future, IntoFuture}, marker::PhantomData};
use tokio::task::JoinHandle;
#[derive(Debug)]
struct TaskHandle<'a>(JoinHandle<()>, PhantomData<&'a ()>);
impl Drop for TaskHandle<'_> {
fn drop(&mut self) {
self.0.abort();
}
}
fn spawn<'a, IFut, Fut>(_fut: IFut) -> TaskHandle<'a>
where
IFut: IntoFuture<Output = (), IntoFuture = Fut>,
Fut: 'a + Send + Future<Output = ()>,
{
todo!()
}
#[tokio::main]
async fn main() {
let mut foo = 32;
let (tx, rx) = tokio::sync::oneshot::channel::<TaskHandle<'_>>();
let handle = spawn(async {
rx.await.unwrap();
foo += 10;
});
tx.send(handle).unwrap();
assert_eq!(foo, 42);
}
This one uses chan
crate, which uses safe code with Arc
and Mutex
. This does not compile
use std::{future::{Future, IntoFuture}, marker::PhantomData};
use tokio::task::JoinHandle;
#[derive(Debug)]
struct TaskHandle<'a>(JoinHandle<()>, PhantomData<&'a ()>);
impl Drop for TaskHandle<'_> {
fn drop(&mut self) {
self.0.abort();
}
}
fn spawn<'a, IFut, Fut>(_fut: IFut) -> TaskHandle<'a>
where
IFut: IntoFuture<Output = (), IntoFuture = Fut>,
Fut: 'a + Send + Future<Output = ()>,
{
todo!()
}
#[tokio::main]
async fn main() {
let mut foo = 32;
let (tx, rx) = chan::sync::<TaskHandle<'_>>(0);
let handle = spawn(async {
rx.recv();
foo += 10;
});
tx.send(handle);
assert_eq!(foo, 42);
}
Error:
1 error[E0597]: `rx` does not live long enough
--> src/main.rs:31:9
|
27 | let (tx, rx) = chan::sync::<TaskHandle<'_>>(0);
| -- binding `rx` declared here
28 |
29 | let handle = spawn(async {
| ----- value captured here by coroutine
30 | // rx.await.unwrap();
31 | rx.recv();
| ^^ borrowed value does not live long enough
...
39 | }
| -
| |
| `rx` dropped here while still borrowed
| borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `chan::Sender`
|
= note: values in a scope are dropped in the opposite order they are defined
2 error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
--> src/main.rs:38:5
|
29 | let handle = spawn(async {
| ----- mutable borrow occurs here
...
32 | foo += 10;
| --- first borrow occurs due to use of `foo` in coroutine
...
38 | assert_eq!(foo, 42);
| ^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here
39 | }
| - mutable borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `chan::Sender`
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
Some errors have detailed explanations: E0502, E0597.
For more information about an error, try `rustc --explain E0502`.
error: could not compile `play` (bin "play") due to 2 previous errors