Dyn trait, generic type, incompatible?

I have a dynamic trait Action which has the handle() method which accepts an App<T> argument. This doesn't work because I get the following error:

17 |     action: Box<dyn Action + 'static>,
   |                 ^^^^^^^^^^^^^^^^^^^^ `Action` is not dyn compatible
   |
note: for a trait to be dyn compatible it needs to allow building a vtable
      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
  --> framework/src/action/action.rs:10:14
   |
 9 | pub trait Action: Send + Sync + Debug {
   |           ------ this trait is not dyn compatible...
10 |     async fn handle<T>(
   |              ^^^^^^ ...because method `handle` has generic type parameters
   = help: consider moving `handle` to another trait

What I'm trying to achieve is create a crate with a struct that can accept an App<T> struct where T is AppState from the user. However, this is causing a conflict with the dyn Action trait, which accepts that AppState struct.

Is there a way around this?

What's the full signature? If it just accepts an arg: App<T> and doesn't return it, for example, there's nothing very useful that can be done with the T inside the method. So you could have some method on App to transform it to an App<()> or such.

Otherwise you typically need to work in more type erasure, like App<Box<dyn Any>> or the like.


Incidentally, async fn is also not dyn-compatible, so you'll probably end up with something like

fn handle(...) -> Pin<Box<dyn Future<Output = ()> + Send + Sync '_>>

(or some use of macros that effectively does that).

I'm using the async-trait

#[async_trait]
pub trait Action: Send + Sync + Debug {
    async fn handle<T>(
        &self,
        app: &App<T>,
        request: HttpRequest,
    ) -> Result<Box<dyn Responsable>, HttpError>;
}

Whether it uses App<T> or not depends on the action. Some may use it, others may not. I'll see what I can do with Box and report back.

What I mean is, say I'm implementing your trait...

#[async_trait]
impl Action for Whatever {
    async fn handle<T>(
        &self,
        app: &App<T>,
        request: HttpRequest,
    ) -> Result<Box<dyn Responsable>, HttpError> {
        // Considering this method body
    }
}

...I can only use properties of T which are requirements on the generic. Here, the only requirement is that T: Sized. There's nothing really useful that allows me to do in the method body. So the only useful things I can do with app are things that likewise don't depend on any particular T.

So find an alternative that gets T out of the signature; probably some way to convert from &App<T> to something without T. That could be a method to convert &App<T> to &App<ConcreteType> or NotApp<'_> or such. Or another way would be to put all the useful things you can do with "&App<T> for any T" into a trait and take a &dyn AppTrait (which &App<T> could coerce to).

So I created this type with some extras to satisfy the compiler since it'll be sent across threads (hopefully only immutably).

type AppState = Box<dyn Any + Send + Sync>;

And in the Action struct.

let state: &AppState = &app.state.downcast_ref().unwrap();

This seems to have satisfied the compiler.

Appreciate the help!