theta 0.1.0-alpha.47

An Rust Actor Framework
Documentation
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use theta_macros::{ActorArgs, actor};

use crate::{actor::Actor, context::RootContext, message::Continuation, prelude::ActorRef};

#[derive(Debug, Clone, ActorArgs)]
pub struct Manager {
    workers: HashMap<String, ActorRef<Worker>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateWorker {
    pub name: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GetWorker {
    pub name: String,
}

#[derive(Debug, Clone, ActorArgs)]
pub struct Worker {}

#[actor("27ca7f4a-f2f7-4644-8ff9-4bdd8f40b5cd")]
impl Actor for Worker {}

#[actor("d89de30e-79c5-49b6-9c16-0903ac576277")]
impl Actor for Manager {
    const _: () = {
        async |msg: CreateWorker| -> () {
            println!("Creating worker with name: {}", msg.name);

            let worker = ctx.spawn(Worker {});

            self.workers.insert(msg.name.clone(), worker.clone());
        };

        async |GetWorker { name }| -> Option<ActorRef<Worker>> {
            println!("Getting worker with name: {name}");

            if let Some(worker) = self.workers.get(&name).cloned() {
                Some(worker)
            } else {
                println!("Worker with name {name} not found");
                None
            }
        };
    };
}

#[tokio::test]
async fn test_manager_behavior() {
    let ctx = RootContext::default();

    let msgs: Vec<<Manager as Actor>::Msg> = vec![
        CreateWorker {
            name: "Worker1".to_string(),
        }
        .into(),
        GetWorker {
            name: "Worker1".to_string(),
        }
        .into(),
    ];

    let serialized_msgs = msgs
        .iter()
        .map(|m| postcard::to_allocvec_cobs(m).unwrap())
        .collect::<Vec<_>>();

    let deserialized_msgs: Vec<<Manager as Actor>::Msg> = serialized_msgs
        .into_iter()
        .map(|mut m| postcard::from_bytes_cobs(m.as_mut_slice()).unwrap())
        .collect();

    let manager = ctx.spawn(Manager {
        workers: HashMap::new(),
    });

    for msg in deserialized_msgs {
        let _ = manager.send(msg, Continuation::Nil);
    }
}