You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.2 KiB
104 lines
3.2 KiB
2 years ago
|
//! 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<Signal>,
|
||
|
}
|
||
|
|
||
|
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::<Self>(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<'a, Store>> {
|
||
|
VecRef::try_map(full, |tile| {
|
||
|
let tile = tile.get().ok_or(())?;
|
||
|
let store = tile.try_into().map_err(|_| ())?;
|
||
|
Ok::<&Store, ()>(store)
|
||
|
}).ok()
|
||
|
}
|