Generic higher order traits (I suppose)

Hello fellow Rustaceans.

The question is for Actix actors, but the problem is not within Actix but within higher order trait bounds I can't construct.

First things first:

I have 3 Actix actors

pub struct ManagementActor {}
impl actix::Actor for ManagementActor {
    type Context = Context<Self>;
 // ... 
}

pub struct GuiActor {}
impl actix::Actor for GuiActor {
    type Context = Context<Self>;
 // ...
}

pub struct Dispatcher {
 gui:    Option<actix::Addr<GuiActor>>,
 mgmt:   Option<actix::Addr<ManagementActor>>,
}

impl actix::Actor for Dispatcher {
    type Context = Context<Self>;
 // ...
}

I'd like to implement a broadcast function that will send generic message M to first 2 actors:

impl Dispatcher {
    fn broadcast<M>(&self, m: M)
    where
        M: actix::Message + Copy + Send,
        M::Result: Send,
        // MISSING PART <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    {
        if let Some(adr) = &self.gui {
            adr.do_send(m); // <-- Error here, Rust doesn't know if M is handled by GuiActor
        }

        if let Some(adr) = &self.mgmt {
            adr.do_send(m); // <-- Error here, Rust doesn't know if M is handled by ManagementActor
        }
    }
}

The (obvious) problem is error in adr.do_send(m) lines. I understand the source of error: Rust doesn't know if M is handled by both actors.

My question is: how to properly construct trait bounds for M to express that requirement?

How to express that for M exists some x that implements both:

impl actix::Handler<x> for GuiActor {
   ///
}

and

impl actix::Handler<x> for ManagementActor {
   ///
}

Best regards,

This is only a suggestion based on the docs which I'm not in a position to test myself.

Based on the do_send bounds, I suggest trying:

    GuiActor: Handler<M>,
    <GuiActor as Handler<M>>::Context: ToEnvelope<GuiActor, M>,
    ManagementActor: Handler<M>,
    <ManagementActor as Handler<M>>::Context: ToEnvelope<ManagementActor, M>,
1 Like

@quinedot , you are a genius.

The exact form necessary was:

impl Dispatcher {
    fn broadcast<M>(&self, m: M)
    where
        M: Message + Copy + Send,
        M::Result: Send,

        GuiActor: Handler<M>,
        <GuiActor as Actor>::Context: ToEnvelope<GuiActor, M>,

        ManagementActor: Handler<M>,
        <ManagementActor as Actor>::Context: ToEnvelope<ManagementActor, M>,
    {
     // ...
    }
}

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.