parity-zcash/script/src/stack.rs

357 lines
9.8 KiB
Rust

use std::ops;
use Error;
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Stack<T> {
data: Vec<T>,
}
impl<T> From<Vec<T>> for Stack<T> {
fn from(v: Vec<T>) -> Self {
Stack {
data: v
}
}
}
impl<T> ops::Deref for Stack<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> ops::DerefMut for Stack<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T> Stack<T> {
#[inline]
pub fn new() -> Self {
Stack {
data: Vec::new()
}
}
#[inline]
pub fn require(&self, len: usize) -> Result<(), Error> {
if self.data.len() < len {
return Err(Error::InvalidStackOperation);
}
Ok(())
}
#[inline]
pub fn last(&self) -> Result<&T, Error> {
self.data.last().ok_or(Error::InvalidStackOperation)
}
#[inline]
pub fn pop(&mut self) -> Result<T, Error> {
self.data.pop().ok_or(Error::InvalidStackOperation)
}
#[inline]
pub fn push(&mut self, value: T) {
self.data.push(value)
}
#[inline]
pub fn top(&self, i: usize) -> Result<&T, Error> {
let pos = i + 1;
try!(self.require(pos));
Ok(&self.data[self.data.len() - pos])
}
#[inline]
pub fn remove(&mut self, i: usize) -> Result<T, Error> {
let pos = i + 1;
try!(self.require(pos));
let to_remove = self.data.len() - pos;
Ok(self.data.remove(to_remove))
}
pub fn drop(&mut self, i: usize) -> Result<(), Error> {
try!(self.require(i));
let mut j = i;
while j > 0 {
self.data.pop();
j -= 1;
}
Ok(())
}
pub fn dup(&mut self, i: usize) -> Result<(), Error> where T: Clone {
try!(self.require(i));
let mut j = i;
while j > 0 {
let v = self.data[self.data.len() - i].clone();
self.data.push(v);
j -= 1;
}
Ok(())
}
pub fn over(&mut self, i: usize) -> Result<(), Error> where T: Clone {
let mut j = i * 2;
try!(self.require(j));
let to_clone = j;
while j > i {
let v = self.data[self.data.len() - to_clone].clone();
self.data.push(v);
j -= 1;
}
Ok(())
}
pub fn rot(&mut self, i: usize) -> Result<(), Error> {
let mut j = i * 3;
try!(self.require(j));
let to_remove = self.data.len() - j;
let limit = j - i;
while j > limit {
let v = self.data.remove(to_remove);
self.data.push(v);
j -= 1;
}
Ok(())
}
pub fn swap(&mut self, i: usize) -> Result<(), Error> {
let mut j = i * 2;
let mut k = i;
try!(self.require(j));
let len = self.data.len();
while k > 0 {
self.data.swap(len - j, len - k);
j -= 1;
k -= 1;
}
Ok(())
}
pub fn nip(&mut self) -> Result<(), Error> {
try!(self.require(2));
let len = self.data.len();
self.data.swap_remove(len - 2);
Ok(())
}
pub fn tuck(&mut self) -> Result<(), Error> where T: Clone {
try!(self.require(2));
let len = self.data.len();
let v = self.data[len - 1].clone();
self.data.insert(len - 2, v);
Ok(())
}
}
#[cfg(test)]
mod tests {
use Error;
use super::Stack;
#[test]
fn test_stack_require() {
let stack: Stack<u8> = vec![].into();
assert_eq!(stack.require(0), Ok(()));
assert_eq!(stack.require(1), Err(Error::InvalidStackOperation));
let stack: Stack<u8> = vec![0].into();
assert_eq!(stack.require(0), Ok(()));
assert_eq!(stack.require(1), Ok(()));
assert_eq!(stack.require(2), Err(Error::InvalidStackOperation));
let stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.require(0), Ok(()));
assert_eq!(stack.require(1), Ok(()));
assert_eq!(stack.require(2), Ok(()));
assert_eq!(stack.require(3), Err(Error::InvalidStackOperation));
}
#[test]
fn test_stack_last() {
let stack: Stack<u8> = vec![].into();
assert_eq!(stack.last(), Err(Error::InvalidStackOperation));
let stack: Stack<u8> = vec![0].into();
assert_eq!(stack.last(), Ok(&0));
let stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.last(), Ok(&5));
}
#[test]
fn test_stack_pop() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.pop(), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![].into());
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.pop(), Ok(0));
assert_eq!(stack, vec![].into());
let mut stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.pop(), Ok(5));
assert_eq!(stack.pop(), Ok(0));
assert_eq!(stack, vec![].into());
}
#[test]
fn test_stack_push() {
let mut stack: Stack<u8> = vec![].into();
stack.push(0);
assert_eq!(stack, vec![0].into());
stack.push(5);
assert_eq!(stack, vec![0, 5].into());
}
#[test]
fn test_stack_top() {
let stack: Stack<u8> = vec![].into();
assert_eq!(stack.top(0), Err(Error::InvalidStackOperation));
let stack: Stack<u8> = vec![0].into();
assert_eq!(stack.top(0), Ok(&0));
assert_eq!(stack.top(1), Err(Error::InvalidStackOperation));
let stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.top(0), Ok(&5));
assert_eq!(stack.top(1), Ok(&0));
assert_eq!(stack.top(2), Err(Error::InvalidStackOperation));
}
#[test]
fn test_stack_remove() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.remove(0), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![].into());
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.remove(0), Ok(0));
assert_eq!(stack.remove(0), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![].into());
let mut stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.remove(1), Ok(0));
assert_eq!(stack, vec![5].into());
assert_eq!(stack.remove(0), Ok(5));
assert_eq!(stack, vec![].into());
}
#[test]
fn test_stack_drop() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.drop(0), Ok(()));
let mut stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.drop(0), Ok(()));
assert_eq!(stack, vec![0, 5].into());
assert_eq!(stack.drop(3), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![0, 5].into());
assert_eq!(stack.drop(1), Ok(()));
assert_eq!(stack, vec![0].into());
let mut stack: Stack<u8> = vec![3, 5, 0].into();
assert_eq!(stack.drop(3), Ok(()));
assert_eq!(stack, vec![].into());
}
#[test]
fn test_stack_dup() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.dup(0), Ok(()));
assert_eq!(stack.dup(1), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![].into());
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.dup(0), Ok(()));
assert_eq!(stack.dup(2), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![0].into());
assert_eq!(stack.dup(1), Ok(()));
assert_eq!(stack, vec![0, 0].into());
assert_eq!(stack.dup(2), Ok(()));
assert_eq!(stack, vec![0, 0, 0, 0].into());
let mut stack: Stack<u8> = vec![0, 1].into();
assert_eq!(stack.dup(2), Ok(()));
assert_eq!(stack, vec![0, 1, 0, 1].into());
}
#[test]
fn test_stack_over() {
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.over(0), Ok(()));
assert_eq!(stack.over(1), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.over(2), Err(Error::InvalidStackOperation));
assert_eq!(stack.over(1), Ok(()));
assert_eq!(stack, vec![0, 5, 0].into());
assert_eq!(stack.over(1), Ok(()));
assert_eq!(stack, vec![0, 5, 0, 5].into());
let mut stack: Stack<u8> = vec![1, 2, 3, 4].into();
assert_eq!(stack.over(2), Ok(()));
assert_eq!(stack, vec![1, 2, 3, 4, 1, 2].into());
}
#[test]
fn test_stack_rot() {
let mut stack: Stack<u8> = vec![0, 5].into();
assert_eq!(stack.rot(0), Ok(()));
assert_eq!(stack.rot(1), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![0, 5].into());
let mut stack: Stack<u8> = vec![0, 1, 2].into();
assert_eq!(stack.rot(2), Err(Error::InvalidStackOperation));
assert_eq!(stack.rot(1), Ok(()));
assert_eq!(stack, vec![1, 2, 0].into());
let mut stack: Stack<u8> = vec![0, 1, 2, 3].into();
assert_eq!(stack.rot(1), Ok(()));
assert_eq!(stack, vec![0, 2, 3, 1].into());
let mut stack: Stack<u8> = vec![0, 1, 2, 3, 4, 5].into();
assert_eq!(stack.rot(3), Err(Error::InvalidStackOperation));
assert_eq!(stack.rot(2), Ok(()));
assert_eq!(stack, vec![2, 3, 4, 5, 0, 1].into());
}
#[test]
fn test_stack_swap() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.swap(0), Ok(()));
assert_eq!(stack, vec![].into());
assert_eq!(stack.swap(1), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0, 1, 2, 3].into();
assert_eq!(stack.swap(0), Ok(()));
assert_eq!(stack, vec![0, 1, 2, 3].into());
assert_eq!(stack.swap(1), Ok(()));
assert_eq!(stack, vec![0, 1, 3, 2].into());
assert_eq!(stack.swap(2), Ok(()));
assert_eq!(stack, vec![3, 2, 0, 1].into());
assert_eq!(stack.swap(3), Err(Error::InvalidStackOperation));
assert_eq!(stack, vec![3, 2, 0, 1].into());
}
#[test]
fn test_stack_nip() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.nip(), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.nip(), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0, 1].into();
assert_eq!(stack.nip(), Ok(()));
assert_eq!(stack, vec![1].into());
assert_eq!(stack.nip(), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0, 1, 2, 3].into();
assert_eq!(stack.nip(), Ok(()));
assert_eq!(stack, vec![0, 1, 3].into());
assert_eq!(stack.nip(), Ok(()));
assert_eq!(stack, vec![0, 3].into());
}
#[test]
fn test_stack_tuck() {
let mut stack: Stack<u8> = vec![].into();
assert_eq!(stack.tuck(), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0].into();
assert_eq!(stack.tuck(), Err(Error::InvalidStackOperation));
let mut stack: Stack<u8> = vec![0, 1].into();
assert_eq!(stack.tuck(), Ok(()));
assert_eq!(stack, vec![1, 0, 1].into());
assert_eq!(stack.tuck(), Ok(()));
assert_eq!(stack, vec![1, 1, 0, 1].into());
let mut stack: Stack<u8> = vec![0, 1, 2, 3].into();
assert_eq!(stack.tuck(), Ok(()));
assert_eq!(stack, vec![0, 1, 3, 2, 3].into());
assert_eq!(stack.tuck(), Ok(()));
assert_eq!(stack, vec![0, 1, 3, 3, 2, 3].into());
}
}