use std::collections::HashMap; use std::sync::mpsc::{Sender, Receiver}; use crate::actor::{Value, Type, Actorful, Slot}; use crate::number::Number; use crate::world::World; #[derive(Clone)] pub struct Constant { pub r#type: Type, pub value: Value, } impl Actorful for Constant { fn inputs(&self) -> Vec { vec![] } fn outputs(&self) -> Vec { vec![Slot { name: "Value".to_string(), r#type: self.r#type.clone() }] } fn launch(&self, _input_channels: HashMap>, output_channels: HashMap>, _world: &mut World) { loop { output_channels["Value"].send(self.value.clone()).unwrap() } } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } } #[derive(Clone)] pub struct Add; impl Actorful for Add { fn inputs(&self) -> Vec { vec![ Slot { name: "N1".to_string(), r#type: Type::AnyNumber }, Slot { name: "N2".to_string(), r#type: Type::AnyNumber }, ] } fn outputs(&self) -> Vec { vec![Slot { name: "Result".to_string(), r#type: Type::AnyNumber }] } fn launch(&self, mut input_channels: HashMap>, output_channels: HashMap>, _world: &mut World) { 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(); } } } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } } #[derive(Clone)] pub struct RepeatValue { pub(crate) r#type: Type, } impl Actorful for RepeatValue { fn inputs(&self) -> Vec { let nonnegative_integer = Type::NumberInRange { min: Some(Number::from(0)), max: None, }; vec![ Slot { name: "Value".to_string(), r#type: self.r#type.clone() }, Slot { name: "Count".to_string(), r#type: nonnegative_integer }, ] } fn outputs(&self) -> Vec { vec![Slot { name: "List".to_string(), r#type: Type::List { contents: Box::new(self.r#type.clone()) } }] } fn launch(&self, mut input_channels: HashMap>, output_channels: HashMap>, _world: &mut World) { 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(); } } } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } } #[derive(Clone)] pub struct DeconstructRecord { pub record_type: Type, } impl Actorful for DeconstructRecord { fn inputs(&self) -> Vec { vec![Slot { name: "Record".to_string(), r#type: self.record_type.clone() }] } fn outputs(&self) -> Vec { if let Type::Record { name: _, fields } = &self.record_type { fields.clone() } else { panic!("bruh that's the wrong goddamn type") } } fn launch(&self, mut input_channels: HashMap>, output_channels: HashMap>, _world: &mut World) { 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(); } } } } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } }