//! Arithmetic operations: add, subtract, etc. use crate::prelude::*; use crate::tile::prelude::*; use veccell::VecRef; #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Store { signal: Option, } impl Store { pub fn signal(&self) -> Option<&Signal> { self.signal.as_ref() } } impl Tile for Store { fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) { if let Some(signal) = context.take_signal() { let position = context.position(); // NOTE: we *could* write the signal immediately, // but by delaying the write we can read from a `Store` without being order-dependent context.callback(move |pane| { if let Some(mut this) = pane.borrow_mut_as::(position) { this.signal = Some(signal); } }); } if context.state() != State::Idle { context.next_state(); } } fn draw_simple(&self, ctx: DrawContext) -> TextChar { if self.signal.is_some() { TextChar::from_state('\u{25c9}', ctx.state) // FISHEYE } else { TextChar::from_state('\u{25cb}', ctx.state) // WHITE CIRCLE } } } /// When a signal is received, reads a signal from a [`Store`] (at the reader's tail), /// then outputs that signal (at the reader's head). /// /// # Example /// /// The following circuit can receive a value in `B`, then store it indefinitely. /// Sending a signal in `A` will output the stored signal from `B` in `OUT`. /// /// ```text /// o = Store /// ▸ = Reader(Right) /// /// (A) ---+ /// | /// (B) --o▸-- (OUT) /// ``` #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Reader(Direction); impl Tile for Reader { fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) { if let Some(_signal) = context.take_signal() { let _: Option<()> = try { let store_position = context.offset(self.0.opposite().into_offset())?; let store = context.get(store_position).and_then(get_store)?; let signal = store.signal.clone()?; drop(store); let target_position = context.offset(self.0.into_offset())?; context.send(target_position, self.0, signal); }; } if context.state() != State::Idle { context.next_state(); } } fn draw_simple(&self, ctx: DrawContext) -> TextChar { match self.0 { Direction::Down => TextChar::from_state('\u{25bd}', ctx.state), // WHITE DOWN-POINTING TRIANGLE Direction::Left => TextChar::from_state('\u{25c1}', ctx.state), // WHITE LEFT-POINTING TRIANGLE Direction::Right => TextChar::from_state('\u{25b7}', ctx.state), // WHITE RIGHT-POINTING TRIANGLE Direction::Up => TextChar::from_state('\u{25b3}', ctx.state), // WHITE UP-POINTING TRIANGLE } } } /// Tries to convert a [`FullTile`] to a [`Store`] fn get_store<'a>(full: VecRef<'a, FullTile>) -> Option> { VecRef::try_map(full, |tile| { let tile = tile.get().ok_or(())?; let store = tile.try_into().map_err(|_| ())?; Ok::<&Store, ()>(store) }).ok() }