use std::collections::HashMap; use std::sync::mpsc::{Receiver, SyncSender}; use std::thread; use uuid::Uuid; use crate::number::Number; use crate::world::World; #[derive(Clone, Hash, Copy, Eq, PartialEq)] pub struct ActorId(Uuid); #[derive(Clone)] pub enum Type { String, Record { name: String, fields: Vec }, AnyNumber, NumberInRange { min: Option, max: Option, }, List { contents: Box, }, } #[derive(Clone)] pub enum Value { String(String), Record(Vec<(String, Value)>), Number(Number), List(Vec), } #[derive(Clone)] pub struct Slot { pub name: String, pub r#type: Type, } pub trait Actorful { fn inputs(&self) -> Vec; fn outputs(&self) -> Vec; fn launch(&self, input_channels: HashMap>, output_channels: HashMap>, world: &mut World) -> Box; fn boxed_clone(&self) -> Box; } #[derive(Clone)] pub enum ProducerSlotID { Input(String), ChildOutput(ActorId, String), } #[derive(Clone)] pub enum ConsumerSlotID { Output(String), ChildInput(ActorId, String), } #[derive(Clone, Default)] pub struct ProgrammableActor { pub inputs: Vec, pub outputs: Vec, pub children: HashMap, pub cables: Vec<(ProducerSlotID, ConsumerSlotID)>, } impl ProgrammableActor { pub fn add_child(&mut self, actor_type: String) -> ActorId { let id = ActorId(Uuid::new_v4()); self.children.insert(id, actor_type); id } pub fn add_cable(&mut self, in_slot: ProducerSlotID, out_slot: ConsumerSlotID) { self.cables.push((in_slot, out_slot)); } } impl Actorful for ProgrammableActor { fn inputs(&self) -> Vec { self.inputs.clone() } fn outputs(&self) -> Vec { self.outputs.clone() } fn launch(&self, mut input_channels: HashMap>, mut output_channels: HashMap>, world: &mut World) -> Box { let mut child_inputs = HashMap::new(); let mut child_outputs = HashMap::new(); for (&child_id, child_type) in &self.children { let (_, my_inputs, my_outputs) = world.spawn_actor(child_type); child_inputs.extend(my_inputs.into_iter().map(|(name, sender)| ((child_id, name), sender))); child_outputs.extend(my_outputs.into_iter().map(|(name, receiver)| ((child_id, name), receiver))); } let cables = self.cables.clone(); Box::new(move || { for (source, dest) in cables { let source = match source { ProducerSlotID::Input(name) => input_channels.remove(&name).unwrap(), ProducerSlotID::ChildOutput(id, name) => child_outputs.remove(&(id, name)).unwrap() }; let dest = match dest { ConsumerSlotID::Output(name) => output_channels.remove(&name).unwrap(), ConsumerSlotID::ChildInput(id, name) => child_inputs.remove(&(id, name)).unwrap() }; thread::spawn(move || { for val in source.iter() { let _ = dest.try_send(val); } }); } }) } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } }