aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-03-07 09:49:58 -0700
committerMelody Horn <melody@boringcactus.com>2021-03-07 09:49:58 -0700
commitc8cfeabc011bfabb6303023a969155ded926d95c (patch)
tree0c8ca2f7b6e8d6923e8daafa7c87c5d31764f0c1
parent36d5ff553a1d65d70da5251b8865d62294c929f6 (diff)
downloadhope-c8cfeabc011bfabb6303023a969155ded926d95c.tar.gz
hope-c8cfeabc011bfabb6303023a969155ded926d95c.zip
another crumb or two of architecture tweaks
-rw-r--r--src/actor.rs49
-rw-r--r--src/basic_actors.rs63
-rw-r--r--src/main.rs39
-rw-r--r--src/world.rs12
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)
}