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.

185 lines
4.7 KiB

//! 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