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)      }  |