Calling a function on a generic type

I'm stuck in the process of refactoring some code:

use actix_web::rt;
use tokio::sync::{mpsc, oneshot};

pub enum StatusResponse {
    Running,
}

pub enum Message {
    Status {
        respond_to: oneshot::Sender<StatusResponse>,
    },
}

trait ActorType<T> {
    fn new(receiver: mpsc::Receiver<T>) -> Self;
}

trait MessageType {}

fn new_actor_handle<T, U>() -> mpsc::Sender<U>
    where T: ActorType<T>,
          U: MessageType {

    let (sender, receiver) = mpsc::channel::<U>(8);
    let mut actor = T::new(receiver);

    let actor_task = tokio::task::spawn_blocking(move || {
        rt::System::new().block_on(async {
            actor.run().await
        });
    });

    sender
}

impl<T> ActorType<T> for Actor {
    fn new(receiver: tokio::sync::mpsc::Receiver<T>) -> Self {
        Actor {
            receiver,
        }
    }
}

impl MessageType for Message {}

#[derive(Clone)]
pub struct Handle {
    pub sender: mpsc::Sender<Message>,
}

impl Handle {
    pub fn new() -> Self {
        Self { sender: new_actor_handle::<Actor, Message>() }
    }

    pub async fn start(&self) -> StatusResponse {
        let (send, recv) = oneshot::channel();
        let msg = Message::Status {
            respond_to: send,
        };

        let _ = self.sender.send(msg).await;
        recv.await.expect("Actor task has been killed")
    }
}

struct Actor {
    receiver: mpsc::Receiver<Message>,
}

impl Actor {
    fn handle_message(&mut self, msg: Message) {
        match msg {
            Message::Status { respond_to } => {
                respond_to.send(StatusResponse::Running);
            },
        }
    }

    async fn run(&mut self) {
        while let Some(msg) = self.receiver.recv().await {
            self.handle_message(msg);
        }

        tracing::info!("done.");
    }
}

The error I get:

error[E0308]: mismatched types
  --> src/test.rs:22:28
   |
18 | fn new_actor_handle<T, U>() -> mpsc::Sender<U>
   |                     -  - found type parameter
   |                     |
   |                     expected type parameter
...
22 |     let mut actor = T::new(receiver);
   |                     ------ ^^^^^^^^ expected `Receiver<T>`, found `Receiver<U>`
   |                     |
   |                     arguments to this function are incorrect
   |
   = note: expected struct `tokio::sync::mpsc::Receiver<T>`
              found struct `tokio::sync::mpsc::Receiver<U>`
   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
note: associated function defined here
  --> src/test.rs:15:8
   |
15 |     fn new(receiver: mpsc::Receiver<T>) -> Self;
   |        ^^^

In the first version I didn't use ActorType and MessageType, but it did not compile, so I tried to add the marker traits.
The relevant function I want to get working is new_actor_handle so I can use this actor approach on multiple modules without copy pasting it everywhere.
Not sure what I'm doing wrong, so any help is welcome :slight_smile:

You are passing a Receiver<U> into the actor constructor instead of a Receiver<T>. You probably want to change your type bounds to: where TActor: ActorType<TMessage>, TMessage: Messagetype. Right now you're doing where TActor: ActorType<TActor>, TMessage: MessageType which is probably a mistake since the ActorType looks like it expects something that implements MessageType as a parameter.

That was indeed the issue. Thanks.

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.