Async Generic Trait Handler using FnOnce - Size cannot be statically determined

The working handler trait uses FnMut successfully but I cannot figure out how to use FnOnce as an async callback.

use std::future::Future;
use futures::future::BoxFuture;

pub trait WorkingHandler: Send + Sync {
    fn call(&mut self, response: u32) -> BoxFuture<'static, ()>;
}

impl<T, F> WorkingHandler for T
where
    T: FnMut(u32) -> F + Send + Sync,
    F: Future<Output = ()> + 'static + Send + Sync,
{
    fn call(&mut self, response: u32) -> BoxFuture<'static, ()> {
        Box::pin(self(response))
    }
}

pub trait BrokenHandler: Send + Sync {
    fn call(self, response: u32) -> BoxFuture<'static, ()>;
}

impl<T, F> BrokenHandler for T
where
    T: FnOnce(u32) -> F + Send + Sync,
    F: Future<Output = ()> + 'static + Send + Sync,
{
    fn call(self, response: u32) -> BoxFuture<'static, ()> {
        Box::pin(self(response))
    }
}

#[tokio::main]
async fn main() {
    let mut working_handler: Box<dyn WorkingHandler> = Box::new(move |response: u32| {
       async move {
           println!("hello response: {}", response);
       } 
    });
    working_handler.call(42).await;
    
    let broken_handler: Box<dyn BrokenHandler> = Box::new(move |response: u32| {
       async move {
           println!("hello response: {}", response);
       } 
    });
    broken_handler.call(42).await;
}
cannot move a value of type dyn BrokenHandler: the size of dyn BrokenHandler cannot be statically determined
       broken_handler.call(42).await;
        ^^^^^^^^^^^^^^^^^^^^^^^

Rust playground example

Traits used with dyn can't have a self argument. It's a fundamental limitation, because such argument is a logical paradox. Passing self without any layer of abstraction/indirection requires exposing the actual concrete representation of this type (its size and layout), but dyn's purpose is to abstract away and hide the type being used.

Your call could take self: Box<dyn Self> or &mut self, but self is not going to work.

&mut self encounters "cannot move out of *self" but self: Box<Self> (without dyn) seems to behave as expected. Thanks!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.