Mutable Arc in Rust

Viewed 13486

Earlier I had a Sync + Send trait SyncMessenger:

trait Messenger {
    fn send_message(&self, user_id: UserId, text: &str);
}

trait SyncMessenger: Messenger + Sync + Send {}

It's implementation:

pub struct DiscordMessenger {
    discord: Arc<Discord>, // (Discord is Sync and Send already)
}
impl Messenger for DiscordMessenger {
    fn send_message(&self, user_id: UserId, text: &str) {
        self.discord.send_message(user_id, text, false);
    }
}
impl SyncMessenger for DiscordMessenger {}

And using it:

struct Bot {
    messenger: Arc<SyncMessenger>,
}
impl Bot {
    pub fn new() -> Bot {
        Bot { messenger: Arc::new(DiscordMessenger::new()) }
    }   

    fn messenger(&self) -> Arc<SyncMessenger> {
        self.messenger.clone()
    }
}

struct PingCommand {
    fn fire(&mut self, bot: &mut Bot) {
        bot.messenger().send_message(UserId(0), "Pong");
    }
}

Everything worked fine. Now I want to implement TestMessenger which does not really send a message through a network but toggles a flag in Self instead:

#[cfg(test)]
struct TestMessenger {
    pub message_sent: bool,
}
impl Messenger for TestMessenger {
    fn send_message(&mut self, user_id: UserId, text: &str) { // we have `&mut self` here
        self.message_sent = true;
    }
}

So I need to change send_message(&self) to send_message(&mut self) everywhere (in traits and in implementations). I did that but after I can't compile my user code:

struct PingCommand {
    fn fire(&mut self, bot: &mut Bot) {
        bot.messenger().send_message(UserId(0), "Pong");
    }
}

Gives error:

   |
12 |         let _ = bot.messenger().send_message(UserId(0),
   |                 ^^^^^^^^^^^^^^^ cannot borrow as mutable

error: aborting due to previous error

I have found something that works but it looks very ugly to me (and requires unwrap() which I would like to avoid):

let _ = Arc::get_mut(&mut bot.messenger()).unwrap().send_message(UserId(0),

So the question here is how to do that as much simple as possible, without unwrap()s, static methods like Arc::get_mut? Why simple fn messenger(&self) -> Arc<SyncMessenger> is not possible to call mut methods?

2 Answers
Related