//! Arithmetic operations: add, subtract, etc. use crate::prelude::*; use crate::tile::prelude::*; macro_rules! binary_op { () => { fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) { if let Some(mut signal) = context.take_signal() { if signal.len() >= 2 { let first = signal.pop().unwrap_or_else(|| unreachable!()); let second = signal.pop().unwrap_or_else(|| unreachable!()); if let Some(res) = self.binary_op(second, first) { signal.push(res); } } if let Some(coords) = context.offset(signal.direction().into_offset()) { context.send(coords, signal.direction(), signal).unwrap_or_else(|_| unreachable!()); } } if context.state() != State::Idle { context.next_state(); } } } } /// Adds two values together: `[..., a, b] -> [..., a+b]` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Add; impl Add { fn binary_op(&self, left: Value, right: Value) -> Option { Some(left + right) } } impl Tile for Add { binary_op!(); fn draw_simple(&self, ctx: DrawContext) -> TextChar { TextChar::from_state('\u{2295}', ctx.state) // CIRCLED PLUS } } /// Subtracts two values: `[..., a, b] -> [..., a-b]` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Sub; impl Sub { fn binary_op(&self, left: Value, right: Value) -> Option { use Value::*; match (left, right) { (Number(x), Number(y)) => Some(Number(x - y)), (String(mut x), Number(y)) => { x.truncate(y as usize); Some(String(x)) } (String(x), String(y)) => { Some(String(x.split(&y).collect())) } _ => None } } } impl Tile for Sub { binary_op!(); fn draw_simple(&self, ctx: DrawContext) -> TextChar { TextChar::from_state('\u{2296}', ctx.state) // CIRCLED MINUS } } /// Multiplies two values together: `[..., a, b] -> [..., a*b]` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Mul; impl Mul { fn binary_op(&self, left: Value, right: Value) -> Option { use Value::*; match (left, right) { (Number(x), Number(y)) => Some(Number(x * y)), (String(x), Number(y)) => Some(String(x.repeat(y as usize))), _ => None } } } impl Tile for Mul { binary_op!(); fn draw_simple(&self, ctx: DrawContext) -> TextChar { TextChar::from_state('\u{2297}', ctx.state) // CIRCLED TIMES } } /// Divides two values together: `[..., a, b] -> [..., a/b]` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Div; impl Div { fn binary_op(&self, left: Value, right: Value) -> Option { use Value::*; match (left, right) { (Number(x), Number(y)) => Some(Number(x / y)), _ => None } } } impl Tile for Div { binary_op!(); fn draw_simple(&self, ctx: DrawContext) -> TextChar { TextChar::from_state('\u{2298}', ctx.state) // CIRCLED DIVISION SLASH } } /// Computes the modulo of two values: `[..., a, b] -> [..., a%b]` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Mod; impl Mod { fn binary_op(&self, left: Value, right: Value) -> Option { use Value::*; match (left, right) { (Number(x), Number(y)) => Some(Number(x % y)), _ => None } } } impl Tile for Mod { binary_op!(); fn draw_simple(&self, ctx: DrawContext) -> TextChar { TextChar::from_state('\u{2299}', ctx.state) // CIRCLED DOT OPERATOR } }