Search code examples
rustpattern-matchingmessage-passing

Save Vec after pattern match


I'm using the Actor trait from the robots crate:

extern crate robots;    

use std::any::Any;
use robots::actors::{Actor, ActorCell};


#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
    Test { data: Vec<u8> },
}

pub struct Dummy {
    data: Vec<u8>,
}

impl Actor for Dummy {
    // Using `Any` is required for actors in RobotS
    fn receive(&self, message: Box<Any>, _context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<ExampleMessage>(message) {
            match *message {
                ExampleMessage::Test { data } => {
                    self.data = data; // cannot assign to immutable field
                    println!("got message")
                }
            }
        }
    }
}

impl Dummy {
    pub fn new(_: ()) -> Dummy {
        let data = Vec::new();
        Dummy { data }
    }
}

Error:

error: cannot assign to immutable field `self.data`
  --> <anon>:18:21
   |
18 |                     self.data = data; // cannot assign to immutable field
   |                     ^^^^^^^^^^^^^^^^

I understand why my current code does not work, but I don't know what the best way would be to save the incoming data (Vec) so my Dummy can access it later.


Solution

  • I found a test in the RobotS github repo that shows how to manage internal state for an Actor. The state has to be encapsulated inside a Mutex for thread-safe access:

    extern crate robots;    
    
    use std::any::Any;
    use std::sync::Mutex;
    use robots::actors::{Actor, ActorCell};
    
    
    #[derive(Clone, PartialEq)]
    pub enum ExampleMessage {
        Test { data: Vec<u8> },
    }
    
    pub struct Dummy {
        data: Mutex<Vec<u8>>,
    }
    
    impl Actor for Dummy {
        // Using `Any` is required for actors in RobotS
        fn receive(&self, message: Box<Any>, _context: ActorCell) {
            if let Ok(message) = Box::<Any>::downcast::<ExampleMessage>(message) {
                match *message {
                    ExampleMessage::Test { data } => {
                        let mut my_data = self.data.lock().unwrap();
                        *my_data = data;
                        println!("got message")
                    }
                }
            }
        }
    }
    
    impl Dummy {
        pub fn new(_: ()) -> Dummy {
            let data = Mutex::new(Vec::new());
            Dummy { data }
        }
    }