Actores: Banquero e Inversores.

El banquero recibe los mensajes con la inversión y si se cumple la condición de que ya recibió todas las devoluciones, se manda un mensaje a el mismo para reiniciar la semana.

extern crate actix;

use std::collections::HashSet;
use actix::{Actor, Context, Handler, System, Message, Addr, AsyncContext, WrapFuture, Recipient, ActorFutureExt, ResponseActFuture};
use rand::{thread_rng, Rng};
use actix::clock::sleep;
use std::time::Duration;

const INVERSORES:usize = 5;

#[derive(Message)]
#[rtype(result = "()")]
struct Invertir {
    amount: f64,
    sender: Recipient<ResultadoInversion>
}

#[derive(Message)]
#[rtype(result = "()")]
struct ResultadoInversion(usize, f64);

#[derive(Message, Debug)]
#[rtype(result = "()")]
struct Semana(f64);

struct Banquero {
    plata: f64,
    inversores: Vec<Recipient<Invertir>>,
    devoluciones: HashSet<usize>
}

struct Inversor {
    id: usize,
}

impl Actor for Banquero {
    type Context = Context<Self>;
}

impl Actor for Inversor {
    type Context = Context<Self>;
}

impl Handler<Semana> for Banquero {
    type Result = ();

    fn handle(&mut self, _msg: Semana, _ctx: &mut Context<Self>) -> Self::Result {
        let plata = _msg.0;
        let amount = plata / self.inversores.len() as f64;
        self.plata = 0.;
        self.devoluciones.clear();

        println!("[BANQUERO] empieza la semana con {}", plata);

        for inversor in self.inversores.iter() {
            inversor.try_send(Invertir { amount, sender: _ctx.address().recipient()}).unwrap();
        }

    }
}

impl Handler<ResultadoInversion> for Banquero {
    type Result = ();

    fn handle(&mut self, msg: ResultadoInversion, _ctx: &mut Context<Self>) -> Self::Result {

        println!("[BANQUERO] recibí resultado de la inversion {}", msg.0);

        if !self.devoluciones.contains(&msg.0) {
            self.plata += msg.1;
            self.devoluciones.insert(msg.0);

            if self.devoluciones.len() == self.inversores.len() {
                println!("[BANQUERO] fin de la semana, resultado final {}", self.plata);
                _ctx.address().try_send(Semana(self.plata)).unwrap();
            }
        }

    }
}

impl Handler<Invertir> for Inversor {
    type Result = ResponseActFuture<Self, ()>;

    fn handle(&mut self, msg: Invertir, _ctx: &mut Context<Self>) -> Self::Result {
        println!("[INV {}] recibo inversion por {}", self.id, msg.amount);
        Box::pin(sleep(Duration::from_millis(thread_rng().gen_range(500, 1500)))
            .into_actor(self)
            .map(move |_result, me, _ctx| {
                let resultado = msg.amount * thread_rng().gen_range(0.5, 1.5);
                println!("[INV {}] devuelvo {}", me.id, resultado);
                msg.sender.try_send(ResultadoInversion(me.id, resultado)).unwrap();
            }))
    }
}

fn main() {
    let system = System::new();
    system.block_on(async {
        let mut inversores = vec!();

        for id in 0..INVERSORES {
            inversores.push(Inversor { id }.start().recipient())
        }

        Banquero { plata: 0.0, inversores, devoluciones: HashSet::with_capacity(INVERSORES) }.start()
            .do_send(Semana(1000.0));
    });

    system.run().unwrap();

}