<commit_before>//! Manipulations and data types that represent polynomial

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules)]

extern crate num;

use std::{cmp, fmt};
use std::iter::{AdditiveIterator, MultiplicativeIterator};
use num::{Zero, One};

/// Polynomial expression
#[deriving(Eq, PartialEq, Clone, Show)]
pub struct Polynomial<T> { data: Vec<T> }

impl<T: Zero> Polynomial<T> {
    /// Creates new `Polynomial`.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1i, 2, 3]);
    /// assert_eq!("1+2*x+3*x^2", poly.pretty("x"));
    /// ```
    #[inline]
    pub fn new(mut data: Vec<T>) -> Polynomial<T> {
        while let Some(true) = data.last().map(|x| x.is_zero()) {
            let _ = data.pop();
        }
        Polynomial { data: data }
    }
}

impl<T: Zero + One + Clone> Polynomial<T> {
    /// Evaluates the polynomial value.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1i, 2, 3]);
    /// assert_eq!(1, poly.eval(0));
    /// assert_eq!(6, poly.eval(1));
    /// assert_eq!(17, poly.eval(2));
    /// ```
    #[inline]
    pub fn eval(&self, x: T) -> T {
        let mut sum: T = Zero::zero();
        let mut x_n: T = One::one();
        for n in self.data.iter() {
            sum = sum + n.clone() * x_n.clone();
            x_n = x_n * x.clone();
        }
        sum
    }
}

impl<T> Polynomial<T> {
    /// Gets the slice of internal data.
    #[inline]
    pub fn data(&self) -> &[T] { self.data.as_slice() }
}

impl<T: Zero + One + Eq + Neg<T> + Ord + fmt::Show + Clone> Polynomial<T> {
    /// Pretty prints the polynomial.
    pub fn pretty(&self, x: &str) -> String {
        if self.is_zero() { return "0".to_string() }

        let one = One::one();
        let mut s = Vec::new();
        for (i, n) in self.data.iter().enumerate() {
            // output n*x^i / -n*x^i
            if n.is_zero() { continue }

            let term = if i.is_zero() {
                n.to_string()
            } else if i == 1 {
                if (*n) == one { x.to_string() }
                else if (*n) == -one.clone() { format!("-{}", x) }
                else { format!("{}*{}", n.to_string(), x) }
            } else {
                if (*n) == one { format!("{}^{}", x, i) }
                else if (*n) == -one.clone() { format!("-{}^{}", x, i) }
                else { format!("{}*{}^{}", n.to_string(), x, i) }
            };

            if s.len() > 0 && (*n) > Zero::zero() { s.push("+".to_string()); }
            s.push(term);
        }

        s.concat()
    }
}

impl<'a, T: Neg<T> + Zero + Clone> Neg<Polynomial<T>> for Polynomial<T> {
    #[inline]
    fn neg(self) -> Polynomial<T> { -&self }
}

impl<'a, T: Neg<T> + Zero + Clone> Neg<Polynomial<T>> for &'a Polynomial<T> {
    #[inline]
    fn neg(self) -> Polynomial<T> {
        Polynomial::new(self.data.iter().map(|x| -x.clone()).collect())
    }
}

macro_rules! forward_val_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<Lhs, Rhs, Result> $imp<Polynomial<Rhs>, Polynomial<Result>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<Result> {
                (&self).$method(&other)
            }
        }
    }
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs, Result> $imp<Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<Result> {
                self.$method(&other)
            }
        }
    }
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs, Result> $imp<&'a Polynomial<Rhs>, Polynomial<Result>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
                (&self).$method(other)
            }
        }
    }
}

macro_rules! forward_all_binop {
    (impl $imp:ident, $method:ident) => {
        forward_val_val_binop!(impl $imp, $method);
        forward_ref_val_binop!(impl $imp, $method);
        forward_val_ref_binop!(impl $imp, $method);
    };
}

forward_all_binop!(impl Add, add);

impl<'a, 'b, Lhs, Rhs, Result> Add<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Add<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn add(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        let max_len = cmp::max(self.data.len(), other.data.len());
        let min_len = cmp::min(self.data.len(), other.data.len());

        let mut sum = Vec::with_capacity(max_len);
        for i in range(0, min_len) {
            sum.push(self.data[i].clone() + other.data[i].clone());
        }

        if self.data.len() <= other.data.len() {
            for i in range(min_len, max_len) {
                sum.push(num::zero::<Lhs>() + other.data[i].clone());
            }
        } else {
            for i in range(min_len, max_len) {
                sum.push(self.data[i].clone() + num::zero::<Rhs>());
            }
        }

        Polynomial::new(sum)
    }
}

forward_all_binop!(impl Sub, sub);

impl<'a, 'b, Lhs, Rhs, Result> Sub<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Sub<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn sub(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        let min_len = cmp::min(self.data.len(), other.data.len());
        let max_len = cmp::max(self.data.len(), other.data.len());

        let mut sub = Vec::with_capacity(max_len);
        for i in range(0, min_len) {
            sub.push(self.data[i].clone() - other.data[i].clone());
        }
        if self.data.len() <= other.data.len() {
            for i in range(min_len, max_len) {
                sub.push(num::zero::<Lhs>() - other.data[i].clone())
            }
        } else {
            for i in range(min_len, max_len) {
                sub.push(self.data[i].clone() - num::zero::<Rhs>())
            }
        }
        Polynomial::new(sub)
    }
}

forward_all_binop!(impl Mul, mul);

impl<'a, 'b, Lhs, Rhs, Result> Mul<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Mul<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn mul(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        if self.is_zero() || other.is_zero() { return Polynomial::new(vec![]) }

        let slen = self.data.len();
        let olen = other.data.len();
        let prod = Vec::from_fn(slen + olen - 1, |i| {
            let mut p = num::zero::<Result>();
            for k in range(0, slen) {
                if i - k >= olen { continue; }
                p = p + self.data[k].clone() * other.data[i - k].clone();
            }
            p
        });
        Polynomial::new(prod)
    }
}

impl<T: Zero + Clone> Zero for Polynomial<T> {
    #[inline]
    fn zero() -> Polynomial<T> { Polynomial { data: vec![] } }
    #[inline]
    fn is_zero(&self) -> bool { self.data.is_empty() }
}

impl<T: Zero + One + Clone> One for Polynomial<T> {
    #[inline]
    fn one() -> Polynomial<T> { Polynomial { data: vec![One::one()] } }
}

impl<A: Zero + Add<A, A> + Clone, T: Iterator<Polynomial<A>>> AdditiveIterator<Polynomial<A>> for T {
    #[inline]
    fn sum(self) -> Polynomial<A> {
        let init: Polynomial<A> = Zero::zero();
        self.fold(init, |acc, x| acc + x)
    }
}

impl<A: Zero + One + Mul<A, A> + Clone, T: Iterator<Polynomial<A>>> MultiplicativeIterator<Polynomial<A>> for T {
    #[inline]
    fn product(self) -> Polynomial<A> {
        let init: Polynomial<A> = One::one();
        self.fold(init, |acc, x| acc * x)
    }
}

#[cfg(test)]
mod tests {
    use super::Polynomial;

    #[test]
    fn new() {
        fn check(dst: Vec<int>, src: Vec<int>) {
            assert_eq!(dst, Polynomial::new(src).data);
        }
        check(vec![1, 2, 3], vec![1, 2, 3]);
        check(vec![1, 2, 3], vec![1, 2, 3, 0, 0]);
        check(vec![], vec![0, 0, 0]);
    }

    #[test]
    fn neg_add_sub() {
        fn check(a: &[int], b: &[int], c: &[int]) {
            fn check_eq(a: &Polynomial<int>, b: &Polynomial<int>) {
                assert_eq!(*a, *b);
                assert_eq!(-a, -b);
            }
            fn check_add(sum: &Polynomial<int>, a: &Polynomial<int>, b: &Polynomial<int>) {
                check_eq(sum, &(a + b));
                check_eq(sum, &(b + a));
            }
            fn check_sub(sum: &Polynomial<int>, a: &Polynomial<int>, b: &Polynomial<int>) {
                check_eq(a, &(sum - b));
                check_eq(b, &(sum - a));
            }

            let a = &Polynomial::new(a.to_vec());
            let b = &Polynomial::new(b.to_vec());
            let c = &Polynomial::new(c.to_vec());
            check_add(c, a, b);
            check_add(&(-c), &(-a), &(-b));
            check_sub(c, a, b);
            check_sub(&(-c), &(-a), &(-b));
        }
        check(&[], &[], &[]);
        check(&[], &[1], &[1]);
        check(&[1], &[1], &[2]);
        check(&[1, 0, 1], &[1], &[2, 0, 1]);
        check(&[1, 0, -1], &[-1, 0, 1], &[]);
    }

    #[test]
    fn mul() {
        fn check(a: &[int], b: &[int], c: &[int]) {
            let a = Polynomial::new(a.to_vec());
            let b = Polynomial::new(b.to_vec());
            let c = Polynomial::new(c.to_vec());
            assert_eq!(c, &a * &b);
            assert_eq!(c, &b * &a);
        }
        check(&[], &[], &[]);
        check(&[0, 0], &[], &[]);
        check(&[0, 0], &[1], &[]);
        check(&[1, 0], &[1], &[1]);
        check(&[1, 0, 1], &[1], &[1, 0, 1]);
        check(&[1, 1], &[1, 1], &[1, 2, 1]);
        check(&[1, 1], &[1, 0, 1], &[1, 1, 1, 1]);
        check(&[0, 0, 1], &[0, 0, 1], &[0, 0, 0, 0, 1]);
    }

    #[test]
    fn eval() {
        fn check(pol: &[int], f: |int| -> int) {
            for n in range(-10i, 10) {
                assert_eq!(f(n), Polynomial::new(pol.to_vec()).eval(n));
            }
        }
        check(&[], |_x| 0);
        check(&[1], |_x| 1);
        check(&[1, 1], |x| x + 1);
        check(&[0, 1], |x| x);
        check(&[10, -10, 10], |x| 10*x*x - 10 * x + 10);
    }

    #[test]
    fn pretty() {
        fn check(slice: &[int], s: &str) {
            assert_eq!(s.to_string(), Polynomial::new(slice.to_vec()).pretty("x"));
        }
        check(&[0], "0");
        check(&[1], "1");
        check(&[1, 1], "1+x");
        check(&[1, 1, 1], "1+x+x^2");
        check(&[2, 2, 2], "2+2*x+2*x^2");
        check(&[0, 0, 0, 1], "x^3");
        check(&[0, 0, 0, -1], "-x^3");
        check(&[-1, 0, 0, -1], "-1-x^3");
        check(&[-1, 1, 0, -1], "-1+x-x^3");
        check(&[-1, 1, -1, -1], "-1+x-x^2-x^3");
    }
}
<commit_msg>polynomial: Remove `uint` or `int` usage as general integer<commit_after>//! Manipulations and data types that represent polynomial

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(macro_rules)]

extern crate num;

use std::{cmp, fmt};
use std::iter::{AdditiveIterator, MultiplicativeIterator};
use num::{Zero, One};

/// Polynomial expression
#[deriving(Eq, PartialEq, Clone, Show)]
pub struct Polynomial<T> { data: Vec<T> }

impl<T: Zero> Polynomial<T> {
    /// Creates new `Polynomial`.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1i, 2, 3]);
    /// assert_eq!("1+2*x+3*x^2", poly.pretty("x"));
    /// ```
    #[inline]
    pub fn new(mut data: Vec<T>) -> Polynomial<T> {
        while let Some(true) = data.last().map(|x| x.is_zero()) {
            let _ = data.pop();
        }
        Polynomial { data: data }
    }
}

impl<T: Zero + One + Clone> Polynomial<T> {
    /// Evaluates the polynomial value.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1i, 2, 3]);
    /// assert_eq!(1, poly.eval(0));
    /// assert_eq!(6, poly.eval(1));
    /// assert_eq!(17, poly.eval(2));
    /// ```
    #[inline]
    pub fn eval(&self, x: T) -> T {
        let mut sum: T = Zero::zero();
        let mut x_n: T = One::one();
        for n in self.data.iter() {
            sum = sum + n.clone() * x_n.clone();
            x_n = x_n * x.clone();
        }
        sum
    }
}

impl<T> Polynomial<T> {
    /// Gets the slice of internal data.
    #[inline]
    pub fn data(&self) -> &[T] { self.data.as_slice() }
}

impl<T: Zero + One + Eq + Neg<T> + Ord + fmt::Show + Clone> Polynomial<T> {
    /// Pretty prints the polynomial.
    pub fn pretty(&self, x: &str) -> String {
        if self.is_zero() { return "0".to_string() }

        let one = One::one();
        let mut s = Vec::new();
        for (i, n) in self.data.iter().enumerate() {
            // output n*x^i / -n*x^i
            if n.is_zero() { continue }

            let term = if i.is_zero() {
                n.to_string()
            } else if i == 1 {
                if (*n) == one { x.to_string() }
                else if (*n) == -one.clone() { format!("-{}", x) }
                else { format!("{}*{}", n.to_string(), x) }
            } else {
                if (*n) == one { format!("{}^{}", x, i) }
                else if (*n) == -one.clone() { format!("-{}^{}", x, i) }
                else { format!("{}*{}^{}", n.to_string(), x, i) }
            };

            if s.len() > 0 && (*n) > Zero::zero() { s.push("+".to_string()); }
            s.push(term);
        }

        s.concat()
    }
}

impl<'a, T: Neg<T> + Zero + Clone> Neg<Polynomial<T>> for Polynomial<T> {
    #[inline]
    fn neg(self) -> Polynomial<T> { -&self }
}

impl<'a, T: Neg<T> + Zero + Clone> Neg<Polynomial<T>> for &'a Polynomial<T> {
    #[inline]
    fn neg(self) -> Polynomial<T> {
        Polynomial::new(self.data.iter().map(|x| -x.clone()).collect())
    }
}

macro_rules! forward_val_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<Lhs, Rhs, Result> $imp<Polynomial<Rhs>, Polynomial<Result>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<Result> {
                (&self).$method(&other)
            }
        }
    }
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs, Result> $imp<Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<Result> {
                self.$method(&other)
            }
        }
    }
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs, Result> $imp<&'a Polynomial<Rhs>, Polynomial<Result>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
        {
            #[inline]
            fn $method(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
                (&self).$method(other)
            }
        }
    }
}

macro_rules! forward_all_binop {
    (impl $imp:ident, $method:ident) => {
        forward_val_val_binop!(impl $imp, $method);
        forward_ref_val_binop!(impl $imp, $method);
        forward_val_ref_binop!(impl $imp, $method);
    };
}

forward_all_binop!(impl Add, add);

impl<'a, 'b, Lhs, Rhs, Result> Add<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Add<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn add(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        let max_len = cmp::max(self.data.len(), other.data.len());
        let min_len = cmp::min(self.data.len(), other.data.len());

        let mut sum = Vec::with_capacity(max_len);
        for i in range(0, min_len) {
            sum.push(self.data[i].clone() + other.data[i].clone());
        }

        if self.data.len() <= other.data.len() {
            for i in range(min_len, max_len) {
                sum.push(num::zero::<Lhs>() + other.data[i].clone());
            }
        } else {
            for i in range(min_len, max_len) {
                sum.push(self.data[i].clone() + num::zero::<Rhs>());
            }
        }

        Polynomial::new(sum)
    }
}

forward_all_binop!(impl Sub, sub);

impl<'a, 'b, Lhs, Rhs, Result> Sub<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Sub<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn sub(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        let min_len = cmp::min(self.data.len(), other.data.len());
        let max_len = cmp::max(self.data.len(), other.data.len());

        let mut sub = Vec::with_capacity(max_len);
        for i in range(0, min_len) {
            sub.push(self.data[i].clone() - other.data[i].clone());
        }
        if self.data.len() <= other.data.len() {
            for i in range(min_len, max_len) {
                sub.push(num::zero::<Lhs>() - other.data[i].clone())
            }
        } else {
            for i in range(min_len, max_len) {
                sub.push(self.data[i].clone() - num::zero::<Rhs>())
            }
        }
        Polynomial::new(sub)
    }
}

forward_all_binop!(impl Mul, mul);

impl<'a, 'b, Lhs, Rhs, Result> Mul<&'b Polynomial<Rhs>, Polynomial<Result>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Mul<Rhs, Result> + Clone, Rhs: Zero + Clone, Result: Zero
{
    fn mul(self, other: &Polynomial<Rhs>) -> Polynomial<Result> {
        if self.is_zero() || other.is_zero() { return Polynomial::new(vec![]) }

        let slen = self.data.len();
        let olen = other.data.len();
        let prod = Vec::from_fn(slen + olen - 1, |i| {
            let mut p = num::zero::<Result>();
            for k in range(0, slen) {
                if i - k >= olen { continue; }
                p = p + self.data[k].clone() * other.data[i - k].clone();
            }
            p
        });
        Polynomial::new(prod)
    }
}

impl<T: Zero + Clone> Zero for Polynomial<T> {
    #[inline]
    fn zero() -> Polynomial<T> { Polynomial { data: vec![] } }
    #[inline]
    fn is_zero(&self) -> bool { self.data.is_empty() }
}

impl<T: Zero + One + Clone> One for Polynomial<T> {
    #[inline]
    fn one() -> Polynomial<T> { Polynomial { data: vec![One::one()] } }
}

impl<A: Zero + Add<A, A> + Clone, T: Iterator<Polynomial<A>>> AdditiveIterator<Polynomial<A>> for T {
    #[inline]
    fn sum(self) -> Polynomial<A> {
        let init: Polynomial<A> = Zero::zero();
        self.fold(init, |acc, x| acc + x)
    }
}

impl<A: Zero + One + Mul<A, A> + Clone, T: Iterator<Polynomial<A>>> MultiplicativeIterator<Polynomial<A>> for T {
    #[inline]
    fn product(self) -> Polynomial<A> {
        let init: Polynomial<A> = One::one();
        self.fold(init, |acc, x| acc * x)
    }
}

#[cfg(test)]
mod tests {
    use super::Polynomial;

    #[test]
    fn new() {
        fn check(dst: Vec<i32>, src: Vec<i32>) {
            assert_eq!(dst, Polynomial::new(src).data);
        }
        check(vec![1, 2, 3], vec![1, 2, 3]);
        check(vec![1, 2, 3], vec![1, 2, 3, 0, 0]);
        check(vec![], vec![0, 0, 0]);
    }

    #[test]
    fn neg_add_sub() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            fn check_eq(a: &Polynomial<i32>, b: &Polynomial<i32>) {
                assert_eq!(*a, *b);
                assert_eq!(-a, -b);
            }
            fn check_add(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(sum, &(a + b));
                check_eq(sum, &(b + a));
            }
            fn check_sub(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(a, &(sum - b));
                check_eq(b, &(sum - a));
            }

            let a = &Polynomial::new(a.to_vec());
            let b = &Polynomial::new(b.to_vec());
            let c = &Polynomial::new(c.to_vec());
            check_add(c, a, b);
            check_add(&(-c), &(-a), &(-b));
            check_sub(c, a, b);
            check_sub(&(-c), &(-a), &(-b));
        }
        check(&[], &[], &[]);
        check(&[], &[1], &[1]);
        check(&[1], &[1], &[2]);
        check(&[1, 0, 1], &[1], &[2, 0, 1]);
        check(&[1, 0, -1], &[-1, 0, 1], &[]);
    }

    #[test]
    fn mul() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            let a = Polynomial::new(a.to_vec());
            let b = Polynomial::new(b.to_vec());
            let c = Polynomial::new(c.to_vec());
            assert_eq!(c, &a * &b);
            assert_eq!(c, &b * &a);
        }
        check(&[], &[], &[]);
        check(&[0, 0], &[], &[]);
        check(&[0, 0], &[1], &[]);
        check(&[1, 0], &[1], &[1]);
        check(&[1, 0, 1], &[1], &[1, 0, 1]);
        check(&[1, 1], &[1, 1], &[1, 2, 1]);
        check(&[1, 1], &[1, 0, 1], &[1, 1, 1, 1]);
        check(&[0, 0, 1], &[0, 0, 1], &[0, 0, 0, 0, 1]);
    }

    #[test]
    fn eval() {
        fn check(pol: &[i32], f: |i32| -> i32) {
            for n in range(-10, 10) {
                assert_eq!(f(n), Polynomial::new(pol.to_vec()).eval(n));
            }
        }
        check(&[], |_x| 0);
        check(&[1], |_x| 1);
        check(&[1, 1], |x| x + 1);
        check(&[0, 1], |x| x);
        check(&[10, -10, 10], |x| 10*x*x - 10 * x + 10);
    }

    #[test]
    fn pretty() {
        fn check(slice: &[i32], s: &str) {
            assert_eq!(s.to_string(), Polynomial::new(slice.to_vec()).pretty("x"));
        }
        check(&[0], "0");
        check(&[1], "1");
        check(&[1, 1], "1+x");
        check(&[1, 1, 1], "1+x+x^2");
        check(&[2, 2, 2], "2+2*x+2*x^2");
        check(&[0, 0, 0, 1], "x^3");
        check(&[0, 0, 0, -1], "-x^3");
        check(&[-1, 0, 0, -1], "-1-x^3");
        check(&[-1, 1, 0, -1], "-1+x-x^3");
        check(&[-1, 1, -1, -1], "-1+x-x^2-x^3");
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//! One of cita's main core components is to execute transaction,
//! create contracts, maintain world state trees, and send executed
//! result block to chain.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     | Queue    | PubModule | Message Type               |
//!     | -------- | --------- | ------------------         |
//!     | executor | Chain     | Request                    |
//!     | executor | Chain     | Richstatus                 |
//!     | executor | Chain     | StateSignal                |
//!     | executor | Chain     | LocalSync                  |
//!     | executor | Consensus | BlockWithProof             |
//!     | executor | Consensus | SignedProposal             |
//!     | executor | Consensus | MiscellaneousReq           |
//!     | executor | Net       | SyncResponse               |
//!     | executor | Net       | SignedProposal             |
//!     | executor | Snapshot  | SnapshotReq                |
//!
//! 2. Publish channel
//!
//!     | Queue    | PubModule | SubModule | Message Type   |
//!     | -------- | --------- | --------- | -------------- |
//!     | executor | Executor  | Snapshot  | SnapshotResp   |
//!     | executor | Executor  | Jsonrpc   | Response       |
//!     | executor | Executor  | Chain     | ExecutedResult |
//!     | executor | Executor  | Auth      | Miscellaneous  |
//!     | executor | Executor  | Auth      | BlackList      |
//!     | executor | Executor  | Chain     | StateSignal    |
//!
//! ### Key behavior
//!
//! key struct:
//!
//! - `Postman`: `postman::Postman`
//! - [`Executor`]
//! - [`GlobalSysConfig`]
//! - [`Genesis`]
//! - [`Contract`]
//! - [`Account`]
//! - `AccountEntry`: `core_executor::state::AccountEntry`
//! - [`State`]
//! - [`StateDB`]
//!
//! This is currently the most complex module that maintains the current state of
//! the entire chain and caches some data, keeps the hash values of the last 256
//! blocks and the information of each block (gas_limit/quota, etc.) in memory,
//! holds the current block map(heigh, block).
//!
//! Of course there is an evm interface in this module.
//!
//! The contract/transaction submission is first cached in memory before being committed
//! to the stateDB (disk).
//!
//! [`Executor`]: ../core_executor/libexecutor/executor/struct.Executor.html
//! [`GlobalSysConfig`]: ../core_executor/libexecutor/executor/struct.GlobalSysConfig.html
//! [`Genesis`]: ../core_executor/libexecutor/genesis/struct.Genesis.html
//! [`Contract`]: ../core_executor/libexecutor/genesis/struct.Contract.html
//! [`Account`]: ../core_executor/state/account/struct.Account.html
//! [`State`]: ../core_executor/state/struct.State.html
//! [`StateDB`]: ../core_executor/state_db/struct.StateDB.html
//!

#[cfg(test)]
extern crate cita_crypto;
extern crate cita_directories;
extern crate cita_types;
extern crate clap;
extern crate common_types as types;
extern crate core_executor as core;
#[macro_use]
extern crate crossbeam_channel;
extern crate db as cita_db;
extern crate dotenv;
extern crate error;
extern crate evm;
extern crate grpc;
#[cfg(test)]
extern crate hashable;
extern crate jsonrpc_types;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate proof;
extern crate pubsub;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate util;

use cita_directories::DataPath;
use clap::App;
use core::contracts::grpc::grpc_vm_adapter;
use core::libexecutor::executor::Executor;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::start_pubsub;
use std::sync::mpsc::channel;
use std::thread;
use util::set_panic_handler;

mod backlogs;
mod postman;
mod snapshot;
#[cfg(test)]
mod tests;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

#[derive(Debug, PartialEq, Deserialize)]
pub struct Options {
    prooftype: u8,
    grpc_port: u16,
    journaldb_type: String,
    genesis_path: String,
    statedb_cache_size: usize,
    eth_compatibility: bool,
}

impl Options {
    pub fn default() -> Self {
        Options {
            prooftype: 2,
            grpc_port: 5000,
            journaldb_type: String::from("archive"),
            genesis_path: String::from("genesis.json"),
            statedb_cache_size: 5 * 1024 * 1024,
            eth_compatibility: false,
        }
    }

    pub fn load(path: &str) -> Self {
        parse_config!(Options, path)
    }
}

fn main() {
    micro_service_init!("cita-executor", "CITA:executor");
    let matches = App::new("executor")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-c, --config=[FILE] 'Sets a switch config file'")
        .get_matches();
    let config_path = matches.value_of("config").unwrap_or("executor.toml");
    let options = Options::load(config_path);
    info!("Version: {}", get_build_info_str(true));
    info!("Config: {:?}", options);

    // start pubsub thread
    let (forward_req_sender, forward_req_receiver) = channel();
    let (forward_resp_sender, forward_resp_receiver) = channel();
    let (mq_req_sender, mq_req_receiver) = crossbeam_channel::unbounded();
    let (mq_resp_sender, mq_resp_receiver) = crossbeam_channel::unbounded();
    let (fsm_req_sender, fsm_req_receiver) = crossbeam_channel::unbounded();
    let (fsm_resp_sender, fsm_resp_receiver) = crossbeam_channel::unbounded();
    let (command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0);
    let (command_resp_sender, command_resp_receiver) = crossbeam_channel::bounded(0);
    start_pubsub(
        "executor",
        routing_key!([
            Chain >> Request,
            Chain >> RichStatus,
            Chain >> StateSignal,
            Chain >> LocalSync,
            Consensus >> BlockWithProof,
            Consensus >> SignedProposal,
            Net >> SyncResponse,
            Snapshot >> SnapshotReq,
            Auth >> MiscellaneousReq,
        ]),
        forward_req_sender,
        forward_resp_receiver,
    );

    // start threads to forward messages between mpsc::channel and crosebeam::channel
    thread::spawn(move || loop {
        match forward_req_receiver.recv() {
            Ok(message) => mq_req_sender.send(message),
            Err(_) => return,
        }
    });
    thread::spawn(move || loop {
        match mq_resp_receiver.recv() {
            Some(message) => forward_resp_sender.send(message).unwrap(),
            None => return,
        }
    });

    // start grpc server thread background
    let server = grpc_vm_adapter::vm_grpc_server(
        options.grpc_port,
        command_req_sender.clone(),
        command_resp_receiver.clone(),
    )
    .expect("failed to initialize grpc server");
    thread::spawn(move || {
        grpc_vm_adapter::serve(&server);
    });

    loop {
        // start executor thread
        // TODO consider to store `data_path` within executor.toml
        let data_path = DataPath::root_node_path();
        let mut executor = Executor::init(
            &options.genesis_path,
            &options.journaldb_type,
            options.statedb_cache_size,
            data_path,
            fsm_req_receiver.clone(),
            fsm_resp_sender.clone(),
            command_req_receiver.clone(),
            command_resp_sender.clone(),
            options.eth_compatibility,
        );
        let current_height = executor.get_current_height();
        let current_hash = executor.get_current_hash();
        let handle = thread::spawn(move || {
            executor.do_loop();
        });

        // start postman thread
        let mut postman = Postman::new(
            current_height,
            current_hash,
            mq_req_receiver.clone(),
            mq_resp_sender.clone(),
            fsm_req_sender.clone(),
            fsm_resp_receiver.clone(),
            command_req_sender.clone(),
            command_resp_receiver.clone(),
        );
        postman.do_loop();

        handle.join().expect(
            "
            Executor exit cause Command::Exit was sent by postman inside.

            When postman roll back the whole cita-chain to an old height,
            it would tell executor thread to reset the `CURRNENT_HASH` to the
            target height, and then exit, both with postman. Main thread would
            re-run postman and executor inside this loop statement.
        ",
        );
    }
}
<commit_msg>Use crossbeam for cita-executor.<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! ## Summary
//! One of cita's main core components is to execute transaction,
//! create contracts, maintain world state trees, and send executed
//! result block to chain.
//!
//! ### Message queuing situation
//!
//! 1. Subscribe channel
//!
//!     | Queue    | PubModule | Message Type               |
//!     | -------- | --------- | ------------------         |
//!     | executor | Chain     | Request                    |
//!     | executor | Chain     | Richstatus                 |
//!     | executor | Chain     | StateSignal                |
//!     | executor | Chain     | LocalSync                  |
//!     | executor | Consensus | BlockWithProof             |
//!     | executor | Consensus | SignedProposal             |
//!     | executor | Consensus | MiscellaneousReq           |
//!     | executor | Net       | SyncResponse               |
//!     | executor | Net       | SignedProposal             |
//!     | executor | Snapshot  | SnapshotReq                |
//!
//! 2. Publish channel
//!
//!     | Queue    | PubModule | SubModule | Message Type   |
//!     | -------- | --------- | --------- | -------------- |
//!     | executor | Executor  | Snapshot  | SnapshotResp   |
//!     | executor | Executor  | Jsonrpc   | Response       |
//!     | executor | Executor  | Chain     | ExecutedResult |
//!     | executor | Executor  | Auth      | Miscellaneous  |
//!     | executor | Executor  | Auth      | BlackList      |
//!     | executor | Executor  | Chain     | StateSignal    |
//!
//! ### Key behavior
//!
//! key struct:
//!
//! - `Postman`: `postman::Postman`
//! - [`Executor`]
//! - [`GlobalSysConfig`]
//! - [`Genesis`]
//! - [`Contract`]
//! - [`Account`]
//! - `AccountEntry`: `core_executor::state::AccountEntry`
//! - [`State`]
//! - [`StateDB`]
//!
//! This is currently the most complex module that maintains the current state of
//! the entire chain and caches some data, keeps the hash values of the last 256
//! blocks and the information of each block (gas_limit/quota, etc.) in memory,
//! holds the current block map(heigh, block).
//!
//! Of course there is an evm interface in this module.
//!
//! The contract/transaction submission is first cached in memory before being committed
//! to the stateDB (disk).
//!
//! [`Executor`]: ../core_executor/libexecutor/executor/struct.Executor.html
//! [`GlobalSysConfig`]: ../core_executor/libexecutor/executor/struct.GlobalSysConfig.html
//! [`Genesis`]: ../core_executor/libexecutor/genesis/struct.Genesis.html
//! [`Contract`]: ../core_executor/libexecutor/genesis/struct.Contract.html
//! [`Account`]: ../core_executor/state/account/struct.Account.html
//! [`State`]: ../core_executor/state/struct.State.html
//! [`StateDB`]: ../core_executor/state_db/struct.StateDB.html
//!

#[cfg(test)]
extern crate cita_crypto;
extern crate cita_directories;
extern crate cita_types;
extern crate clap;
extern crate common_types as types;
extern crate core_executor as core;
#[macro_use]
extern crate crossbeam_channel;
extern crate db as cita_db;
extern crate dotenv;
extern crate error;
extern crate evm;
extern crate grpc;
#[cfg(test)]
extern crate hashable;
extern crate jsonrpc_types;
#[macro_use]
extern crate libproto;
#[macro_use]
extern crate logger;
extern crate proof;
extern crate pubsub;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate util;

use cita_directories::DataPath;
use clap::App;
use core::contracts::grpc::grpc_vm_adapter;
use core::libexecutor::executor::Executor;
use libproto::router::{MsgType, RoutingKey, SubModules};
use postman::Postman;
use pubsub::channel;
use pubsub::start_pubsub;
use std::thread;
use util::set_panic_handler;

mod backlogs;
mod postman;
mod snapshot;
#[cfg(test)]
mod tests;

include!(concat!(env!("OUT_DIR"), "/build_info.rs"));

#[derive(Debug, PartialEq, Deserialize)]
pub struct Options {
    prooftype: u8,
    grpc_port: u16,
    journaldb_type: String,
    genesis_path: String,
    statedb_cache_size: usize,
    eth_compatibility: bool,
}

impl Options {
    pub fn default() -> Self {
        Options {
            prooftype: 2,
            grpc_port: 5000,
            journaldb_type: String::from("archive"),
            genesis_path: String::from("genesis.json"),
            statedb_cache_size: 5 * 1024 * 1024,
            eth_compatibility: false,
        }
    }

    pub fn load(path: &str) -> Self {
        parse_config!(Options, path)
    }
}

fn main() {
    micro_service_init!("cita-executor", "CITA:executor");
    let matches = App::new("executor")
        .version(get_build_info_str(true))
        .long_version(get_build_info_str(false))
        .author("Cryptape")
        .about("CITA Block Chain Node powered by Rust")
        .arg_from_usage("-c, --config=[FILE] 'Sets a switch config file'")
        .get_matches();
    let config_path = matches.value_of("config").unwrap_or("executor.toml");
    let options = Options::load(config_path);
    info!("Version: {}", get_build_info_str(true));
    info!("Config: {:?}", options);

    // start pubsub thread
    let (forward_req_sender, forward_req_receiver) = channel::unbounded();
    let (forward_resp_sender, forward_resp_receiver) = channel::unbounded();
    let (mq_req_sender, mq_req_receiver) = crossbeam_channel::unbounded();
    let (mq_resp_sender, mq_resp_receiver) = crossbeam_channel::unbounded();
    let (fsm_req_sender, fsm_req_receiver) = crossbeam_channel::unbounded();
    let (fsm_resp_sender, fsm_resp_receiver) = crossbeam_channel::unbounded();
    let (command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0);
    let (command_resp_sender, command_resp_receiver) = crossbeam_channel::bounded(0);
    start_pubsub(
        "executor",
        routing_key!([
            Chain >> Request,
            Chain >> RichStatus,
            Chain >> StateSignal,
            Chain >> LocalSync,
            Consensus >> BlockWithProof,
            Consensus >> SignedProposal,
            Net >> SyncResponse,
            Snapshot >> SnapshotReq,
            Auth >> MiscellaneousReq,
        ]),
        forward_req_sender,
        forward_resp_receiver,
    );

    // start threads to forward messages between mpsc::channel and crosebeam::channel
    thread::spawn(move || loop {
        match forward_req_receiver.recv() {
            Ok(message) => mq_req_sender.send(message),
            Err(_) => return,
        }
    });
    thread::spawn(move || loop {
        match mq_resp_receiver.recv() {
            Some(message) => forward_resp_sender.send(message).unwrap(),
            None => return,
        }
    });

    // start grpc server thread background
    let server = grpc_vm_adapter::vm_grpc_server(
        options.grpc_port,
        command_req_sender.clone(),
        command_resp_receiver.clone(),
    )
    .expect("failed to initialize grpc server");
    thread::spawn(move || {
        grpc_vm_adapter::serve(&server);
    });

    loop {
        // start executor thread
        // TODO consider to store `data_path` within executor.toml
        let data_path = DataPath::root_node_path();
        let mut executor = Executor::init(
            &options.genesis_path,
            &options.journaldb_type,
            options.statedb_cache_size,
            data_path,
            fsm_req_receiver.clone(),
            fsm_resp_sender.clone(),
            command_req_receiver.clone(),
            command_resp_sender.clone(),
            options.eth_compatibility,
        );
        let current_height = executor.get_current_height();
        let current_hash = executor.get_current_hash();
        let handle = thread::spawn(move || {
            executor.do_loop();
        });

        // start postman thread
        let mut postman = Postman::new(
            current_height,
            current_hash,
            mq_req_receiver.clone(),
            mq_resp_sender.clone(),
            fsm_req_sender.clone(),
            fsm_resp_receiver.clone(),
            command_req_sender.clone(),
            command_resp_receiver.clone(),
        );
        postman.do_loop();

        handle.join().expect(
            "
            Executor exit cause Command::Exit was sent by postman inside.

            When postman roll back the whole cita-chain to an old height,
            it would tell executor thread to reset the `CURRNENT_HASH` to the
            target height, and then exit, both with postman. Main thread would
            re-run postman and executor inside this loop statement.
        ",
        );
    }
}
<|endoftext|>


<commit_before>// Std
use std::io::Write;

// Internal
use crate::Generator;
use crate::INTERNAL_ERROR_MSG;
use clap::*;

/// Generate zsh completion file
pub struct Zsh;

impl Generator for Zsh {
    fn file_name(name: &str) -> String {
        format!("_{}", name)
    }

    fn generate(app: &App, buf: &mut dyn Write) {
        w!(
            buf,
            format!(
                "\
#compdef {name}

autoload -U is-at-least

_{name}() {{
    typeset -A opt_args
    typeset -a _arguments_options
    local ret=1

    if is-at-least 5.2; then
        _arguments_options=(-s -S -C)
    else
        _arguments_options=(-s -C)
    fi

    local context curcontext=\"$curcontext\" state line
    {initial_args}
    {subcommands}
}}

{subcommand_details}

_{name} \"$@\"",
                name = app.get_bin_name().unwrap(),
                initial_args = get_args_of(app),
                subcommands = get_subcommands_of(app),
                subcommand_details = subcommand_details(app)
            )
            .as_bytes()
        );
    }
}

// Displays the commands of a subcommand
// (( $+functions[_[bin_name_underscore]_commands] )) ||
// _[bin_name_underscore]_commands() {
//     local commands; commands=(
//         '[arg_name]:[arg_help]'
//     )
//     _describe -t commands '[bin_name] commands' commands "$@"
//
// Where the following variables are present:
//    [bin_name_underscore]: The full space deliniated bin_name, where spaces have been replaced by
//                           underscore characters
//    [arg_name]: The name of the subcommand
//    [arg_help]: The help message of the subcommand
//    [bin_name]: The full space deliniated bin_name
//
// Here's a snippet from rustup:
//
// (( $+functions[_rustup_commands] )) ||
// _rustup_commands() {
//     local commands; commands=(
//         'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
//      # ... snip for brevity
//      'help:Prints this message or the help of the given subcommand(s)'
//     )
//     _describe -t commands 'rustup commands' commands "$@"
//
fn subcommand_details(p: &App) -> String {
    debugln!("ZshGen::subcommand_details;");

    let name = p.get_bin_name().unwrap();

    // First we do ourself
    let mut ret = vec![format!(
        "\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
        bin_name_underscore = name.replace(" ", "__"),
        bin_name = name,
        subcommands_and_args = subcommands_of(p)
    )];

    // Next we start looping through all the children, grandchildren, etc.
    let mut all_subcommands = Zsh::all_subcommands(p);

    all_subcommands.sort();
    all_subcommands.dedup();

    for &(_, ref bin_name) in &all_subcommands {
        debugln!("Zsh::subcommand_details:iter: bin_name={}", bin_name);

        ret.push(format!(
            "\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = bin_name.replace(" ", "__"),
            bin_name = bin_name,
            subcommands_and_args = subcommands_of(parser_of(p, bin_name))
        ));
    }

    ret.join("\n")
}

// Generates subcommand completions in form of
//
//         '[arg_name]:[arg_help]'
//
// Where:
//    [arg_name]: the subcommand's name
//    [arg_help]: the help message of the subcommand
//
// A snippet from rustup:
//         'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
fn subcommands_of(p: &App) -> String {
    debugln!("Zsh::subcommands_of;");

    let mut ret = vec![];

    fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
        debugln!("Zsh::add_sc;");

        let s = format!(
            "\"{name}:{help}\" \\",
            name = n,
            help = sc
                .about
                .unwrap_or("")
                .replace("[", "\\[")
                .replace("]", "\\]")
        );

        if !s.is_empty() {
            ret.push(s);
        }
    }

    // The subcommands
    for sc in subcommands!(p) {
        debugln!("Zsh::subcommands_of:iter: subcommand={}", sc.name);

        add_sc(sc, &sc.name, &mut ret);

        if let Some(ref v) = sc.aliases {
            for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
                add_sc(sc, alias, &mut ret);
            }
        }
    }

    ret.join("\n")
}

// Get's the subcommand section of a completion file
// This looks roughly like:
//
// case $state in
// ([bin_name]_args)
//     curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
//     case $line[1] in
//
//         ([name])
//         _arguments -C -s -S \
//             [subcommand_args]
//         && ret=0
//
//         [RECURSIVE_CALLS]
//
//         ;;",
//
//         [repeat]
//
//     esac
// ;;
// esac",
//
// Where the following variables are present:
//    [name] = The subcommand name in the form of "install" for "rustup toolchain install"
//    [bin_name] = The full space deliniated bin_name such as "rustup toolchain install"
//    [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
//    [repeat] = From the same recursive calls, but for all subcommands
//    [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &App) -> String {
    debugln!("Zsh::get_subcommands_of;");
    debugln!(
        "Zsh::get_subcommands_of: Has subcommands...{:?}",
        p.has_subcommands()
    );

    if !p.has_subcommands() {
        return String::new();
    }

    let sc_names = Zsh::subcommands(p);
    let mut subcmds = vec![];

    for &(ref name, ref bin_name) in &sc_names {
        let mut v = vec![format!("({})", name)];
        let subcommand_args = get_args_of(parser_of(p, &*bin_name));

        if !subcommand_args.is_empty() {
            v.push(subcommand_args);
        }

        let subcommands = get_subcommands_of(parser_of(p, &*bin_name));

        if !subcommands.is_empty() {
            v.push(subcommands);
        }

        v.push(String::from(";;"));
        subcmds.push(v.join("\n"));
    }

    format!(
        "case $state in
    ({name})
        words=($line[{pos}] \"${{words[@]}}\")
        (( CURRENT += 1 ))
        curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\"
        case $line[{pos}] in
            {subcommands}
        esac
    ;;
esac",
        name = p.name,
        name_hyphen = p.get_bin_name().unwrap().replace(" ", "-"),
        subcommands = subcmds.join("\n"),
        pos = positionals!(p).count() + 1
    )
}

fn parser_of<'b>(p: &'b App<'b>, mut sc: &str) -> &'b App<'b> {
    debugln!("Zsh::parser_of: sc={}", sc);

    if sc == p.get_bin_name().unwrap_or(&String::new()) {
        return p;
    }

    sc = sc.split(' ').last().unwrap();
    find_subcmd!(p, sc).expect(INTERNAL_ERROR_MSG)
}

// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to
// another ZSH function if there are subcommands.
// The structer works like this:
//    ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
//       ^-- list '-v -h'    ^--'*'          ^--'+'                   ^-- list 'one two three'
//
// An example from the rustup command:
//
// _arguments -C -s -S \
//         '(-h --help --verbose)-v[Enable verbose output]' \
//         '(-V -v --version --verbose --help)-h[Prints help information]' \
//      # ... snip for brevity
//         ':: :_rustup_commands' \    # <-- displays subcommands
//         '*::: :->rustup' \          # <-- displays subcommand args and child subcommands
//     && ret=0
//
// The args used for _arguments are as follows:
//    -C: modify the $context internal variable
//    -s: Allow stacking of short args (i.e. -a -b -c => -abc)
//    -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &App) -> String {
    debugln!("Zsh::get_args_of;");

    let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
    let opts = write_opts_of(p);
    let flags = write_flags_of(p);
    let positionals = write_positionals_of(p);

    let sc_or_a = if p.has_subcommands() {
        format!(
            "\":: :_{name}_commands\" \\",
            name = p.bin_name.as_ref().unwrap().replace(" ", "__")
        )
    } else {
        String::new()
    };

    let sc = if p.has_subcommands() {
        format!("\"*::: :->{name}\" \\", name = p.name)
    } else {
        String::new()
    };

    if !opts.is_empty() {
        ret.push(opts);
    }

    if !flags.is_empty() {
        ret.push(flags);
    }

    if !positionals.is_empty() {
        ret.push(positionals);
    }

    if !sc_or_a.is_empty() {
        ret.push(sc_or_a);
    }

    if !sc.is_empty() {
        ret.push(sc);
    }

    ret.push(String::from("&& ret=0"));
    ret.join("\n")
}

// Escape help string inside single quotes and brackets
fn escape_help(string: &str) -> String {
    string
        .replace("\\", "\\\\")
        .replace("'", "'\\''")
        .replace("[", "\\[")
        .replace("]", "\\]")
}

// Escape value string inside single quotes and parentheses
fn escape_value(string: &str) -> String {
    string
        .replace("\\", "\\\\")
        .replace("'", "'\\''")
        .replace("(", "\\(")
        .replace(")", "\\)")
        .replace(" ", "\\ ")
}

fn write_opts_of(p: &App) -> String {
    debugln!("Zsh::write_opts_of;");

    let mut ret = vec![];

    for o in opts!(p) {
        debugln!("Zsh::write_opts_of:iter: o={}", o.name);

        let help = o.help.map_or(String::new(), escape_help);
        let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);

        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        // @TODO @soundness should probably be either multiple occurrences or multiple values and
        // not both
        let multiple = if o.is_set(ArgSettings::MultipleOccurrences)
            || o.is_set(ArgSettings::MultipleValues)
        {
            "*"
        } else {
            ""
        };

        let pv = if let Some(ref pv_vec) = o.possible_vals {
            format!(
                ": :({})",
                pv_vec
                    .iter()
                    .map(|v| escape_value(*v))
                    .collect::<Vec<String>>()
                    .join(" ")
            )
        } else {
            String::new()
        };

        if let Some(short) = o.short {
            let s = format!(
                "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = short,
                possible_values = pv,
                help = help
            );

            debugln!("write_opts_of:iter: Wrote...{}", &*s);
            ret.push(s);
        }

        if let Some(long) = o.long {
            let l = format!(
                "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                possible_values = pv,
                help = help
            );

            debugln!("write_opts_of:iter: Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_flags_of(p: &App) -> String {
    debugln!("Zsh::write_flags_of;");

    let mut ret = vec![];

    for f in Zsh::flags(p) {
        debugln!("Zsh::write_flags_of:iter: f={}", f.name);

        let help = f.help.map_or(String::new(), escape_help);
        let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);

        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if f.is_set(ArgSettings::MultipleOccurrences) {
            "*"
        } else {
            ""
        };

        if let Some(short) = f.short {
            let s = format!(
                "'{conflicts}{multiple}-{arg}[{help}]' \\",
                multiple = multiple,
                conflicts = conflicts,
                arg = short,
                help = help
            );

            debugln!("Zsh::write_flags_of:iter: Wrote...{}", &*s);

            ret.push(s);
        }

        if let Some(long) = f.long {
            let l = format!(
                "'{conflicts}{multiple}--{arg}[{help}]' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                help = help
            );

            debugln!("Zsh::write_flags_of:iter: Wrote...{}", &*l);

            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_positionals_of(p: &App) -> String {
    debugln!("Zsh::write_positionals_of;");

    let mut ret = vec![];

    for arg in positionals!(p) {
        debugln!("Zsh::write_positionals_of:iter: arg={}", arg.name);

        let optional = if !arg.is_set(ArgSettings::Required) {
            ":"
        } else {
            ""
        };

        let a = format!(
            "'{optional}:{name}{help}:{action}' \\",
            optional = optional,
            name = arg.name,
            help = arg
                .help
                .map_or("".to_owned(), |v| " -- ".to_owned() + v)
                .replace("[", "\\[")
                .replace("]", "\\]"),
            action = arg
                .possible_vals
                .as_ref()
                .map_or("_files".to_owned(), |values| {
                    format!(
                        "({})",
                        values
                            .iter()
                            .map(|v| escape_value(*v))
                            .collect::<Vec<String>>()
                            .join(" ")
                    )
                })
        );

        debugln!("Zsh::write_positionals_of:iter: Wrote...{}", a);

        ret.push(a);
    }

    ret.join("\n")
}
<commit_msg>Escape colon in zsh completion help<commit_after>// Std
use std::io::Write;

// Internal
use crate::Generator;
use crate::INTERNAL_ERROR_MSG;
use clap::*;

/// Generate zsh completion file
pub struct Zsh;

impl Generator for Zsh {
    fn file_name(name: &str) -> String {
        format!("_{}", name)
    }

    fn generate(app: &App, buf: &mut dyn Write) {
        w!(
            buf,
            format!(
                "\
#compdef {name}

autoload -U is-at-least

_{name}() {{
    typeset -A opt_args
    typeset -a _arguments_options
    local ret=1

    if is-at-least 5.2; then
        _arguments_options=(-s -S -C)
    else
        _arguments_options=(-s -C)
    fi

    local context curcontext=\"$curcontext\" state line
    {initial_args}
    {subcommands}
}}

{subcommand_details}

_{name} \"$@\"",
                name = app.get_bin_name().unwrap(),
                initial_args = get_args_of(app),
                subcommands = get_subcommands_of(app),
                subcommand_details = subcommand_details(app)
            )
            .as_bytes()
        );
    }
}

// Displays the commands of a subcommand
// (( $+functions[_[bin_name_underscore]_commands] )) ||
// _[bin_name_underscore]_commands() {
//     local commands; commands=(
//         '[arg_name]:[arg_help]'
//     )
//     _describe -t commands '[bin_name] commands' commands "$@"
//
// Where the following variables are present:
//    [bin_name_underscore]: The full space deliniated bin_name, where spaces have been replaced by
//                           underscore characters
//    [arg_name]: The name of the subcommand
//    [arg_help]: The help message of the subcommand
//    [bin_name]: The full space deliniated bin_name
//
// Here's a snippet from rustup:
//
// (( $+functions[_rustup_commands] )) ||
// _rustup_commands() {
//     local commands; commands=(
//         'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
//      # ... snip for brevity
//      'help:Prints this message or the help of the given subcommand(s)'
//     )
//     _describe -t commands 'rustup commands' commands "$@"
//
fn subcommand_details(p: &App) -> String {
    debugln!("ZshGen::subcommand_details;");

    let name = p.get_bin_name().unwrap();

    // First we do ourself
    let mut ret = vec![format!(
        "\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
        bin_name_underscore = name.replace(" ", "__"),
        bin_name = name,
        subcommands_and_args = subcommands_of(p)
    )];

    // Next we start looping through all the children, grandchildren, etc.
    let mut all_subcommands = Zsh::all_subcommands(p);

    all_subcommands.sort();
    all_subcommands.dedup();

    for &(_, ref bin_name) in &all_subcommands {
        debugln!("Zsh::subcommand_details:iter: bin_name={}", bin_name);

        ret.push(format!(
            "\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = bin_name.replace(" ", "__"),
            bin_name = bin_name,
            subcommands_and_args = subcommands_of(parser_of(p, bin_name))
        ));
    }

    ret.join("\n")
}

// Generates subcommand completions in form of
//
//         '[arg_name]:[arg_help]'
//
// Where:
//    [arg_name]: the subcommand's name
//    [arg_help]: the help message of the subcommand
//
// A snippet from rustup:
//         'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
fn subcommands_of(p: &App) -> String {
    debugln!("Zsh::subcommands_of;");

    let mut ret = vec![];

    fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
        debugln!("Zsh::add_sc;");

        let s = format!(
            "\"{name}:{help}\" \\",
            name = n,
            help = sc
                .about
                .unwrap_or("")
                .replace("[", "\\[")
                .replace("]", "\\]")
        );

        if !s.is_empty() {
            ret.push(s);
        }
    }

    // The subcommands
    for sc in subcommands!(p) {
        debugln!("Zsh::subcommands_of:iter: subcommand={}", sc.name);

        add_sc(sc, &sc.name, &mut ret);

        if let Some(ref v) = sc.aliases {
            for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
                add_sc(sc, alias, &mut ret);
            }
        }
    }

    ret.join("\n")
}

// Get's the subcommand section of a completion file
// This looks roughly like:
//
// case $state in
// ([bin_name]_args)
//     curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
//     case $line[1] in
//
//         ([name])
//         _arguments -C -s -S \
//             [subcommand_args]
//         && ret=0
//
//         [RECURSIVE_CALLS]
//
//         ;;",
//
//         [repeat]
//
//     esac
// ;;
// esac",
//
// Where the following variables are present:
//    [name] = The subcommand name in the form of "install" for "rustup toolchain install"
//    [bin_name] = The full space deliniated bin_name such as "rustup toolchain install"
//    [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
//    [repeat] = From the same recursive calls, but for all subcommands
//    [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &App) -> String {
    debugln!("Zsh::get_subcommands_of;");
    debugln!(
        "Zsh::get_subcommands_of: Has subcommands...{:?}",
        p.has_subcommands()
    );

    if !p.has_subcommands() {
        return String::new();
    }

    let sc_names = Zsh::subcommands(p);
    let mut subcmds = vec![];

    for &(ref name, ref bin_name) in &sc_names {
        let mut v = vec![format!("({})", name)];
        let subcommand_args = get_args_of(parser_of(p, &*bin_name));

        if !subcommand_args.is_empty() {
            v.push(subcommand_args);
        }

        let subcommands = get_subcommands_of(parser_of(p, &*bin_name));

        if !subcommands.is_empty() {
            v.push(subcommands);
        }

        v.push(String::from(";;"));
        subcmds.push(v.join("\n"));
    }

    format!(
        "case $state in
    ({name})
        words=($line[{pos}] \"${{words[@]}}\")
        (( CURRENT += 1 ))
        curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\"
        case $line[{pos}] in
            {subcommands}
        esac
    ;;
esac",
        name = p.name,
        name_hyphen = p.get_bin_name().unwrap().replace(" ", "-"),
        subcommands = subcmds.join("\n"),
        pos = positionals!(p).count() + 1
    )
}

fn parser_of<'b>(p: &'b App<'b>, mut sc: &str) -> &'b App<'b> {
    debugln!("Zsh::parser_of: sc={}", sc);

    if sc == p.get_bin_name().unwrap_or(&String::new()) {
        return p;
    }

    sc = sc.split(' ').last().unwrap();
    find_subcmd!(p, sc).expect(INTERNAL_ERROR_MSG)
}

// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to
// another ZSH function if there are subcommands.
// The structer works like this:
//    ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
//       ^-- list '-v -h'    ^--'*'          ^--'+'                   ^-- list 'one two three'
//
// An example from the rustup command:
//
// _arguments -C -s -S \
//         '(-h --help --verbose)-v[Enable verbose output]' \
//         '(-V -v --version --verbose --help)-h[Prints help information]' \
//      # ... snip for brevity
//         ':: :_rustup_commands' \    # <-- displays subcommands
//         '*::: :->rustup' \          # <-- displays subcommand args and child subcommands
//     && ret=0
//
// The args used for _arguments are as follows:
//    -C: modify the $context internal variable
//    -s: Allow stacking of short args (i.e. -a -b -c => -abc)
//    -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &App) -> String {
    debugln!("Zsh::get_args_of;");

    let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
    let opts = write_opts_of(p);
    let flags = write_flags_of(p);
    let positionals = write_positionals_of(p);

    let sc_or_a = if p.has_subcommands() {
        format!(
            "\":: :_{name}_commands\" \\",
            name = p.bin_name.as_ref().unwrap().replace(" ", "__")
        )
    } else {
        String::new()
    };

    let sc = if p.has_subcommands() {
        format!("\"*::: :->{name}\" \\", name = p.name)
    } else {
        String::new()
    };

    if !opts.is_empty() {
        ret.push(opts);
    }

    if !flags.is_empty() {
        ret.push(flags);
    }

    if !positionals.is_empty() {
        ret.push(positionals);
    }

    if !sc_or_a.is_empty() {
        ret.push(sc_or_a);
    }

    if !sc.is_empty() {
        ret.push(sc);
    }

    ret.push(String::from("&& ret=0"));
    ret.join("\n")
}

// Escape help string inside single quotes and brackets
fn escape_help(string: &str) -> String {
    string
        .replace("\\", "\\\\")
        .replace("'", "'\\''")
        .replace("[", "\\[")
        .replace("]", "\\]")
}

// Escape value string inside single quotes and parentheses
fn escape_value(string: &str) -> String {
    string
        .replace("\\", "\\\\")
        .replace("'", "'\\''")
        .replace("(", "\\(")
        .replace(")", "\\)")
        .replace(" ", "\\ ")
}

fn write_opts_of(p: &App) -> String {
    debugln!("Zsh::write_opts_of;");

    let mut ret = vec![];

    for o in opts!(p) {
        debugln!("Zsh::write_opts_of:iter: o={}", o.name);

        let help = o.help.map_or(String::new(), escape_help);
        let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);

        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        // @TODO @soundness should probably be either multiple occurrences or multiple values and
        // not both
        let multiple = if o.is_set(ArgSettings::MultipleOccurrences)
            || o.is_set(ArgSettings::MultipleValues)
        {
            "*"
        } else {
            ""
        };

        let pv = if let Some(ref pv_vec) = o.possible_vals {
            format!(
                ": :({})",
                pv_vec
                    .iter()
                    .map(|v| escape_value(*v))
                    .collect::<Vec<String>>()
                    .join(" ")
            )
        } else {
            String::new()
        };

        if let Some(short) = o.short {
            let s = format!(
                "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = short,
                possible_values = pv,
                help = help
            );

            debugln!("write_opts_of:iter: Wrote...{}", &*s);
            ret.push(s);
        }

        if let Some(long) = o.long {
            let l = format!(
                "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                possible_values = pv,
                help = help
            );

            debugln!("write_opts_of:iter: Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_flags_of(p: &App) -> String {
    debugln!("Zsh::write_flags_of;");

    let mut ret = vec![];

    for f in Zsh::flags(p) {
        debugln!("Zsh::write_flags_of:iter: f={}", f.name);

        let help = f.help.map_or(String::new(), escape_help);
        let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);

        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if f.is_set(ArgSettings::MultipleOccurrences) {
            "*"
        } else {
            ""
        };

        if let Some(short) = f.short {
            let s = format!(
                "'{conflicts}{multiple}-{arg}[{help}]' \\",
                multiple = multiple,
                conflicts = conflicts,
                arg = short,
                help = help
            );

            debugln!("Zsh::write_flags_of:iter: Wrote...{}", &*s);

            ret.push(s);
        }

        if let Some(long) = f.long {
            let l = format!(
                "'{conflicts}{multiple}--{arg}[{help}]' \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                help = help
            );

            debugln!("Zsh::write_flags_of:iter: Wrote...{}", &*l);

            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_positionals_of(p: &App) -> String {
    debugln!("Zsh::write_positionals_of;");

    let mut ret = vec![];

    for arg in positionals!(p) {
        debugln!("Zsh::write_positionals_of:iter: arg={}", arg.name);

        let optional = if !arg.is_set(ArgSettings::Required) {
            ":"
        } else {
            ""
        };

        let a = format!(
            "'{optional}:{name}{help}:{action}' \\",
            optional = optional,
            name = arg.name,
            help = arg
                .help
                .map_or("".to_owned(), |v| " -- ".to_owned() + v)
                .replace("[", "\\[")
                .replace("]", "\\]")
                .replace(":", "\\:"),
            action = arg
                .possible_vals
                .as_ref()
                .map_or("_files".to_owned(), |values| {
                    format!(
                        "({})",
                        values
                            .iter()
                            .map(|v| escape_value(*v))
                            .collect::<Vec<String>>()
                            .join(" ")
                    )
                })
        );

        debugln!("Zsh::write_positionals_of:iter: Wrote...{}", a);

        ret.push(a);
    }

    ret.join("\n")
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use memory::Size;

use super::operation::Operation;
use super::scope::{ScopeItem, ScopeStack};

pub type FuncArgs = Vec<ScopeItem>;

#[derive(Clone)]
pub struct FunctionTypeDef {
    args: Vec<ItemType>,
    return_type: Box<ItemType>,
}

/// An item is anything that can be declared
#[derive(Clone)]
pub enum ItemType {
    /// A struct has a single definition with any number of
    /// fields and generics
    /// Structs can have impls which contain methods for that
    /// struct
    Struct {/*TODO*/},

    /// A fixed-size array
    Array {
        /// The type of the elements in this array
        type_name: String,
        /// The number of elements that this array can hold
        size: usize,
    },

    BuiltInFunction {
        type_def: FunctionTypeDef,
        /// Generates operations that represent calling the
        /// function with the given arguments
        operations: Rc<Fn(FuncArgs, ScopeStack) -> Vec<Operation>>,
    }
}

impl ItemType {
    /// Computes the required size in cells of this type
    pub fn required_size(&self, scope: &ScopeStack) -> Size {
        unimplemented!(); //TODO
    }
}
<commit_msg>Making it possible to define varadic functions<commit_after>use std::rc::Rc;

use memory::Size;

use super::operation::Operation;
use super::scope::{ScopeItem, ScopeStack};

/// The arguments that will get passed to a function
/// Distinct to the function's actual type because these are
/// ScopeItems not type defintions
/// Arguments can be assumed to match the type of that function
pub type FuncArgs = Vec<ScopeItem>;

/// Definition of a function's type
#[derive(Clone)]
pub struct FunctionTypeDef {
    args: Vec<FuncArgType>,
    return_type: Box<ItemType>,
}

#[derive(Clone)]
pub enum FuncArgType {
    /// A single argument of the given type
    Arg(ItemType),
    /// Any number of arguments of the given type
    Variadic(ItemType),
}

/// An item is anything that can be declared
#[derive(Clone)]
pub enum ItemType {
    /// Any type
    ///TODO: Replace with type bounds when generics are implemented in #45
    Any,

    /// A struct has a single definition with any number of
    /// fields and generics
    /// Structs can have impls which contain methods for that
    /// struct
    Struct {/*TODO*/},

    /// A fixed-size array
    Array {
        /// The type of the elements in this array
        type_name: String,
        /// The number of elements that this array can hold
        size: usize,
    },

    BuiltInFunction {
        type_def: FunctionTypeDef,
        /// Generates operations that represent calling the
        /// function with the given arguments
        operations: Rc<Fn(FuncArgs, ScopeStack) -> Vec<Operation>>,
    },
}

impl ItemType {
    /// Computes the required size in cells of this type
    pub fn required_size(&self, scope: &ScopeStack) -> Size {
        unimplemented!(); //TODO
    }
}
<|endoftext|>


<commit_before>mod list_container_options;
pub use self::list_container_options::{ListContainerOptions, LIST_CONTAINER_OPTIONS_DEFAULT};

use azure::core;
use azure::core::errors::AzureError;
use azure::core::errors::check_status_extract_body;
use azure::core::enumerations;
use azure::core::parsing::{cast_must, cast_optional, traverse};
use azure::core::incompletevector::IncompleteVector;

use azure::core::lease::{LeaseDuration, LeaseState, LeaseStatus};
use azure::storage::client::Client;

use futures::future::*;

use hyper::Method;
use hyper::StatusCode;

use std::str::FromStr;
use chrono::DateTime;
use chrono::Utc;

use std::fmt;

use xml::Element;

use azure::core::errors::TraversingError;
use azure::core::parsing::FromStringOptional;

header! { (XMSBlobPublicAccess, "x-ms-blob-public-access") => [PublicAccess] }

create_enum!(
    PublicAccess,
    (None, "none"),
    (Container, "container"),
    (Blob, "blob")
);

#[derive(Debug, Clone)]
pub struct Container {
    pub name: String,
    pub last_modified: DateTime<Utc>,
    pub e_tag: String,
    pub lease_status: LeaseStatus,
    pub lease_state: LeaseState,
    pub lease_duration: Option<LeaseDuration>,
}

impl Container {
    pub fn new(name: &str) -> Container {
        Container {
            name: name.to_owned(),
            last_modified: Utc::now(),
            e_tag: "".to_owned(),
            lease_status: LeaseStatus::Unlocked,
            lease_state: LeaseState::Available,
            lease_duration: None,
        }
    }

    pub fn parse(elem: &Element) -> Result<Container, core::errors::AzureError> {
        let name = try!(cast_must::<String>(elem, &["Name"]));
        let last_modified = try!(cast_must::<DateTime<Utc>>(
            elem,
            &["Properties", "Last-Modified"]
        ));
        let e_tag = try!(cast_must::<String>(elem, &["Properties", "Etag"]));

        let lease_state = try!(cast_must::<LeaseState>(elem, &["Properties", "LeaseState"]));

        let lease_duration = try!(cast_optional::<LeaseDuration>(
            elem,
            &["Properties", "LeaseDuration"]
        ));

        let lease_status = try!(cast_must::<LeaseStatus>(
            elem,
            &["Properties", "LeaseStatus"]
        ));

        Ok(Container {
            name: name,
            last_modified: last_modified,
            e_tag: e_tag,
            lease_status: lease_status,
            lease_state: lease_state,
            lease_duration: lease_duration,
        })
    }

    pub fn delete(&mut self, c: &Client) -> impl Future<Item = (), Error = AzureError> {
        let uri = format!(
            "https://{}.blob.core.windows.net/{}?restype=container",
            c.account(),
            self.name
        );

        let req = c.perform_request(&uri, Method::Delete, |_| {}, None);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Accepted).and_then(|_| ok(()))
        })
    }

    pub fn create(
        c: &Client,
        container_name: &str,
        pa: PublicAccess,
    ) -> impl Future<Item = (), Error = AzureError> {
        let uri = format!(
            "https://{}.blob.core.windows.net/{}?restype=container",
            c.account(),
            container_name
        );

        let req = c.perform_request(
            &uri,
            Method::Put,
            |ref mut headers| { headers.set(XMSBlobPublicAccess(pa)); },
            None,
        );

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Created).and_then(|_| ok(()))
        })
    }

    // TODO
    // pub fn get_acl(c : &Client, gao : &GetAclOptions)

    pub fn list(
        c: &Client,
        lco: &ListContainerOptions,
    ) -> Box<Future<Item = IncompleteVector<Container>, Error = AzureError>> {
        let mut uri = format!(
            "https://{}.blob.core.windows.net?comp=list&maxresults={}",
            c.account(),
            lco.max_results
        );

        if !lco.include_metadata {
            uri = format!("{}&include=metadata", uri);
        }

        if let Some(ref prefix) = lco.prefix {
            uri = format!("{}&prefix={}", uri, prefix);
        }

        if let Some(ref nm) = lco.next_marker {
            uri = format!("{}&marker={}", uri, nm);
        }

        if let Some(ref timeout) = lco.timeout {
            uri = format!("{}&timeout={}", uri, timeout);
        }

        let req = c.perform_request(&uri, Method::Get, |_| {}, None);

        Box::new(done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Ok).and_then(|body| {
                done(incomplete_vector_from_response(&body)).from_err()
            })
        }))
    }
}

fn incomplete_vector_from_response(body: &str) -> Result<IncompleteVector<Container>, AzureError> {
    let elem: Element = body.parse()?;

    let mut v = Vec::new();

    // let containers = try!(traverse(&elem, &["Containers", "Container"]));
    // println!("containers == {:?}", containers);

    for container in traverse(&elem, &["Containers", "Container"], true)? {
        v.push(Container::parse(container)?);
    }

    let next_marker = match cast_optional::<String>(&elem, &["NextMarker"])? {
        Some(ref nm) if nm == "" => None,
        Some(nm) => Some(nm),
        None => None,
    };

    Ok(IncompleteVector::new(next_marker, v))
}
<commit_msg>Switched from Box to impl Future in list containers<commit_after>mod list_container_options;
pub use self::list_container_options::{ListContainerOptions, LIST_CONTAINER_OPTIONS_DEFAULT};

use azure::core;
use azure::core::errors::AzureError;
use azure::core::errors::check_status_extract_body;
use azure::core::enumerations;
use azure::core::parsing::{cast_must, cast_optional, traverse};
use azure::core::incompletevector::IncompleteVector;

use azure::core::lease::{LeaseDuration, LeaseState, LeaseStatus};
use azure::storage::client::Client;

use futures::future::*;

use hyper::Method;
use hyper::StatusCode;

use std::str::FromStr;
use chrono::DateTime;
use chrono::Utc;

use std::fmt;

use xml::Element;

use azure::core::errors::TraversingError;
use azure::core::parsing::FromStringOptional;

header! { (XMSBlobPublicAccess, "x-ms-blob-public-access") => [PublicAccess] }

create_enum!(
    PublicAccess,
    (None, "none"),
    (Container, "container"),
    (Blob, "blob")
);

#[derive(Debug, Clone)]
pub struct Container {
    pub name: String,
    pub last_modified: DateTime<Utc>,
    pub e_tag: String,
    pub lease_status: LeaseStatus,
    pub lease_state: LeaseState,
    pub lease_duration: Option<LeaseDuration>,
}

impl Container {
    pub fn new(name: &str) -> Container {
        Container {
            name: name.to_owned(),
            last_modified: Utc::now(),
            e_tag: "".to_owned(),
            lease_status: LeaseStatus::Unlocked,
            lease_state: LeaseState::Available,
            lease_duration: None,
        }
    }

    pub fn parse(elem: &Element) -> Result<Container, core::errors::AzureError> {
        let name = try!(cast_must::<String>(elem, &["Name"]));
        let last_modified = try!(cast_must::<DateTime<Utc>>(
            elem,
            &["Properties", "Last-Modified"]
        ));
        let e_tag = try!(cast_must::<String>(elem, &["Properties", "Etag"]));

        let lease_state = try!(cast_must::<LeaseState>(elem, &["Properties", "LeaseState"]));

        let lease_duration = try!(cast_optional::<LeaseDuration>(
            elem,
            &["Properties", "LeaseDuration"]
        ));

        let lease_status = try!(cast_must::<LeaseStatus>(
            elem,
            &["Properties", "LeaseStatus"]
        ));

        Ok(Container {
            name: name,
            last_modified: last_modified,
            e_tag: e_tag,
            lease_status: lease_status,
            lease_state: lease_state,
            lease_duration: lease_duration,
        })
    }

    pub fn delete(&mut self, c: &Client) -> impl Future<Item = (), Error = AzureError> {
        let uri = format!(
            "https://{}.blob.core.windows.net/{}?restype=container",
            c.account(),
            self.name
        );

        let req = c.perform_request(&uri, Method::Delete, |_| {}, None);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Accepted).and_then(|_| ok(()))
        })
    }

    pub fn create(
        c: &Client,
        container_name: &str,
        pa: PublicAccess,
    ) -> impl Future<Item = (), Error = AzureError> {
        let uri = format!(
            "https://{}.blob.core.windows.net/{}?restype=container",
            c.account(),
            container_name
        );

        let req = c.perform_request(
            &uri,
            Method::Put,
            |ref mut headers| {
                headers.set(XMSBlobPublicAccess(pa));
            },
            None,
        );

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Created).and_then(|_| ok(()))
        })
    }

    // TODO
    // pub fn get_acl(c : &Client, gao : &GetAclOptions)

    pub fn list(
        c: &Client,
        lco: &ListContainerOptions,
    ) -> impl Future<Item = IncompleteVector<Container>, Error = AzureError> {
        let mut uri = format!(
            "https://{}.blob.core.windows.net?comp=list&maxresults={}",
            c.account(),
            lco.max_results
        );

        if !lco.include_metadata {
            uri = format!("{}&include=metadata", uri);
        }

        if let Some(ref prefix) = lco.prefix {
            uri = format!("{}&prefix={}", uri, prefix);
        }

        if let Some(ref nm) = lco.next_marker {
            uri = format!("{}&marker={}", uri, nm);
        }

        if let Some(ref timeout) = lco.timeout {
            uri = format!("{}&timeout={}", uri, timeout);
        }

        let req = c.perform_request(&uri, Method::Get, |_| {}, None);

        done(req).from_err().and_then(move |future_response| {
            check_status_extract_body(future_response, StatusCode::Ok).and_then(|body| {
                done(incomplete_vector_from_response(&body)).from_err()
            })
        })
    }
}

fn incomplete_vector_from_response(body: &str) -> Result<IncompleteVector<Container>, AzureError> {
    let elem: Element = body.parse()?;

    let mut v = Vec::new();

    // let containers = try!(traverse(&elem, &["Containers", "Container"]));
    // println!("containers == {:?}", containers);

    for container in traverse(&elem, &["Containers", "Container"], true)? {
        v.push(Container::parse(container)?);
    }

    let next_marker = match cast_optional::<String>(&elem, &["NextMarker"])? {
        Some(ref nm) if nm == "" => None,
        Some(nm) => Some(nm),
        None => None,
    };

    Ok(IncompleteVector::new(next_marker, v))
}
<|endoftext|>


<commit_before>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        self.run_opcode(self.get_opcode());
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&self) {}
    // RET
    fn op_00ee(&self) {}
    // SYS addr
    fn op_0nnn(&self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&self, x: usize) {}
}
<commit_msg>add basic unit test<commit_after>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        self.run_opcode(self.get_opcode());
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&self) {}
    // RET
    fn op_00ee(&self) {}
    // SYS addr
    fn op_0nnn(&self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&self, x: usize) {}
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }
}
<|endoftext|>


<commit_before>extern crate term;

pub fn spinner(rx: Receiver<int>, tx: Sender<int>) {
    let spinner = vec!["|", "/", "-", "\\",];
    for spin in spinner.iter().cycle() {
        say("white", "\x08");
        say("yellow", *spin);
        let r = rx.try_recv();
        match r {
            Ok(_) => {
                say("white", "\x08");
                tx.send(1);
                break;
            },
            Err(_) => {
                continue;
            }
        }
    }
}

pub fn say(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    (write!(t, "{}", to_say)).unwrap();
    t.reset().unwrap()
}

pub fn sayln(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    say(color, to_say);
    (write!(t, "\n")).unwrap();
}

<commit_msg>Replace the last character with whitespace<commit_after>extern crate term;

pub fn spinner(rx: Receiver<int>, tx: Sender<int>) {
    let spinner = vec!["|", "/", "-", "\\",];
    for spin in spinner.iter().cycle() {
        say("white", "\x08");
        say("yellow", *spin);
        let r = rx.try_recv();
        match r {
            Ok(_) => {
                say("white", "\x08 ");
                tx.send(1);
                break;
            },
            Err(_) => {
                continue;
            }
        }
    }
}

pub fn say(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    let color_const = match color {
        "green" => term::color::BRIGHT_GREEN,
        "yellow" => term::color::BRIGHT_YELLOW,
        "red" => term::color::BRIGHT_RED,
        "magenta" => term::color::BRIGHT_MAGENTA,
        "white" => term::color::WHITE,
        _ => term::color::WHITE
    };
    t.fg(color_const).unwrap();
    (write!(t, "{}", to_say)).unwrap();
    t.reset().unwrap()
}

pub fn sayln(color: &str, to_say: &str) {
    let mut t = term::stdout().unwrap();
    say(color, to_say);
    (write!(t, "\n")).unwrap();
}

<|endoftext|>