0

I would like something as follows. Where my async fn my_fn(arg: &str) takes a reference and does something with it. Note that my_fn must be async because my real code does async stuff. See the Playground for the example.

use futures::Future;
use std::marker::PhantomData;

struct MyStruct<M, F> {
    my_fn: M,

    phantom: PhantomData<F>,
}

impl<M, F> MyStruct<M, F>
where
    M: Fn(&str) -> F,
    F: Future<Output = ()>,
{
    async fn run(&mut self) {
        let args = String::from("world");
        (self.my_fn)(&args).await;
    }
}

async fn my_fn(arg: &str) {
    println!("hello {}", arg);
}

#[tokio::main]
async fn main() {
    let mut s = MyStruct {
        my_fn: my_fn,
        phantom: PhantomData,
    };
    s.run().await;
}

Unfortunately I get the error:

error[E0599]: the method run exists for struct MyStruct<for<'r> fn(&'r str) -> impl for<'r> futures::Future<Output = ()> {my_fn}, _>, but its trait bounds were not satisfied --> src/main.rs:31:7

I see that if my_fn takes ownership of the passed in argument such as async fn my_fn(arg: String) instead of async fn my_fn(arg: &str) then it works. See Playground link. Unfortunately in my real code I am not able to pass ownership to my_fn.

use futures::Future;
use std::marker::PhantomData;

struct MyStruct<M, F> {
    my_fn: M,

    phantom: PhantomData<F>,
}

impl<M, F> MyStruct<M, F>
where
    M: Fn(String) -> F,
    F: Future<Output = ()>,
{
    async fn run(&mut self) {
        let args = String::from("world");
        (self.my_fn)(args).await;
    }
}

async fn my_fn(arg: String) {
    println!("hello {}", arg);
}

#[tokio::main]
async fn main() {
    let mut s = MyStruct {
        my_fn: my_fn,
        phantom: PhantomData,
    };
    s.run().await;
}

Is this an issue where I need to Pin something or similar?

Dan
  • 5,013
  • 5
  • 33
  • 59

0 Answers0