|
|
|
//! Basic stack operations: push a value, pop a value, swap, etc.
|
|
|
|
|
|
|
|
use crate::prelude::*;
|
|
|
|
use crate::tile::prelude::*;
|
|
|
|
|
|
|
|
/// Pushes a value on the stack, then lets the signal through
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub struct Push {
|
|
|
|
value: Value
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Push {
|
|
|
|
pub fn new(value: Value) -> Self {
|
|
|
|
Self {
|
|
|
|
value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Push {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new(Value::Number(0.0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tile for Push {
|
|
|
|
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
|
|
|
|
if let Some(mut signal) = context.take_signal() {
|
|
|
|
signal.push(self.value.clone());
|
|
|
|
|
|
|
|
if let Some(coords) = context.offset(signal.direction().into_offset()) {
|
|
|
|
let _ = context.send(coords, signal.direction(), signal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if context.state() != State::Idle {
|
|
|
|
context.next_state();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
|
|
|
|
TextChar::from_state('P', ctx.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Pops `n` values from the top of the stack, then lets the signal through
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub struct Pop {
|
|
|
|
amount: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Pop {
|
|
|
|
pub fn new(amount: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
amount
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Pop {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tile for Pop {
|
|
|
|
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
|
|
|
|
if let Some(mut signal) = context.take_signal() {
|
|
|
|
for _ in 0..self.amount {
|
|
|
|
let _ = signal.pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(coords) = context.offset(signal.direction().into_offset()) {
|
|
|
|
let _ = context.send(coords, signal.direction(), signal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if context.state() != State::Idle {
|
|
|
|
context.next_state();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
|
|
|
|
if self.amount == 1 {
|
|
|
|
TextChar::from_state('\u{2c63}', ctx.state) // Latin Capital Letter P with Stroke
|
|
|
|
} else {
|
|
|
|
TextChar::from_state(ctx.blink.scroll(&format!("\u{2c63}\u{2c63}\u{2c63}{}", self.amount)), ctx.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reverses the order of the top `n` values from the stack, then lets the signal through
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub struct Swap {
|
|
|
|
amount: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Swap {
|
|
|
|
pub fn new(amount: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
amount
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Swap {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new(2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tile for Swap {
|
|
|
|
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
|
|
|
|
if let Some(mut signal) = context.take_signal() {
|
|
|
|
let len = signal.stack().len();
|
|
|
|
let last_elements = if self.amount > len {
|
|
|
|
&mut signal.stack_mut()[..]
|
|
|
|
} else {
|
|
|
|
&mut signal.stack_mut()[(len - self.amount)..len]
|
|
|
|
};
|
|
|
|
|
|
|
|
last_elements.reverse();
|
|
|
|
|
|
|
|
if let Some(coords) = context.offset(signal.direction().into_offset()) {
|
|
|
|
let _ = context.send(coords, signal.direction(), signal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if context.state() != State::Idle {
|
|
|
|
context.next_state();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
|
|
|
|
if self.amount == 2 {
|
|
|
|
TextChar::from_state('s', ctx.state)
|
|
|
|
} else {
|
|
|
|
TextChar::from_state(ctx.blink.scroll(&format!("sss{}", self.amount)), ctx.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Duplicates the nth element from the stack, pushing it back on top
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
|
|
|
|
pub struct Duplicate {
|
|
|
|
offset: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Duplicate {
|
|
|
|
pub fn new(offset: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
offset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tile for Duplicate {
|
|
|
|
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
|
|
|
|
if let Some(mut signal) = context.take_signal() {
|
|
|
|
if self.offset < signal.len() {
|
|
|
|
let index = signal.len() - self.offset - 1;
|
|
|
|
signal.push(signal.stack()[index].clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(coords) = context.offset(signal.direction().into_offset()) {
|
|
|
|
let _ = context.send(coords, signal.direction(), signal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if context.state() != State::Idle {
|
|
|
|
context.next_state();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_simple(&self, ctx: DrawContext) -> TextChar {
|
|
|
|
if self.offset == 0 {
|
|
|
|
TextChar::from_state('d', ctx.state)
|
|
|
|
} else {
|
|
|
|
TextChar::from_state(ctx.blink.scroll(&format!("ddd{}", self.offset)), ctx.state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: SwapN, RotateLeft, RotateRight, RotateLeftN, RotateRightN
|