diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/actor.rs | 49 | ||||
-rw-r--r-- | src/basic_actors.rs | 63 | ||||
-rw-r--r-- | src/main.rs | 39 | ||||
-rw-r--r-- | src/world.rs | 12 |
4 files changed, 108 insertions, 55 deletions
diff --git a/src/actor.rs b/src/actor.rs index e83c003..12e351f 100644 --- a/src/actor.rs +++ b/src/actor.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::mpsc::{Receiver, Sender}; +use std::sync::mpsc::{Receiver, SyncSender}; use std::thread; use uuid::Uuid; @@ -44,7 +44,8 @@ pub struct Slot { pub trait Actorful { fn inputs(&self) -> Vec<Slot>; fn outputs(&self) -> Vec<Slot>; - fn launch(&self, input_channels: HashMap<String, Receiver<Value>>, output_channels: HashMap<String, Sender<Value>>, world: &mut World); + fn launch(&self, input_channels: HashMap<String, Receiver<Value>>, + output_channels: HashMap<String, SyncSender<Value>>, world: &mut World) -> Box<dyn FnOnce() + Send>; fn boxed_clone(&self) -> Box<dyn Actorful + Send>; } @@ -89,27 +90,33 @@ impl Actorful for ProgrammableActor { self.outputs.clone() } - fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, mut output_channels: HashMap<String, Sender<Value>>, world: &mut World) { - let mut child_channels = HashMap::new(); + fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, + mut output_channels: HashMap<String, SyncSender<Value>>, world: &mut World) -> Box<dyn FnOnce() + Send> { + let mut child_inputs = HashMap::new(); + let mut child_outputs = HashMap::new(); for (&child_id, child_type) in &self.children { - let (_, child_inputs, child_outputs) = world.spawn_actor(child_type); - child_channels.insert(child_id, (child_inputs, child_outputs)); - } - for (source, dest) in &self.cables { - let source = match source { - ProducerSlotID::Input(name) => input_channels.remove(name).unwrap(), - ProducerSlotID::ChildOutput(id, name) => child_channels[id].1.remove(name).unwrap() - }; - let dest = match dest { - ConsumerSlotID::Output(name) => output_channels.remove(name).unwrap(), - ConsumerSlotID::ChildInput(id, name) => child_channels[id].0.remove(name).unwrap() - }; - thread::spawn(move || { - for val in source.iter() { - dest.send(val).unwrap() - } - }); + 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() { + dest.send(val).unwrap() + } + }); + } + }) } fn boxed_clone(&self) -> Box<dyn Actorful + Send> { diff --git a/src/basic_actors.rs b/src/basic_actors.rs index 6f514d6..da391cf 100644 --- a/src/basic_actors.rs +++ b/src/basic_actors.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::mpsc::{Sender, Receiver}; +use std::sync::mpsc::{SyncSender, Receiver}; use crate::actor::{Value, Type, Actorful, Slot}; use crate::number::Number; @@ -20,10 +20,14 @@ impl Actorful for Constant { vec![Slot { name: "Value".to_string(), r#type: self.r#type.clone() }] } - fn launch(&self, _input_channels: HashMap<String, Receiver<Value>>, output_channels: HashMap<String, Sender<Value>>, _world: &mut World) { - loop { - output_channels["Value"].send(self.value.clone()).unwrap() - } + fn launch(&self, _input_channels: HashMap<String, Receiver<Value>>, + output_channels: HashMap<String, SyncSender<Value>>, _world: &mut World) -> Box<dyn FnOnce() + Send> { + let value = self.value.clone(); + Box::new(move || { + loop { + output_channels["Value"].send(value.clone()).unwrap() + } + }) } fn boxed_clone(&self) -> Box<dyn Actorful + Send> { @@ -46,14 +50,17 @@ impl Actorful for Add { vec![Slot { name: "Result".to_string(), r#type: Type::AnyNumber }] } - fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, output_channels: HashMap<String, Sender<Value>>, _world: &mut World) { + fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, + output_channels: HashMap<String, SyncSender<Value>>, _world: &mut World) -> Box<dyn FnOnce() + Send> { let n1 = input_channels.remove("N1").unwrap(); let n2 = input_channels.remove("N2").unwrap(); - for (n1, n2) in n1.iter().zip(n2.iter()) { - if let (Value::Number(n1), Value::Number(n2)) = (n1, n2) { - output_channels["Result"].send(Value::Number(n1 + n2)).unwrap(); + Box::new(move || { + for (n1, n2) in n1.iter().zip(n2.iter()) { + if let (Value::Number(n1), Value::Number(n2)) = (n1, n2) { + output_channels["Result"].send(Value::Number(n1 + n2)).unwrap(); + } } - } + }) } fn boxed_clone(&self) -> Box<dyn Actorful + Send> { @@ -82,18 +89,21 @@ impl Actorful for RepeatValue { vec![Slot { name: "List".to_string(), r#type: Type::List { contents: Box::new(self.r#type.clone()) } }] } - fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, output_channels: HashMap<String, Sender<Value>>, _world: &mut World) { + fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, + output_channels: HashMap<String, SyncSender<Value>>, _world: &mut World) -> Box<dyn FnOnce() + Send> { let value = input_channels.remove("Value").unwrap(); let count = input_channels.remove("Count").unwrap(); - for (value, count) in value.iter().zip(count.iter()) { - if let Value::Number(count) = count { - // TODO figure out what a smart thing to do would be here instead - // this API design is deliberately suboptimal because i'd like to not do it - let count: usize = format!("{}", count).parse().unwrap(); - let vec = vec![value; count]; - output_channels["List"].send(Value::List(vec)).unwrap(); + Box::new(move || { + for (value, count) in value.iter().zip(count.iter()) { + if let Value::Number(count) = count { + // TODO figure out what a smart thing to do would be here instead + // this API design is deliberately suboptimal because i'd like to not do it + let count: usize = format!("{}", count).parse().unwrap(); + let vec = vec![value; count]; + output_channels["List"].send(Value::List(vec)).unwrap(); + } } - } + }) } fn boxed_clone(&self) -> Box<dyn Actorful + Send> { @@ -119,15 +129,18 @@ impl Actorful for DeconstructRecord { } } - fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, output_channels: HashMap<String, Sender<Value>>, _world: &mut World) { + fn launch(&self, mut input_channels: HashMap<String, Receiver<Value>>, + output_channels: HashMap<String, SyncSender<Value>>, _world: &mut World) -> Box<dyn FnOnce() + Send> { let record = input_channels.remove("Record").unwrap(); - for record in record.iter() { - if let Value::Record(fields) = record { - for (label, value) in fields { - output_channels[&label].send(value).unwrap(); + Box::new(move || { + for record in record.iter() { + if let Value::Record(fields) = record { + for (label, value) in fields { + output_channels[&label].send(value).unwrap(); + } } } - } + }) } fn boxed_clone(&self) -> Box<dyn Actorful + Send> { diff --git a/src/main.rs b/src/main.rs index b4adbd3..6bf920b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use minifb::{Key, Window, WindowOptions}; +use minifb::{Key, Window, WindowOptions, MouseMode}; mod actor; mod basic_actors; @@ -98,9 +98,40 @@ fn main() { world.upsert_actor_type("System".to_string(), Box::new(system)); + let (_, mut system_inputs, mut system_outputs) = world.spawn_actor("System"); + + let mouse_position = system_inputs.remove("mouse_position").unwrap(); + let screen_buffer = system_outputs.remove("screen_buffer").unwrap(); + while window.is_open() && !window.is_key_down(Key::Escape) { - window - .update_with_buffer(&buffer, WIDTH, HEIGHT) - .unwrap(); + if let Some((mouse_x, mouse_y)) = window.get_mouse_pos(MouseMode::Discard) { + let mouse_x = mouse_x as u16; + let mouse_y = mouse_y as u16; + let value = actor::Value::Record(vec![ + ("X".to_string(), actor::Value::Number(number::Number::from(mouse_x))), + ("Y".to_string(), actor::Value::Number(number::Number::from(mouse_y))), + ]); + mouse_position.send(value).unwrap(); + } + + if let Ok(value) = screen_buffer.try_recv() { + if let actor::Value::List(data) = value { + let u32_data: Vec<u32> = data.into_iter() + .map(|x| { + if let actor::Value::Number(x) = x { + format!("{}", x).parse().unwrap() + } else { + panic!("bruh") + } + }) + .collect(); + if u32_data.len() != WIDTH * HEIGHT { + panic!("bruhhhhhhhhhhhhhh"); + } + window.update_with_buffer(&u32_data, WIDTH, HEIGHT).unwrap(); + } + } else { + window.update(); + } } } diff --git a/src/world.rs b/src/world.rs index 53217e2..1fbc4fe 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,11 +1,13 @@ use std::collections::HashMap; -use std::sync::mpsc::{self, Receiver, Sender}; +use std::sync::mpsc::{self, Receiver, SyncSender}; use std::thread; use uuid::Uuid; use crate::actor::{Actorful, Value, Slot}; +const CHANNEL_SIZE: usize = 5; + pub struct ActorThreadId(Uuid); #[derive(Default)] @@ -19,9 +21,9 @@ impl World { self.actor_types.insert(name, actor); } - pub fn spawn_actor(&mut self, r#type: &str) -> (Uuid, HashMap<String, Sender<Value>>, HashMap<String, Receiver<Value>>) { - fn make_channels(slot: Slot) -> ((String, Sender<Value>), (String, Receiver<Value>)) { - let (sender, receiver) = mpsc::channel::<Value>(); + pub fn spawn_actor(&mut self, r#type: &str) -> (Uuid, HashMap<String, SyncSender<Value>>, HashMap<String, Receiver<Value>>) { + fn make_channels(slot: Slot) -> ((String, SyncSender<Value>), (String, Receiver<Value>)) { + let (sender, receiver) = mpsc::sync_channel::<Value>(CHANNEL_SIZE); ((slot.name.clone(), sender), (slot.name, receiver)) } @@ -40,7 +42,7 @@ impl World { let id = Uuid::new_v4(); thread::Builder::new() .name(id.to_string()) - .spawn(move || actor.launch(input_receivers, output_senders, self)) + .spawn(actor.launch(input_receivers, output_senders, self)) .unwrap(); (id, input_senders, output_receivers) } |