<commit_before>//! Matrix Decompositions
//!
//! References:
//! 1. [On Matrix Balancing and EigenVector computation](http://arxiv.org/pdf/1401.5766v1.pdf), James, Langou and Lowery

use std::ops::{Mul, Add, Div, Sub, Neg};
use std::fmt;

use linalg::matrix::Matrix;
use linalg::vector::Vector;
use linalg::Metric;
use linalg::utils;

use libnum::{One, Zero, Float, NumCast};
use libnum::cast;

impl<T: Copy + Zero + Float> Matrix<T> {
    /// Cholesky decomposition
    ///
    /// Returns the cholesky decomposition of a positive definite matrix.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let m = Matrix::new(3,3, vec![1.0,0.5,0.5,0.5,1.0,0.5,0.5,0.5,1.0]);
    ///
    /// let l = m.cholesky();
    /// ```
    ///
    /// # Panics
    ///
    /// - Matrix is not square.
    /// - Matrix is not positive definite. (This should probably be a Failure not a Panic).
    pub fn cholesky(&self) -> Matrix<T> {
        assert!(self.rows() == self.cols(), "Matrix is not square.");

        let mut new_data = Vec::<T>::with_capacity(self.rows() * self.cols());

        for i in 0..self.rows() {

            for j in 0..self.cols() {

                if j > i {
                    new_data.push(T::zero());
                    continue;
                }

                let mut sum = T::zero();
                for k in 0..j {
                    sum = sum + (new_data[i * self.cols() + k] * new_data[j * self.cols() + k]);
                }

                if j == i {
                    new_data.push((self[[i, i]] - sum).sqrt());
                } else {
                    let p = (self[[i, j]] - sum) / new_data[j * self.cols + j];

                    assert!(!p.is_nan(), "Matrix is not positive definite.");
                    new_data.push(p);
                }
            }
        }

        Matrix {
            rows: self.rows(),
            cols: self.cols(),
            data: new_data,
        }
    }

    fn make_householder(mat: Matrix<T>) -> Matrix<T> {
        assert!(mat.cols() == 1usize, "Householder matrix has invalid size.");
        let size = mat.rows();

        let denom = mat.data()[0] + mat.data()[0].signum() * mat.norm();

        if denom == T::zero() {
            panic!("Matrix can not be decomposed.");
        }
        let mut v = (mat / denom).into_vec();
        v[0] = T::one();
        let v = Vector::new(v);
        let v_norm_sq = v.dot(&v);

        let v_vert = Matrix::new(size, 1, v.data().clone());
        let v_hor = Matrix::new(1, size, v.into_vec());
        Matrix::<T>::identity(size) - (v_vert * v_hor) * ((T::one() + T::one()) / v_norm_sq)

    }

    /// Compute the QR decomposition of the matrix.
    ///
    /// Returns the tuple (Q,R).
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let m = Matrix::new(3,3, vec![1.0,0.5,0.5,0.5,1.0,0.5,0.5,0.5,1.0]);
    ///
    /// let l = m.qr_decomp();
    /// ```
    pub fn qr_decomp(self) -> (Matrix<T>, Matrix<T>) {
        let m = self.rows();
        let n = self.cols();

        let mut q = Matrix::<T>::identity(m);
        let mut r = self;

        for i in 0..(n - ((m == n) as usize)) {
            let lower_rows = &(i..m).collect::<Vec<usize>>()[..];
            let lower_self = (r.select_cols(&[i])).select_rows(lower_rows);
            let mut holder_data = Matrix::make_householder(lower_self).into_vec();

            // This bit is inefficient
            // using for now as we'll swap to lapack eventually.
            let mut h_full_data = Vec::with_capacity(m * m);

            for j in 0..m {
                let mut row_data: Vec<T>;
                if j < i {
                    row_data = vec![T::zero(); m];
                    row_data[j] = T::one();
                    h_full_data.extend(row_data);
                } else {
                    row_data = vec![T::zero();i];
                    h_full_data.extend(row_data);
                    h_full_data.extend(holder_data.drain(..m - i));
                }
            }

            let h = Matrix::new(m, m, h_full_data);

            q = q * &h;
            r = h * &r;
        }

        (q, r)
    }
}

impl<T: Copy + Zero + One + Float + NumCast + fmt::Debug> Matrix<T> {
    /// Returns (U,H), where H is the upper hessenberg form
    /// and U is the unitary transform matrix.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let a = Matrix::new(4,4,vec![2.,0.,1.,1.,2.,0.,1.,2.,1.,2.,0.,0.,2.,0.,1.,1.]);
    /// let h = a.upper_hessenberg();
    /// ```
    pub fn upper_hessenberg(&self) -> Matrix<T> {
        let n = self.rows();
        assert!(n == self.cols(),
                "Matrix must be square to produce upper hessenberg.");

        let mut dummy = self.clone();
        dummy.balance_matrix();

        for i in 0..n - 2 {
            let lower_rows = &(i + 1..n).collect::<Vec<usize>>()[..];
            let lower_self = (dummy.select_cols(&[i])).select_rows(lower_rows);
            let mut holder_data = Matrix::make_householder(lower_self).into_vec();

            let mut u_data = Vec::with_capacity(n * n);

            for j in 0..n {
                let mut row_data: Vec<T>;
                if j <= i {
                    row_data = vec![T::zero(); n];
                    row_data[j] = T::one();
                    u_data.extend(row_data);
                } else {
                    row_data = vec![T::zero();i+1];
                    u_data.extend(row_data);
                    u_data.extend(holder_data.drain(..n - i - 1));
                }
            }

            let u = Matrix::new(n, n, u_data);
            dummy = &u * dummy * u.transpose();
        }
        dummy
    }

    fn balance_matrix(&mut self) {
        let n = self.rows();
        let radix = cast::<f64, T>(2.0).unwrap();

        assert!(n == self.cols(),
                "Matrix must be square to produce balance matrix.");

        let mut d = Matrix::<T>::identity(n);
        let mut converged = false;

        while !converged {
            converged = true;

            for i in 0..n {
                let mut c = self.select_cols(&[i]).norm();
                let mut r = self.select_rows(&[i]).norm();

                let s = c * c + r * r;
                let mut f = T::one();

                while c < r / radix {
                    c = c * radix;
                    r = r / radix;
                    f = f * radix;
                }

                while c >= r * radix {
                    c = c / radix;
                    r = r * radix;
                    f = f / radix;
                }

                if (c * c + r * r) < cast::<f64, T>(0.95).unwrap() * s {
                    converged = false;
                    d.data[(i + 1) * self.cols] = f * d.data[(i + 1) * self.cols];

                    for j in 1..n {
                        self.data[j * self.cols + i] = f * self.data[j * self.cols + i];
                        self.data[i * self.cols + j] = f * self.data[i * self.cols + j];
                    }
                }
            }
        }
    }

    /// Eigen values of a square matrix.
    ///
    /// Returns a Vec of eigen values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let a = Matrix::new(3,3,vec![2.,0.,1.,0.,2.,0.,1.,0.,2.]);
    ///
    /// let e = a.eigenvalues();
    /// println!("{:?}", e);
    /// ```
    pub fn eigenvalues(&self) -> Vec<T> {
        let n = self.rows();
        assert!(n == self.cols(), "Matrix must be square for eigendecomp.");
        let mut h = self.upper_hessenberg();

        for _ in 0..200 {
            let (q, r) = h.qr_decomp();
            h = r * &q;
        }

        h.diag().into_vec()
    }
}

impl<T> Matrix<T> where T: Copy + One + Zero + Neg<Output=T> +
                           Add<T, Output=T> + Mul<T, Output=T> +
                           Sub<T, Output=T> + Div<T, Output=T> +
                           PartialOrd {

/// Computes L, U, and P for LUP decomposition.
///
/// Returns L,U, and P respectively.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::matrix::Matrix;
///
/// let a = Matrix::new(3,3, vec![1.0,2.0,0.0,
///                               0.0,3.0,4.0,
///                               5.0, 1.0, 2.0]);
///
/// let (l,u,p) = a.lup_decomp();
/// ```
    pub fn lup_decomp(&self) -> (Matrix<T>, Matrix<T>, Matrix<T>) {
        assert!(self.rows == self.cols, "Matrix is not square.");

        let n = self.cols;

        let mut l = Matrix::<T>::zeros(n, n);
        let mut u = Matrix::<T>::zeros(n, n);

        let mt = self.transpose();

        let mut p = Matrix::<T>::identity(n);

// Compute the permutation matrix
        for i in 0..n {
            let (row,_) = utils::argmax(&mt.data[i*(n+1)..(i+1)*n]);

            if row != 0 {
                for j in 0..n {
                    p.data.swap(i*n + j, row*n+j)
                }
            }
        }

        let a_2 = &p * self;

        for i in 0..n {
            l.data[i*(n+1)] = T::one();

            for j in 0..i+1 {
                let mut s1 = T::zero();

                for k in 0..j {
                    s1 = s1 + l.data[j*n + k] * u.data[k*n + i];
                }

                u.data[j*n + i] = a_2[[j,i]] - s1;
            }

            for j in i..n {
                let mut s2 = T::zero();

                for k in 0..i {
                    s2 = s2 + l.data[j*n + k] * u.data[k*n + i];
                }

                let denom = u[[i,i]];

                if denom == T::zero() {
                    panic!("Arithmetic error. Matrix could not be decomposed.")
                }
                l.data[j*n + i] = (a_2[[j,i]] - s2) / denom;
            }

        }

        (l,u,p)
    }
}
<commit_msg>Implementing implicit double-shit eigenvalue decomposition.<commit_after>//! Matrix Decompositions
//!
//! References:
//! 1. [On Matrix Balancing and EigenVector computation](http://arxiv.org/pdf/1401.5766v1.pdf), James, Langou and Lowery

use std::ops::{Mul, Add, Div, Sub, Neg};
use std::{f64, cmp};

use linalg::matrix::Matrix;
use linalg::vector::Vector;
use linalg::Metric;
use linalg::utils;

use libnum::{One, Zero, Float, NumCast, Signed};
use libnum::{cast, abs};

impl<T: Copy + Zero + Float> Matrix<T> {
    /// Cholesky decomposition
    ///
    /// Returns the cholesky decomposition of a positive definite matrix.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let m = Matrix::new(3,3, vec![1.0,0.5,0.5,0.5,1.0,0.5,0.5,0.5,1.0]);
    ///
    /// let l = m.cholesky();
    /// ```
    ///
    /// # Panics
    ///
    /// - Matrix is not square.
    /// - Matrix is not positive definite. (This should probably be a Failure not a Panic).
    pub fn cholesky(&self) -> Matrix<T> {
        assert!(self.rows() == self.cols(), "Matrix is not square.");

        let mut new_data = Vec::<T>::with_capacity(self.rows() * self.cols());

        for i in 0..self.rows() {

            for j in 0..self.cols() {

                if j > i {
                    new_data.push(T::zero());
                    continue;
                }

                let mut sum = T::zero();
                for k in 0..j {
                    sum = sum + (new_data[i * self.cols() + k] * new_data[j * self.cols() + k]);
                }

                if j == i {
                    new_data.push((self[[i, i]] - sum).sqrt());
                } else {
                    let p = (self[[i, j]] - sum) / new_data[j * self.cols + j];

                    assert!(!p.is_nan(), "Matrix is not positive definite.");
                    new_data.push(p);
                }
            }
        }

        Matrix {
            rows: self.rows(),
            cols: self.cols(),
            data: new_data,
        }
    }

    fn make_householder(mat: Matrix<T>) -> Matrix<T> {
        assert!(mat.cols() == 1usize, "Householder matrix has invalid size.");
        let size = mat.rows();

        let denom = mat.data()[0] + mat.data()[0].signum() * mat.norm();

        if denom == T::zero() {
            panic!("Matrix can not be decomposed.");
        }

        let mut v = (mat / denom).into_vec();
        v[0] = T::one();
        let v = Vector::new(v);
        let v_norm_sq = v.dot(&v);

        let v_vert = Matrix::new(size, 1, v.data().clone());
        let v_hor = Matrix::new(1, size, v.into_vec());
        Matrix::<T>::identity(size) - (v_vert * v_hor) * ((T::one() + T::one()) / v_norm_sq)
    }

    fn make_householder_vec(mat: Matrix<T>) -> Matrix<T> {
        assert!(mat.cols() == 1usize, "Householder matrix has invalid size.");
        let size = mat.rows();

        let denom = mat.data()[0] + mat.data()[0].signum() * mat.norm();

        if denom == T::zero() {
            panic!("Matrix can not be decomposed.");
        }

        let mut v = (mat / denom).into_vec();
        v[0] = T::one();
        let v = Matrix::new(size, 1, v);

        &v / v.norm()
    }

    /// Compute the QR decomposition of the matrix.
    ///
    /// Returns the tuple (Q,R).
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let m = Matrix::new(3,3, vec![1.0,0.5,0.5,0.5,1.0,0.5,0.5,0.5,1.0]);
    ///
    /// let l = m.qr_decomp();
    /// ```
    pub fn qr_decomp(self) -> (Matrix<T>, Matrix<T>) {
        let m = self.rows();
        let n = self.cols();

        let mut q = Matrix::<T>::identity(m);
        let mut r = self;

        for i in 0..(n - ((m == n) as usize)) {
            let lower_rows = &(i..m).collect::<Vec<usize>>()[..];
            let lower_self = r.select(lower_rows, &[i]);
            let mut holder_data = Matrix::make_householder(lower_self).into_vec();

            // This bit is inefficient
            // using for now as we'll swap to lapack eventually.
            let mut h_full_data = Vec::with_capacity(m * m);

            for j in 0..m {
                let mut row_data: Vec<T>;
                if j < i {
                    row_data = vec![T::zero(); m];
                    row_data[j] = T::one();
                    h_full_data.extend(row_data);
                } else {
                    row_data = vec![T::zero();i];
                    h_full_data.extend(row_data);
                    h_full_data.extend(holder_data.drain(..m - i));
                }
            }

            let h = Matrix::new(m, m, h_full_data);

            q = q * &h;
            r = h * &r;
        }

        (q, r)
    }
}

impl<T: Copy + Zero + One + Float + NumCast + Signed> Matrix<T> {
    /// Returns (U,H), where H is the upper hessenberg form
    /// and U is the unitary transform matrix.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let a = Matrix::new(4,4,vec![2.,0.,1.,1.,2.,0.,1.,2.,1.,2.,0.,0.,2.,0.,1.,1.]);
    /// let h = a.upper_hessenberg();
    ///
    /// println!("{:?}", h.data());
    /// ```
    ///
    /// # Panics
    ///
    /// - The matrix is not square.
    pub fn upper_hessenberg(&self) -> Matrix<T> {
        let n = self.rows;
        assert!(n == self.cols,
                "Matrix must be square to produce upper hessenberg.");

        let mut dummy = self.clone();
        dummy.balance_matrix();

        for i in 0..n - 2 {
            let lower_rows = &(i + 1..n).collect::<Vec<usize>>()[..];
            let lower_self = dummy.select(lower_rows, &[i]);;
            let h_holder_vec = Matrix::make_householder_vec(lower_self);

            let i_plus_to_n = (i + 1..n).collect::<Vec<usize>>();

            let dummy_block = dummy.select(&i_plus_to_n, &(i..n).collect::<Vec<usize>>());
            let reduc_block = &dummy_block -
                              &h_holder_vec * (h_holder_vec.transpose() * &dummy_block) *
                              (T::one() + T::one());

            // Reassign block
            for j in i + 1..n {
                for k in i..n {
                    dummy.data[j * dummy.cols + k] = reduc_block.data[(j - i - 1) * reduc_block.cols + k - i]
                }
            }

            let dummy_block = dummy.select(&(0..n).collect::<Vec<usize>>(), &i_plus_to_n);
            let reduc_block = &dummy_block -
                              (&dummy_block * &h_holder_vec) * h_holder_vec.transpose() *
                              (T::one() + T::one());

            // Reassign block
            for j in 0..n {
                for k in i + 1..n {
                    dummy.data[j * dummy.cols + k] = reduc_block.data[j * reduc_block.cols + k - i - 1]
                }
            }

        }

        // Enforce upper hessenberg
        for i in 0..self.cols-2 {
            for j in i + 2..self.rows {
                dummy.data[j * self.cols + i] = T::zero();
            }
        }

        dummy
    }

    fn balance_matrix(&mut self) {
        let n = self.rows();
        let radix = T::one() + T::one();

        assert!(n == self.cols(),
                "Matrix must be square to produce balance matrix.");

        let mut d = Matrix::<T>::identity(n);
        let mut converged = false;

        while !converged {
            converged = true;

            for i in 0..n {
                let mut c = self.select_cols(&[i]).norm();
                let mut r = self.select_rows(&[i]).norm();

                let s = c * c + r * r;
                let mut f = T::one();

                while c < r / radix {
                    c = c * radix;
                    r = r / radix;
                    f = f * radix;
                }

                while c >= r * radix {
                    c = c / radix;
                    r = r * radix;
                    f = f / radix;
                }

                if (c * c + r * r) < cast::<f64, T>(0.95).unwrap() * s {
                    converged = false;
                    d.data[(i + 1) * self.cols] = f * d.data[(i + 1) * self.cols];

                    for j in 0..n {
                        self.data[j * self.cols + i] = f * self.data[j * self.cols + i];
                        self.data[i * self.cols + j] = self.data[i * self.cols + j] / f;
                    }
                }
            }
        }
    }

    /// Compute the cos and sin values for the givens rotation.
    ///
    /// Returns a tuple (c,s).
    fn givens_rot(a: T, b: T) -> (T, T) {
        let r = a.hypot(b);

        (a / r, -b / r)
    }

    /// Eigen values of a square matrix.
    ///
    /// Returns a Vec of eigen values.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let a = Matrix::new(3,3,vec![3.,2.,4.,2.,0.,2.,4.,2.,3.]);
    ///
    /// let a = Matrix::new(4,4, (1..17).map(|v| v as f64).collect::<Vec<f64>>());
    /// let e = a.eigenvalues();
    /// println!("{:?}", e);
    /// ```
    ///
    /// # Panics
    ///
    /// - The matrix is not square.
    pub fn eigenvalues(&self) -> Vec<T> {
        let n = self.rows();
        assert!(n == self.cols(), "Matrix must be square for eigendecomp.");
        let mut h = self.upper_hessenberg();

        let eps = cast::<f64, T>(f64::MIN_POSITIVE * 2f64).unwrap();

        let mut id = Matrix::<T>::identity(n);
        let max_iters = 100;
        let mut curr_iters = 0;

        let mut eigs = Vec::with_capacity(n);

        for m in (1..n).rev() {

            while abs(h[[m, m - 1]]) > eps && curr_iters < max_iters {
                curr_iters += 1;

                let new_shift = h[[m, m]];
                let (q, r) = (h - &id * new_shift).qr_decomp();
                h = r * &q + &id * new_shift;
            }

            eigs.push(h[[m, m]]);

            let upper_block_indices = &(0..m).collect::<Vec<usize>>()[..];
            h = h.select(upper_block_indices, upper_block_indices);

            id = Matrix::<T>::identity(m);

            curr_iters = 0;
        }

        eigs.push(h[[0, 0]]);
        eigs.shrink_to_fit();
        eigs
    }

    /// Eigen decomposition of a square matrix.
    ///
    /// Returns a Vec of eigen values, and the eigen vectors.
    ///
    /// NOTE: This method currently does not return the eigenvector matrix correctly.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::linalg::matrix::Matrix;
    ///
    /// let a = Matrix::new(3,3,vec![3.,2.,4.,2.,0.,2.,4.,2.,3.]);
    ///
    /// let a = Matrix::new(4,4, (1..17).map(|v| v as f64).collect::<Vec<f64>>());
    /// let (e, _) = a.eigendecomp();
    /// println!("{:?}", e);
    /// ```
    ///
    /// # Panics
    ///
    /// - The matrix is not square.
    pub fn eigendecomp(&self) -> (Vec<T>, Matrix<T>) {
        let n = self.rows();
        assert!(n == self.cols(), "Matrix must be square for eigendecomp.");

        let mut h = self.upper_hessenberg();

        let mut p = n - 1;

        let eps = cast::<f64, T>(1e-15).unwrap();

        while p > 1 {
            let q = p - 1;
            let s = h[[q, q]] + h[[p, p]];
            let t = h[[q, q]] * h[[p, p]] - h[[q, p]] * h[[p, q]];

            let mut x = h[[0, 0]] * h[[0, 0]] + h[[0, 1]] * h[[1, 0]] - h[[0, 0]] * s + t;
            let mut y = h[[1, 0]] * (h[[0, 0]] + h[[1, 1]] - s);
            let mut z = h[[1, 0]] * h[[2, 1]];

            for k in 0..p - 1 {
                let r = cmp::max(1, k) - 1;

                let householder = Matrix::make_householder(Matrix::new(3, 1, vec![x, y, z]));

                let h_block = h.select(&[k, k + 1, k + 2], &(r..n).collect::<Vec<usize>>());
                let reduc_block = &householder * h_block;

                // Reassign the block
                for i in k..k + 3 {
                    for j in r..n {
                        h.data[i * h.cols + j] = reduc_block.data[(i - k) * reduc_block.cols() + j -
                                                                  r];
                    }
                }

                let r = cmp::min(k + 4, p + 1);

                let h_block = h.select(&(0..r).collect::<Vec<usize>>(), &[k, k + 1, k + 2]);
                let reduc_block = h_block * householder.transpose();

                // Reassign the block
                for i in 0..r {
                    for j in k..k + 3 {
                        h.data[i * h.cols + j] = reduc_block.data[i * reduc_block.cols + j - k];
                    }
                }

                x = h[[k + 1, k]];
                y = h[[k + 2, k]];

                if k < p - 2 {
                    z = h[[k + 3, k]];
                }
            }

            let (c, s) = Matrix::givens_rot(x, y);
            let givens_mat = Matrix::new(2, 2, vec![c, -s, s, c]);

            let h_block = h.select(&(q..p + 1).collect::<Vec<usize>>(),
                                   &(p - 2..n).collect::<Vec<usize>>());
            let reduc_block = &givens_mat * h_block;

            // Reassign the block
            for i in q..p + 1 {
                for j in p - 2..n {
                    h.data[i * h.cols + j] = reduc_block.data[(i - q) * reduc_block.cols + j -
                                                              (p - 2)];
                }
            }

            let h_block = h.select(&(0..p).collect::<Vec<usize>>(),
                                   &(p - 1..p + 1).collect::<Vec<usize>>());
            let reduc_block = h_block * givens_mat.transpose();

            // Reassign the block
            for i in 1..p {
                for j in p - 1..p + 1 {
                    h.data[i * h.cols + j] = reduc_block.data[i * reduc_block.cols + j - (p - 1)];
                }
            }

            // Check for convergence
            if abs(h[[p, q]]) < eps * (abs(h[[q, q]]) + abs(h[[p, p]])) {
                h.data[p * h.cols + q] = T::zero();
                p = p - 1;
            } else if abs(h[[p - 1, q - 1]]) < eps * (abs(h[[q - 1, q - 1]]) + abs(h[[q, q]])) {
                h.data[(p - 1) * h.cols + q - 1] = T::zero();
                p = p - 2;
            }
        }

        (h.diag().into_vec(), Matrix::<T>::new(0, 0, Vec::new()))
    }
}

impl<T> Matrix<T> where T: Copy + One + Zero + Neg<Output=T> +
                           Add<T, Output=T> + Mul<T, Output=T> +
                           Sub<T, Output=T> + Div<T, Output=T> +
                           PartialOrd {

/// Computes L, U, and P for LUP decomposition.
///
/// Returns L,U, and P respectively.
///
/// # Examples
///
/// ```
/// use rusty_machine::linalg::matrix::Matrix;
///
/// let a = Matrix::new(3,3, vec![1.0,2.0,0.0,
///                               0.0,3.0,4.0,
///                               5.0, 1.0, 2.0]);
///
/// let (l,u,p) = a.lup_decomp();
/// ```
    pub fn lup_decomp(&self) -> (Matrix<T>, Matrix<T>, Matrix<T>) {
        assert!(self.rows == self.cols, "Matrix is not square.");

        let n = self.cols;

        let mut l = Matrix::<T>::zeros(n, n);
        let mut u = Matrix::<T>::zeros(n, n);

        let mt = self.transpose();

        let mut p = Matrix::<T>::identity(n);

// Compute the permutation matrix
        for i in 0..n {
            let (row,_) = utils::argmax(&mt.data[i*(n+1)..(i+1)*n]);

            if row != 0 {
                for j in 0..n {
                    p.data.swap(i*n + j, row*n+j)
                }
            }
        }

        let a_2 = &p * self;

        for i in 0..n {
            l.data[i*(n+1)] = T::one();

            for j in 0..i+1 {
                let mut s1 = T::zero();

                for k in 0..j {
                    s1 = s1 + l.data[j*n + k] * u.data[k*n + i];
                }

                u.data[j*n + i] = a_2[[j,i]] - s1;
            }

            for j in i..n {
                let mut s2 = T::zero();

                for k in 0..i {
                    s2 = s2 + l.data[j*n + k] * u.data[k*n + i];
                }

                let denom = u[[i,i]];

                if denom == T::zero() {
                    panic!("Arithmetic error. Matrix could not be decomposed.")
                }
                l.data[j*n + i] = (a_2[[j,i]] - s2) / denom;
            }

        }

        (l,u,p)
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2015 Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! PWM Support for the NXP LPC17xx MCUs

use hal::lpc17xx::peripheral_clock::PeripheralClock::PWM1Clock;
use core::intrinsics::abort;

use self::PWMChannel::*;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;

/// "Channels" correspond to MR1..6 (0 used for period)
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum PWMChannel {
    CHANNEL0 = 0,  // reserved for period
    CHANNEL1,
    CHANNEL2,
    CHANNEL3,
    CHANNEL4,
    CHANNEL5,
    CHANNEL6,
}

impl PWMChannel {

    /// Set the match register for this channel to the provided value
    fn set_mr(&self, value: u32) {
        // note that for whatever reason, the match registers are fragmented
        // across two registers.  They aren't even located next to each other
        // in memory
        match *self {
            CHANNEL0 => { reg::PWM1.mr[0].set_value(value); },
            CHANNEL1 => { reg::PWM1.mr[1].set_value(value); },
            CHANNEL2 => { reg::PWM1.mr[2].set_value(value); },
            CHANNEL3 => { reg::PWM1.mr[3].set_value(value); },
            CHANNEL4 => { reg::PWM1.mr2[0].set_value(value); },
            CHANNEL5 => { reg::PWM1.mr2[1].set_value(value); },
            CHANNEL6 => { reg::PWM1.mr2[2].set_value(value); },
        };
    }
}

#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub struct PWM {
    channel: PWMChannel,
    period_us: u32,
    pulsewidth_us: u32,
}

impl PWM {

    /// Create a new PWM Output on the provided channel
    pub fn new(channel: PWMChannel) -> PWM {
        PWM1Clock.enable();
        PWM1Clock.set_divisor(4);

        // reset TC on match 0 for this channel and
        // enable output
        let mcr = reg::PWM1.mcr;
        let pcr = reg::PWM1.pcr;
        match channel {
            CHANNEL0 => { unsafe { abort() } },  // CHANNEL0 reserved for internal use
            CHANNEL0 => { panic!() },  // CHANNEL0 reserved for internal use
            CHANNEL1 => { mcr.set_pwmmr1r(true); pcr.set_pwmena1(true); },
            CHANNEL2 => { mcr.set_pwmmr2r(true); pcr.set_pwmena2(true); },
            CHANNEL3 => { mcr.set_pwmmr3r(true); pcr.set_pwmena3(true); },
            CHANNEL4 => { mcr.set_pwmmr4r(true); pcr.set_pwmena4(true); },
            CHANNEL5 => { mcr.set_pwmmr5r(true); pcr.set_pwmena5(true); },
            CHANNEL6 => { mcr.set_pwmmr6r(true); pcr.set_pwmena6(true); },
        };

        let pwm = PWM {
            channel: channel,
            period_us: 20_000,  // 20ms
            pulsewidth_us: 0,   // off by default
        };
        pwm.update_output();

        // TODO: Pin Muxing?
        //   - On the LPC1768, a few pads could be used for, e.g. PWM1.3
        //   - Can work as-is if function setup correct on the Pin, but this requires
        //     reading the user manual in detail
        //   - Alt for PWM on various pins is not always the same (1 or 2)
        pwm
    }

    /// Update the PWM Signal based on the current state
    fn update_output(&self) {
        // calculate the number of ticks for our period and pulsewidth
        let freq_hz: u32 = PWM1Clock.frequency();
        let freq_mhz: u32 = freq_hz / 1_000_000;
        let period_ticks: u32 = freq_mhz * self.period_us;
        let pulsewidth_ticks: u32 = freq_mhz * self.pulsewidth_us;

        // Set the match registers for period (CH0) and pulsewidth (CHN)
        CHANNEL0.set_mr(period_ticks);
        self.channel.set_mr(pulsewidth_ticks);

        // set the channel latch to update CH0 and CHN
        reg::PWM1.ler.set_value(1 << CHANNEL0 as u32 |
                                1 << self.channel as u32);

        // enable counter and pwm, clear reset
        reg::PWM1.tcr
            .set_ctr_en(reg::PWM1_tcr_ctr_en::ENABLED)
            .set_pwm_enable(reg::PWM1_tcr_pwm_enable::ENABLED)
            .set_ctr_reset(reg::PWM1_tcr_ctr_reset::SYNCHRONOUS_RESET);
    }

}

/// Implementation of Generic PWMOutput trait for LPC17xx
impl ::hal::pwm::PWMOutput for PWM {
    fn set_period_us(&mut self, period_us: u32) {
        self.period_us = period_us;
        self.update_output();
    }

    fn get_period_us(&self) -> u32 {
        self.period_us
    }

    fn set_pulsewidth_us(&mut self, pulsewidth_us: u32) {
        self.pulsewidth_us = pulsewidth_us;
        self.update_output();
    }

    fn get_pulsewidth_us(&self) -> u32 {
        self.pulsewidth_us
    }
}

/// LPC17xx PWM Register Definitions (User Manual: 24.6)
mod reg {
    use volatile_cell::VolatileCell;
    use core::ops::Drop;

    ioregs!(PWM1 = {
        /// Interrupt Register. The IR can be written to clear
        /// interrupts. The IR can be read to identify which of eight
        /// possible interrupt sources are pending.
        0x00 => reg32 ir {
            0  => irq_mr0,  //= Interrupt flag for PWM match channel 0.
            1  => irq_mr1,  //= Interrupt flag for PWM match channel 1.
            2  => irq_mr2,  //= Interrupt flag for PWM match channel 2.
            3  => irq_mr3,  //= Interrupt flag for PWM match channel 3.
            4  => irq_cap0, //= Interrupt flag for capture input 0
            5  => irq_cap1, //= Interrupt flag for capture input 1.
            // 7:6 Reserved
            8  => irq_mr4,  //= Interrupt flag for PWM match channel 4.
            9  => irq_mr5,  //= Interrupt flag for PWM match channel 5.
            10 => irq_mr6,  //= Interrupt flag for PWM match channel 6.
        }
        /// Timer Control Register. The TCR is used to control the
        /// Timer Counter functions. The Timer Counter can be disabled
        /// or reset through the TCR.
        0x04 => reg32 tcr {
            0 => ctr_en {
                0 => DISABLED,
                1 => ENABLED
            },
            1 => ctr_reset {
                0 => CLEAR_RESET,
                1 => SYNCHRONOUS_RESET
            },
            // 2 => Reserved
            3 => pwm_enable {
                0 => DISABLED,
                1 => ENABLED
            }
        }
        /// Timer Counter. The 32-bit TC is incremented every PR+1
        /// cycles of PCLK.  The TC is controlled through the TCR.
        0x08 => reg32 tc { 31..0 => value }
        /// Prescale Register. The TC is incremented every PR+1 cycles
        /// of PCLK.
        0x0C => reg32 pr { 31..0 => value }
        /// Prescale Counter. The 32-bit PC is a counter which is
        /// incremented to the value stored in PR. When the value in
        /// PR is reached, the TC is incremented. The PC is observable
        /// and controllable through the bus interface.
        0x10 => reg32 pc { 31..0 => value }
        /// Match Control Register. The MCR is used to control if an
        /// interrupt is generated and if the TC is reset when a Match
        /// occurs.
        0x14 => reg32 mcr {
            0 => pwmmr0i,  //= if set, interrupt on pwmmr0
            1 => pwmmr0r,  //= if set, reset on pwmmr0
            2 => pwmmr0s,  //= if set, stop on pwmmr0

            3 => pwmmr1i,  //= if set, interrupt on pwmmr1
            4 => pwmmr1r,  //= if set, reset on pwmmr1
            5 => pwmmr1s,  //= if set, stop on pwmmr1

            6 => pwmmr2i,  //= if set, interrupt on pwmmr2
            7 => pwmmr2r,  //= if set, reset on pwmmr2
            8 => pwmmr2s,  //= if set, stop on pwmmr2

            9 => pwmmr3i,  //= if set, interrupt on pwmmr3
            10 => pwmmr3r,  //= if set, reset on pwmmr3
            11 => pwmmr3s,  //= if set, stop on pwmmr3

            12 => pwmmr4i,  //= if set, interrupt on pwmmr4
            13 => pwmmr4r,  //= if set, reset on pwmmr4
            14 => pwmmr4s,  //= if set, stop on pwmmr4

            15=> pwmmr5i,  //= if set, interrupt on pwmmr5
            16 => pwmmr5r,  //= if set, reset on pwmmr5
            17 => pwmmr5s,  //= if set, stop on pwmmr5

            18 => pwmmr6i,  //= if set, interrupt on pwmmr6
            19 => pwmmr6r,  //= if set, reset on pwmmr6
            20 => pwmmr6s,  //= if set, stop on pwmmr6
        }
        /// Match Registers (0-3).  MR<N> can be enabled in the MCR to reset
        /// the TC, stop both the TC and PC, and/or generate an
        /// interrupt when it matches the TC.  In addition, a match
        /// between this value and the TC sets any PWM output that is
        /// in single-edge mode, and sets PWM<N + 1> if it’s in double-edge
        /// mode.
        0x18 => reg32 mr[4] { 31..0 => value }
        /// Capture Control Register. The CCR controls which edges of
        /// the capture inputs are used to load the Capture Registers
        /// and whether or not an interrupt is generated when a
        /// capture takes place.
        0x28 => reg32 ccr { 31..0 => value }
        /// Capture Registers (0-3). CR<N> is loaded with the value of the TC
        /// when there is an event on the CAPn.<N> input.
        0x30 => reg32 cr[4] { 31..0 => value }
        /// Match Registers (4-6).  See `mr` registers.  Not sure why
        /// banks are fragmented.
        0x40 => reg32 mr2[3] { 31..0 => value }
        /// PWM Control Register. Enables PWM outputs and selects PWM
        /// channel types as either single edge or double edge
        /// controlled.
        0x4c => reg32 pcr {
            9  => pwmena1,
            10 => pwmena2,
            11 => pwmena3,
            12 => pwmena4,
            13 => pwmena5,
            14 => pwmena6,
        }
        /// Load Enable Register. Enables use of new PWM match
        /// values.
        0x50 => reg32 ler { 31..0 => value }
        /// Count Control Register. The CTCR selects between Timer and
        /// Counter mode, and in Counter mode selects the signal and
        /// edge(s) for counting.
        0x70 => reg32 ctcr {
            0..2 => mode {
                0 => TIMER_MODE,
                1 => COUNTER_MODE_RISING,
                2 => COUNTER_MODE_FALLING,
                3 => COUNTER_MODE_BOTH
            }
        }
    });

    extern {
        #[link_name="lpc17xx_iomem_PWM1"] pub static PWM1: PWM1;
    }

}
<commit_msg>pwm: use local scope for register writes<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2015 Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! PWM Support for the NXP LPC17xx MCUs

use hal::lpc17xx::peripheral_clock::PeripheralClock::PWM1Clock;
use core::intrinsics::abort;

use self::PWMChannel::*;

#[path="../../util/ioreg.rs"]
#[macro_use] mod ioreg;

/// "Channels" correspond to MR1..6 (0 used for period)
#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub enum PWMChannel {
    CHANNEL0 = 0,  // reserved for period
    CHANNEL1,
    CHANNEL2,
    CHANNEL3,
    CHANNEL4,
    CHANNEL5,
    CHANNEL6,
}

impl PWMChannel {

    /// Set the match register for this channel to the provided value
    fn set_mr(&self, value: u32) {
        // note that for whatever reason, the match registers are fragmented
        // across two registers.  They aren't even located next to each other
        // in memory
        match *self {
            CHANNEL0 => { reg::PWM1.mr[0].set_value(value); },
            CHANNEL1 => { reg::PWM1.mr[1].set_value(value); },
            CHANNEL2 => { reg::PWM1.mr[2].set_value(value); },
            CHANNEL3 => { reg::PWM1.mr[3].set_value(value); },
            CHANNEL4 => { reg::PWM1.mr2[0].set_value(value); },
            CHANNEL5 => { reg::PWM1.mr2[1].set_value(value); },
            CHANNEL6 => { reg::PWM1.mr2[2].set_value(value); },
        };
    }
}

#[allow(missing_docs)]
#[derive(Clone, Copy)]
pub struct PWM {
    channel: PWMChannel,
    period_us: u32,
    pulsewidth_us: u32,
}

impl PWM {

    /// Create a new PWM Output on the provided channel
    pub fn new(channel: PWMChannel) -> PWM {
        PWM1Clock.enable();
        PWM1Clock.set_divisor(4);

        // reset TC on match 0 for this channel and
        // enable output
        match channel {
            CHANNEL0 => { unsafe { abort() } },  // CHANNEL0 reserved for internal use
            CHANNEL1 => { reg::PWM1.mcr.set_pwmmr1r(true); reg::PWM1.pcr.set_pwmena1(true); },
            CHANNEL2 => { reg::PWM1.mcr.set_pwmmr2r(true); reg::PWM1.pcr.set_pwmena2(true); },
            CHANNEL3 => { reg::PWM1.mcr.set_pwmmr3r(true); reg::PWM1.pcr.set_pwmena3(true); },
            CHANNEL4 => { reg::PWM1.mcr.set_pwmmr4r(true); reg::PWM1.pcr.set_pwmena4(true); },
            CHANNEL5 => { reg::PWM1.mcr.set_pwmmr5r(true); reg::PWM1.pcr.set_pwmena5(true); },
            CHANNEL6 => { reg::PWM1.mcr.set_pwmmr6r(true); reg::PWM1.pcr.set_pwmena6(true); },
        };

        let pwm = PWM {
            channel: channel,
            period_us: 20_000,  // 20ms
            pulsewidth_us: 0,   // off by default
        };
        pwm.update_output();

        // TODO: Pin Muxing?
        //   - On the LPC1768, a few pads could be used for, e.g. PWM1.3
        //   - Can work as-is if function setup correct on the Pin, but this requires
        //     reading the user manual in detail
        //   - Alt for PWM on various pins is not always the same (1 or 2)
        pwm
    }

    /// Update the PWM Signal based on the current state
    fn update_output(&self) {
        // calculate the number of ticks for our period and pulsewidth
        let freq_hz: u32 = PWM1Clock.frequency();
        let freq_mhz: u32 = freq_hz / 1_000_000;
        let period_ticks: u32 = freq_mhz * self.period_us;
        let pulsewidth_ticks: u32 = freq_mhz * self.pulsewidth_us;

        // Set the match registers for period (CH0) and pulsewidth (CHN)
        CHANNEL0.set_mr(period_ticks);
        self.channel.set_mr(pulsewidth_ticks);

        // set the channel latch to update CH0 and CHN
        reg::PWM1.ler.set_value(1 << CHANNEL0 as u32 |
                                1 << self.channel as u32);

        // enable counter and pwm, clear reset
        reg::PWM1.tcr
            .set_ctr_en(reg::PWM1_tcr_ctr_en::ENABLED)
            .set_pwm_enable(reg::PWM1_tcr_pwm_enable::ENABLED)
            .set_ctr_reset(reg::PWM1_tcr_ctr_reset::SYNCHRONOUS_RESET);
    }

}

/// Implementation of Generic PWMOutput trait for LPC17xx
impl ::hal::pwm::PWMOutput for PWM {
    fn set_period_us(&mut self, period_us: u32) {
        self.period_us = period_us;
        self.update_output();
    }

    fn get_period_us(&self) -> u32 {
        self.period_us
    }

    fn set_pulsewidth_us(&mut self, pulsewidth_us: u32) {
        self.pulsewidth_us = pulsewidth_us;
        self.update_output();
    }

    fn get_pulsewidth_us(&self) -> u32 {
        self.pulsewidth_us
    }
}

/// LPC17xx PWM Register Definitions (User Manual: 24.6)
mod reg {
    use volatile_cell::VolatileCell;
    use core::ops::Drop;

    ioregs!(PWM1 = {
        /// Interrupt Register. The IR can be written to clear
        /// interrupts. The IR can be read to identify which of eight
        /// possible interrupt sources are pending.
        0x00 => reg32 ir {
            0  => irq_mr0,  //= Interrupt flag for PWM match channel 0.
            1  => irq_mr1,  //= Interrupt flag for PWM match channel 1.
            2  => irq_mr2,  //= Interrupt flag for PWM match channel 2.
            3  => irq_mr3,  //= Interrupt flag for PWM match channel 3.
            4  => irq_cap0, //= Interrupt flag for capture input 0
            5  => irq_cap1, //= Interrupt flag for capture input 1.
            // 7:6 Reserved
            8  => irq_mr4,  //= Interrupt flag for PWM match channel 4.
            9  => irq_mr5,  //= Interrupt flag for PWM match channel 5.
            10 => irq_mr6,  //= Interrupt flag for PWM match channel 6.
        }
        /// Timer Control Register. The TCR is used to control the
        /// Timer Counter functions. The Timer Counter can be disabled
        /// or reset through the TCR.
        0x04 => reg32 tcr {
            0 => ctr_en {
                0 => DISABLED,
                1 => ENABLED
            },
            1 => ctr_reset {
                0 => CLEAR_RESET,
                1 => SYNCHRONOUS_RESET
            },
            // 2 => Reserved
            3 => pwm_enable {
                0 => DISABLED,
                1 => ENABLED
            }
        }
        /// Timer Counter. The 32-bit TC is incremented every PR+1
        /// cycles of PCLK.  The TC is controlled through the TCR.
        0x08 => reg32 tc { 31..0 => value }
        /// Prescale Register. The TC is incremented every PR+1 cycles
        /// of PCLK.
        0x0C => reg32 pr { 31..0 => value }
        /// Prescale Counter. The 32-bit PC is a counter which is
        /// incremented to the value stored in PR. When the value in
        /// PR is reached, the TC is incremented. The PC is observable
        /// and controllable through the bus interface.
        0x10 => reg32 pc { 31..0 => value }
        /// Match Control Register. The MCR is used to control if an
        /// interrupt is generated and if the TC is reset when a Match
        /// occurs.
        0x14 => reg32 mcr {
            0 => pwmmr0i,  //= if set, interrupt on pwmmr0
            1 => pwmmr0r,  //= if set, reset on pwmmr0
            2 => pwmmr0s,  //= if set, stop on pwmmr0

            3 => pwmmr1i,  //= if set, interrupt on pwmmr1
            4 => pwmmr1r,  //= if set, reset on pwmmr1
            5 => pwmmr1s,  //= if set, stop on pwmmr1

            6 => pwmmr2i,  //= if set, interrupt on pwmmr2
            7 => pwmmr2r,  //= if set, reset on pwmmr2
            8 => pwmmr2s,  //= if set, stop on pwmmr2

            9 => pwmmr3i,  //= if set, interrupt on pwmmr3
            10 => pwmmr3r,  //= if set, reset on pwmmr3
            11 => pwmmr3s,  //= if set, stop on pwmmr3

            12 => pwmmr4i,  //= if set, interrupt on pwmmr4
            13 => pwmmr4r,  //= if set, reset on pwmmr4
            14 => pwmmr4s,  //= if set, stop on pwmmr4

            15=> pwmmr5i,  //= if set, interrupt on pwmmr5
            16 => pwmmr5r,  //= if set, reset on pwmmr5
            17 => pwmmr5s,  //= if set, stop on pwmmr5

            18 => pwmmr6i,  //= if set, interrupt on pwmmr6
            19 => pwmmr6r,  //= if set, reset on pwmmr6
            20 => pwmmr6s,  //= if set, stop on pwmmr6
        }
        /// Match Registers (0-3).  MR<N> can be enabled in the MCR to reset
        /// the TC, stop both the TC and PC, and/or generate an
        /// interrupt when it matches the TC.  In addition, a match
        /// between this value and the TC sets any PWM output that is
        /// in single-edge mode, and sets PWM<N + 1> if it’s in double-edge
        /// mode.
        0x18 => reg32 mr[4] { 31..0 => value }
        /// Capture Control Register. The CCR controls which edges of
        /// the capture inputs are used to load the Capture Registers
        /// and whether or not an interrupt is generated when a
        /// capture takes place.
        0x28 => reg32 ccr { 31..0 => value }
        /// Capture Registers (0-3). CR<N> is loaded with the value of the TC
        /// when there is an event on the CAPn.<N> input.
        0x30 => reg32 cr[4] { 31..0 => value }
        /// Match Registers (4-6).  See `mr` registers.  Not sure why
        /// banks are fragmented.
        0x40 => reg32 mr2[3] { 31..0 => value }
        /// PWM Control Register. Enables PWM outputs and selects PWM
        /// channel types as either single edge or double edge
        /// controlled.
        0x4c => reg32 pcr {
            9  => pwmena1,
            10 => pwmena2,
            11 => pwmena3,
            12 => pwmena4,
            13 => pwmena5,
            14 => pwmena6,
        }
        /// Load Enable Register. Enables use of new PWM match
        /// values.
        0x50 => reg32 ler { 31..0 => value }
        /// Count Control Register. The CTCR selects between Timer and
        /// Counter mode, and in Counter mode selects the signal and
        /// edge(s) for counting.
        0x70 => reg32 ctcr {
            0..2 => mode {
                0 => TIMER_MODE,
                1 => COUNTER_MODE_RISING,
                2 => COUNTER_MODE_FALLING,
                3 => COUNTER_MODE_BOTH
            }
        }
    });

    extern {
        #[link_name="lpc17xx_iomem_PWM1"] pub static PWM1: PWM1;
    }

}
<|endoftext|>


<commit_before><commit_msg>Implement the StatusHandler.<commit_after>use super::*;
use super::super::server::{self, Server};
use super::super::test_server;
use super::super::packets::*;
use std::collections;
use std::iter::{self, Iterator, IntoIterator};
use std::convert;
use std::net;

pub struct StatusHandler {
    listening: bool,
    version: String,
    supported_extensions: collections::HashSet<String>,
}

impl StatusHandler {
    pub fn new<T>(listening: bool, version: &str, supported_extensions: &[T])->StatusHandler
    where T: convert::Into<String>+Clone,
    {
        let mut set = collections::HashSet::<String>::new();
        for i in supported_extensions.into_iter() {
            set.insert(i.clone().into());
        }
        StatusHandler {
            listening: listening,
            version: version.to_string(),
            supported_extensions: set,
        }
    }
}

impl PacketHandler for StatusHandler {
    fn handle_incoming_packet_always<T: server::Server>(&mut self, packet: &Packet, ip: net::IpAddr, server: &mut T)->bool {
        match *packet {
            Packet::StatusRequest(ref req) => {
                server.send(
                &match *req {
                    StatusRequest::FastnetQuery => Packet::StatusResponse(StatusResponse::FastnetResponse(self.listening)),
                    StatusRequest::VersionQuery => Packet::StatusResponse(StatusResponse::VersionResponse(self.version.clone())),
                    StatusRequest::ExtensionQuery(ref name) => {
                        let supported = self.supported_extensions.contains(name);
                        Packet::StatusResponse(StatusResponse::ExtensionResponse{name: name.clone(), supported: supported})
                    }
                }, &ip);
                true
            },
            _ => false
        }
    }
}

handler_test!(test_status_handler, |server: &mut test_server::TestServer, ip: net::IpAddr| {
    let mut handler = StatusHandler::new(true, "1.0", &["test_atest"]);
    handler.handle_incoming_packet_always(&Packet::StatusRequest(StatusRequest::FastnetQuery), ip, server);
    handler.handle_incoming_packet_always(&Packet::StatusRequest(StatusRequest::VersionQuery), ip, server);
    handler.handle_incoming_packet_always(&Packet::StatusRequest(StatusRequest::ExtensionQuery("test_atest".to_string())), ip, server);
},
Packet::StatusResponse(StatusResponse::FastnetResponse(true)),
Packet::StatusResponse(StatusResponse::VersionResponse("1.0".to_string())),
Packet::StatusResponse(StatusResponse::ExtensionResponse{name: "test_atest".to_string(), supported: true})
);
<|endoftext|>


<commit_before>//! Structures and functions to aid in various TUF data interchange formats.

mod cjson;

use json;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use std::fmt::Debug;
use std::io::{Read, Write};

use Result;
use error::Error;

/// The format used for data interchange, serialization, and deserialization.
pub trait DataInterchange: Debug + PartialEq + Clone {
    /// The type of data that is contained in the `signed` portion of metadata.
    type RawData: Serialize + DeserializeOwned + Clone + PartialEq;

    /// The data interchange's extension.
    fn extension() -> &'static str;

    /// A function that canonicalizes data to allow for deterministic signatures.
    fn canonicalize(raw_data: &Self::RawData) -> Result<Vec<u8>>;

    /// Deserialize from `RawData`.
    fn deserialize<T>(raw_data: &Self::RawData) -> Result<T>
    where
        T: DeserializeOwned;

    /// Serialize into `RawData`.
    fn serialize<T>(data: &T) -> Result<Self::RawData>
    where
        T: Serialize;

    /// Write a struct to a stream.
    ///
    /// Note: This *MUST* write the bytes canonically for hashes to line up correctly in other
    /// areas of the library.
    fn to_writer<W, T: Sized>(writer: W, value: &T) -> Result<()>
    where
        W: Write,
        T: Serialize;

    /// Read a struct from a stream.
    fn from_reader<R, T>(rdr: R) -> Result<T>
    where
        R: Read,
        T: DeserializeOwned;
}

/// JSON data interchange.
///
/// # Schema
///
/// This doesn't use JSON Schema because that specification language is rage inducing. Here's
/// something else instead.
///
/// ## Common Entities
///
/// `NATURAL_NUMBER` is an integer in the range `[1, 2**32)`.
///
/// `EXPIRES` is an ISO-8601 date time in format `YYYY-MM-DD'T'hh:mm:ss'Z'`.
///
/// `KEY_ID` is the base64url encoded value of `sha256(spki(pub_key))`.
///
/// `PUB_KEY` is the following:
///
/// ```bash
/// {
///   "type": KEY_TYPE,
///   "value": PUBLIC
/// }
/// ```
///
/// `PUBLIC` is a base64url encoded `SubjectPublicKeyInfo` DER public key.
///
/// `KEY_TYPE` is a string (either `rsa` or `ed25519`).
///
/// `HASH_VALUE` is a base64url encoded hash value.
///
/// `METADATA_DESCRIPTION` is the following:
///
/// ```bash
/// {
///   "version": NATURAL_NUMBER,
///   "size": NATURAL_NUMBER,
///   "hashes": {
///     HASH_ALGORITHM: HASH_VALUE
///     ...
///   }
/// }
/// ```
///
/// ## `SignedMetadata`
///
/// ```bash
/// {
///   "signatures": [SIGNATURE],
///   "signed": SIGNED
/// }
/// ```
///
/// `SIGNED` is one of:
///
/// - `RootMetadata`
/// - `SnapshotMetadata`
/// - `TargetsMetadata`
/// - `TimestampMetadata`
///
/// The the elements of `signatures` must have unique `key_id`s.
///
/// ## `RootMetadata`
///
/// ```bash
/// {
///   "type": "root",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "keys": [PUB_KEY, ...]
///   "root": ROLE_DESCRIPTION,
///   "snapshot": ROLE_DESCRIPTION,
///   "targets": ROLE_DESCRIPTION,
///   "timestamp": ROLE_DESCRIPTION
/// }
/// ```
///
/// `ROLE_DESCRIPTION` is the following:
///
/// ```bash
/// {
///   "threshold": NATURAL_NUMBER,
///   "key_ids": [KEY_ID, ...]
/// }
/// ```
///
/// ## `SnapshotMetadata`
///
/// ```bash
/// {
///   "type": "snapshot",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "meta": {
///     META_PATH: METADATA_DESCRIPTION
///   }
/// }
/// ```
///
/// `META_PATH` is a string.
///
///
/// ## `TargetsMetadata`
///
/// ```bash
/// {
///   "type": "timestamp",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "targets": {
///     TARGET_PATH: TARGET_DESCRIPTION
///     ...
///   },
///   "delegations": DELEGATIONS
/// }
/// ```
///
/// `DELEGATIONS` is optional and is described by the following:
///
/// ```bash
/// {
///   "keys": [PUB_KEY, ...]
///   "roles": {
///     ROLE: DELEGATION,
///     ...
///   }
/// }
/// ```
///
/// `DELEGATION` is:
///
/// ```bash
/// {
///   "name": ROLE,
///   "threshold": NATURAL_NUMBER,
///   "terminating": BOOLEAN,
///   "key_ids": [KEY_ID, ...],
///   "paths": [PATH, ...]
/// }
/// ```
///
/// `ROLE` is a string,
///
/// `PATH` is a string.
///
/// ## `TimestampMetadata`
///
/// ```bash
/// {
///   "type": "timestamp",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "snapshot": METADATA_DESCRIPTION
/// }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Json {}
impl DataInterchange for Json {
    type RawData = json::Value;

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    ///
    /// assert_eq!(Json::extension(), "json");
    /// ```
    fn extension() -> &'static str {
        "json"
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// let jsn: &[u8] = br#"{"foo": "bar", "baz": "quux"}"#;
    /// let raw = Json::from_reader(jsn).unwrap();
    /// let out = Json::canonicalize(&raw).unwrap();
    /// assert_eq!(out, br#"{"baz":"quux","foo":"bar"}"#);
    /// ```
    fn canonicalize(raw_data: &Self::RawData) -> Result<Vec<u8>> {
        cjson::canonicalize(raw_data).map_err(|e| Error::Opaque(e))
    }

    /// ```
    /// #[macro_use]
    /// extern crate serde_derive;
    /// #[macro_use]
    /// extern crate serde_json;
    /// extern crate tuf;
    ///
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// #[derive(Deserialize, Debug, PartialEq)]
    /// struct Thing {
    ///    foo: String,
    ///    bar: String,
    /// }
    ///
    /// fn main() {
    ///     let jsn = json!({"foo": "wat", "bar": "lol"});
    ///     let thing = Thing { foo: "wat".into(), bar: "lol".into() };
    ///     let de: Thing = Json::deserialize(&jsn).unwrap();
    ///     assert_eq!(de, thing);
    /// }
    /// ```
    fn deserialize<T>(raw_data: &Self::RawData) -> Result<T>
    where
        T: DeserializeOwned,
    {
        Ok(json::from_value(raw_data.clone())?)
    }

    /// ```
    /// #[macro_use]
    /// extern crate serde_derive;
    /// #[macro_use]
    /// extern crate serde_json;
    /// extern crate tuf;
    ///
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// #[derive(Serialize)]
    /// struct Thing {
    ///    foo: String,
    ///    bar: String,
    /// }
    ///
    /// fn main() {
    ///     let jsn = json!({"foo": "wat", "bar": "lol"});
    ///     let thing = Thing { foo: "wat".into(), bar: "lol".into() };
    ///     let se: serde_json::Value = Json::serialize(&thing).unwrap();
    ///     assert_eq!(se, jsn);
    /// }
    /// ```
    fn serialize<T>(data: &T) -> Result<Self::RawData>
    where
        T: Serialize,
    {
        Ok(json::to_value(data)?)
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    ///
    /// let arr = vec![1, 2, 3];
    /// let mut buf = Vec::new();
    /// Json::to_writer(&mut buf, &arr).unwrap();
    /// assert!(&buf == b"[1, 2, 3]" || &buf == b"[1,2,3]");
    /// ```
    fn to_writer<W, T: Sized>(mut writer: W, value: &T) -> Result<()>
    where
        W: Write,
        T: Serialize,
    {
        let bytes = Self::canonicalize(&Self::serialize(value)?)?;
        writer.write_all(&bytes)?;
        Ok(())
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// let jsn: &[u8] = br#"{"foo": "bar", "baz": "quux"}"#;
    /// let _: HashMap<String, String> = Json::from_reader(jsn).unwrap();
    /// ```
    fn from_reader<R, T>(rdr: R) -> Result<T>
    where
        R: Read,
        T: DeserializeOwned,
    {
        Ok(json::from_reader(rdr)?)
    }
}
<commit_msg>updated json schema for TAP9 modifications<commit_after>//! Structures and functions to aid in various TUF data interchange formats.

mod cjson;

use json;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use std::fmt::Debug;
use std::io::{Read, Write};

use Result;
use error::Error;

/// The format used for data interchange, serialization, and deserialization.
pub trait DataInterchange: Debug + PartialEq + Clone {
    /// The type of data that is contained in the `signed` portion of metadata.
    type RawData: Serialize + DeserializeOwned + Clone + PartialEq;

    /// The data interchange's extension.
    fn extension() -> &'static str;

    /// A function that canonicalizes data to allow for deterministic signatures.
    fn canonicalize(raw_data: &Self::RawData) -> Result<Vec<u8>>;

    /// Deserialize from `RawData`.
    fn deserialize<T>(raw_data: &Self::RawData) -> Result<T>
    where
        T: DeserializeOwned;

    /// Serialize into `RawData`.
    fn serialize<T>(data: &T) -> Result<Self::RawData>
    where
        T: Serialize;

    /// Write a struct to a stream.
    ///
    /// Note: This *MUST* write the bytes canonically for hashes to line up correctly in other
    /// areas of the library.
    fn to_writer<W, T: Sized>(writer: W, value: &T) -> Result<()>
    where
        W: Write,
        T: Serialize;

    /// Read a struct from a stream.
    fn from_reader<R, T>(rdr: R) -> Result<T>
    where
        R: Read,
        T: DeserializeOwned;
}

/// JSON data interchange.
///
/// # Schema
///
/// This doesn't use JSON Schema because that specification language is rage inducing. Here's
/// something else instead.
///
/// ## Common Entities
///
/// `NATURAL_NUMBER` is an integer in the range `[1, 2**32)`.
///
/// `EXPIRES` is an ISO-8601 date time in format `YYYY-MM-DD'T'hh:mm:ss'Z'`.
///
/// `KEY_ID` is the base64url encoded value of `sha256(spki(pub_key))`.
///
/// `PUB_KEY` is the following:
///
/// ```bash
/// {
///   "type": KEY_TYPE,
///   "scheme": SCHEME,
///   "value": PUBLIC
/// }
/// ```
///
/// `PUBLIC` is a base64url encoded `SubjectPublicKeyInfo` DER public key.
///
/// `KEY_TYPE` is a string (either `rsa` or `ed25519`).
///
/// `SCHEME` is a string (either `ed25519`, `rsassa-pss-sha256`, or `rsassa-pss-sha512`
///
/// `HASH_VALUE` is a base64url encoded hash value.
///
/// `SIG_VALUE` is a base64url encoded signature value.
///
/// `METADATA_DESCRIPTION` is the following:
///
/// ```bash
/// {
///   "version": NATURAL_NUMBER,
///   "size": NATURAL_NUMBER,
///   "hashes": {
///     HASH_ALGORITHM: HASH_VALUE
///     ...
///   }
/// }
/// ```
///
/// ## `SignedMetadata`
///
/// ```bash
/// {
///   "signatures": [SIGNATURE],
///   "signed": SIGNED
/// }
/// ```
///
/// `SIGNATURE` is:
///
/// ```bash
/// {
///   "key_id": KEY_ID,
///   "signature": SIG_VALUE
/// }
/// ```
///
/// `SIGNED` is one of:
///
/// - `RootMetadata`
/// - `SnapshotMetadata`
/// - `TargetsMetadata`
/// - `TimestampMetadata`
///
/// The the elements of `signatures` must have unique `key_id`s.
///
/// ## `RootMetadata`
///
/// ```bash
/// {
///   "type": "root",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "keys": [PUB_KEY, ...]
///   "root": ROLE_DESCRIPTION,
///   "snapshot": ROLE_DESCRIPTION,
///   "targets": ROLE_DESCRIPTION,
///   "timestamp": ROLE_DESCRIPTION
/// }
/// ```
///
/// `ROLE_DESCRIPTION` is the following:
///
/// ```bash
/// {
///   "threshold": NATURAL_NUMBER,
///   "key_ids": [KEY_ID, ...]
/// }
/// ```
///
/// ## `SnapshotMetadata`
///
/// ```bash
/// {
///   "type": "snapshot",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "meta": {
///     META_PATH: METADATA_DESCRIPTION
///   }
/// }
/// ```
///
/// `META_PATH` is a string.
///
///
/// ## `TargetsMetadata`
///
/// ```bash
/// {
///   "type": "timestamp",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "targets": {
///     TARGET_PATH: TARGET_DESCRIPTION
///     ...
///   },
///   "delegations": DELEGATIONS
/// }
/// ```
///
/// `DELEGATIONS` is optional and is described by the following:
///
/// ```bash
/// {
///   "keys": [PUB_KEY, ...]
///   "roles": {
///     ROLE: DELEGATION,
///     ...
///   }
/// }
/// ```
///
/// `DELEGATION` is:
///
/// ```bash
/// {
///   "name": ROLE,
///   "threshold": NATURAL_NUMBER,
///   "terminating": BOOLEAN,
///   "key_ids": [KEY_ID, ...],
///   "paths": [PATH, ...]
/// }
/// ```
///
/// `ROLE` is a string,
///
/// `PATH` is a string.
///
/// ## `TimestampMetadata`
///
/// ```bash
/// {
///   "type": "timestamp",
///   "version": NATURAL_NUMBER,
///   "expires": EXPIRES,
///   "snapshot": METADATA_DESCRIPTION
/// }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Json {}
impl DataInterchange for Json {
    type RawData = json::Value;

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    ///
    /// assert_eq!(Json::extension(), "json");
    /// ```
    fn extension() -> &'static str {
        "json"
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// let jsn: &[u8] = br#"{"foo": "bar", "baz": "quux"}"#;
    /// let raw = Json::from_reader(jsn).unwrap();
    /// let out = Json::canonicalize(&raw).unwrap();
    /// assert_eq!(out, br#"{"baz":"quux","foo":"bar"}"#);
    /// ```
    fn canonicalize(raw_data: &Self::RawData) -> Result<Vec<u8>> {
        cjson::canonicalize(raw_data).map_err(|e| Error::Opaque(e))
    }

    /// ```
    /// #[macro_use]
    /// extern crate serde_derive;
    /// #[macro_use]
    /// extern crate serde_json;
    /// extern crate tuf;
    ///
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// #[derive(Deserialize, Debug, PartialEq)]
    /// struct Thing {
    ///    foo: String,
    ///    bar: String,
    /// }
    ///
    /// fn main() {
    ///     let jsn = json!({"foo": "wat", "bar": "lol"});
    ///     let thing = Thing { foo: "wat".into(), bar: "lol".into() };
    ///     let de: Thing = Json::deserialize(&jsn).unwrap();
    ///     assert_eq!(de, thing);
    /// }
    /// ```
    fn deserialize<T>(raw_data: &Self::RawData) -> Result<T>
    where
        T: DeserializeOwned,
    {
        Ok(json::from_value(raw_data.clone())?)
    }

    /// ```
    /// #[macro_use]
    /// extern crate serde_derive;
    /// #[macro_use]
    /// extern crate serde_json;
    /// extern crate tuf;
    ///
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// #[derive(Serialize)]
    /// struct Thing {
    ///    foo: String,
    ///    bar: String,
    /// }
    ///
    /// fn main() {
    ///     let jsn = json!({"foo": "wat", "bar": "lol"});
    ///     let thing = Thing { foo: "wat".into(), bar: "lol".into() };
    ///     let se: serde_json::Value = Json::serialize(&thing).unwrap();
    ///     assert_eq!(se, jsn);
    /// }
    /// ```
    fn serialize<T>(data: &T) -> Result<Self::RawData>
    where
        T: Serialize,
    {
        Ok(json::to_value(data)?)
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    ///
    /// let arr = vec![1, 2, 3];
    /// let mut buf = Vec::new();
    /// Json::to_writer(&mut buf, &arr).unwrap();
    /// assert!(&buf == b"[1, 2, 3]" || &buf == b"[1,2,3]");
    /// ```
    fn to_writer<W, T: Sized>(mut writer: W, value: &T) -> Result<()>
    where
        W: Write,
        T: Serialize,
    {
        let bytes = Self::canonicalize(&Self::serialize(value)?)?;
        writer.write_all(&bytes)?;
        Ok(())
    }

    /// ```
    /// use tuf::interchange::{DataInterchange, Json};
    /// use std::collections::HashMap;
    ///
    /// let jsn: &[u8] = br#"{"foo": "bar", "baz": "quux"}"#;
    /// let _: HashMap<String, String> = Json::from_reader(jsn).unwrap();
    /// ```
    fn from_reader<R, T>(rdr: R) -> Result<T>
    where
        R: Read,
        T: DeserializeOwned,
    {
        Ok(json::from_reader(rdr)?)
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))]
#![cfg_attr(feature = "cargo-clippy", allow(explicit_iter_loop))]

use cargo;
use filetime;

use git2;

use hex;
#[macro_use]
extern crate lazy_static;
use libc;
#[macro_use]
extern crate proptest;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

use toml;

#[cfg(windows)]
extern crate winapi;

#[macro_use]
mod support;

mod alt_registry;
mod bad_config;
mod bad_manifest_path;
mod bench;
mod build;
mod build_auth;
mod build_lib;
mod build_plan;
mod build_script;
mod build_script_env;
mod cargo_alias_config;
mod cargo_command;
mod cargo_features;
mod cfg;
mod check;
mod clean;
mod collisions;
mod concurrent;
mod config;
mod corrupt_git;
mod cross_compile;
mod cross_publish;
mod custom_target;
mod death;
mod dep_info;
mod directory;
mod doc;
mod edition;
mod features;
mod fetch;
mod fix;
mod freshness;
mod generate_lockfile;
mod git;
mod init;
mod install;
mod jobserver;
mod local_registry;
mod lockfile_compat;
mod login;
mod member_errors;
mod metabuild;
mod metadata;
mod net_config;
mod new;
mod out_dir;
mod overrides;
mod package;
mod patch;
mod path;
mod plugins;
mod proc_macro;
mod profile_config;
mod profile_overrides;
mod profile_targets;
mod profiles;
mod publish;
mod read_manifest;
mod registry;
mod rename_deps;
mod required_features;
mod resolve;
mod run;
mod rustc;
mod rustc_info_cache;
mod rustdoc;
mod rustdocflags;
mod rustflags;
mod search;
mod shell_quoting;
mod small_fd_limits;
mod test;
mod tool_paths;
mod update;
mod verify_project;
mod version;
mod warn_on_failure;
mod workspaces;

#[test]
fn aaa_trigger_cross_compile_disabled_check() {
    // This triggers the cross compile disabled check to run ASAP, see #5141
    support::cross_compile::disabled();
}
<commit_msg>Remove unused imports<commit_after>#![deny(warnings)]
#![cfg_attr(feature = "cargo-clippy", allow(blacklisted_name))]
#![cfg_attr(feature = "cargo-clippy", allow(explicit_iter_loop))]

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate proptest;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

#[macro_use]
mod support;

mod alt_registry;
mod bad_config;
mod bad_manifest_path;
mod bench;
mod build;
mod build_auth;
mod build_lib;
mod build_plan;
mod build_script;
mod build_script_env;
mod cargo_alias_config;
mod cargo_command;
mod cargo_features;
mod cfg;
mod check;
mod clean;
mod collisions;
mod concurrent;
mod config;
mod corrupt_git;
mod cross_compile;
mod cross_publish;
mod custom_target;
mod death;
mod dep_info;
mod directory;
mod doc;
mod edition;
mod features;
mod fetch;
mod fix;
mod freshness;
mod generate_lockfile;
mod git;
mod init;
mod install;
mod jobserver;
mod local_registry;
mod lockfile_compat;
mod login;
mod member_errors;
mod metabuild;
mod metadata;
mod net_config;
mod new;
mod out_dir;
mod overrides;
mod package;
mod patch;
mod path;
mod plugins;
mod proc_macro;
mod profile_config;
mod profile_overrides;
mod profile_targets;
mod profiles;
mod publish;
mod read_manifest;
mod registry;
mod rename_deps;
mod required_features;
mod resolve;
mod run;
mod rustc;
mod rustc_info_cache;
mod rustdoc;
mod rustdocflags;
mod rustflags;
mod search;
mod shell_quoting;
mod small_fd_limits;
mod test;
mod tool_paths;
mod update;
mod verify_project;
mod version;
mod warn_on_failure;
mod workspaces;

#[test]
fn aaa_trigger_cross_compile_disabled_check() {
    // This triggers the cross compile disabled check to run ASAP, see #5141
    support::cross_compile::disabled();
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Finally trait provides a method, `finally` on
//! stack closures that emulates Java-style try/finally blocks.
//!
//! Using the `finally` method is sometimes convenient, but the type rules
//! prohibit any shared, mutable state between the "try" case and the
//! "finally" case. For advanced cases, the `try_finally` function can
//! also be used. See that function for more details.
//!
//! # Example
//!
//! ```
//! # #![feature(unboxed_closures)]
//!
//! use std::finally::Finally;
//!
//! (|| {
//!     // ...
//! }).finally(|| {
//!     // this code is always run
//! })
//! ```

#![unstable(feature = "core")]
#![deprecated(since = "1.0.0",
              reason = "It is unclear if this module is more robust than implementing \
                        Drop on a custom type, and this module is being removed with no \
                        replacement. Use a custom Drop implementation to regain existing \
                        functionality.")]
#![allow(deprecated)]

use ops::{Drop, FnMut, FnOnce};

/// A trait for executing a destructor unconditionally after a block of code,
/// regardless of whether the blocked fails.
pub trait Finally<T> {
    /// Executes this object, unconditionally running `dtor` after this block of
    /// code has run.
    fn finally<F>(&mut self, dtor: F) -> T where F: FnMut();
}

impl<T, F> Finally<T> for F where F: FnMut() -> T {
    fn finally<G>(&mut self, mut dtor: G) -> T where G: FnMut() {
        try_finally(&mut (), self, |_, f| (*f)(), |_| dtor())
    }
}

/// The most general form of the `finally` functions. The function
/// `try_fn` will be invoked first; whether or not it panics, the
/// function `finally_fn` will be invoked next. The two parameters
/// `mutate` and `drop` are used to thread state through the two
/// closures. `mutate` is used for any shared, mutable state that both
/// closures require access to; `drop` is used for any state that the
/// `try_fn` requires ownership of.
///
/// **WARNING:** While shared, mutable state between the try and finally
/// function is often necessary, one must be very careful; the `try`
/// function could have panicked at any point, so the values of the shared
/// state may be inconsistent.
///
/// # Example
///
/// ```
/// use std::finally::try_finally;
///
/// struct State<'a> { buffer: &'a mut [u8], len: uint }
/// # let mut buf = [];
/// let mut state = State { buffer: &mut buf, len: 0 };
/// try_finally(
///     &mut state, (),
///     |state, ()| {
///         // use state.buffer, state.len
///     },
///     |state| {
///         // use state.buffer, state.len to cleanup
///     })
/// ```
pub fn try_finally<T, U, R, F, G>(mutate: &mut T, drop: U, try_fn: F, finally_fn: G) -> R where
    F: FnOnce(&mut T, U) -> R,
    G: FnMut(&mut T),
{
    let f = Finallyalizer {
        mutate: mutate,
        dtor: finally_fn,
    };
    try_fn(&mut *f.mutate, drop)
}

struct Finallyalizer<'a, A:'a, F> where F: FnMut(&mut A) {
    mutate: &'a mut A,
    dtor: F,
}

#[unsafe_destructor]
impl<'a, A, F> Drop for Finallyalizer<'a, A, F> where F: FnMut(&mut A) {
    #[inline]
    fn drop(&mut self) {
        (self.dtor)(self.mutate);
    }
}

<commit_msg>Audit integer types in finally.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Finally trait provides a method, `finally` on
//! stack closures that emulates Java-style try/finally blocks.
//!
//! Using the `finally` method is sometimes convenient, but the type rules
//! prohibit any shared, mutable state between the "try" case and the
//! "finally" case. For advanced cases, the `try_finally` function can
//! also be used. See that function for more details.
//!
//! # Example
//!
//! ```
//! # #![feature(unboxed_closures)]
//!
//! use std::finally::Finally;
//!
//! (|| {
//!     // ...
//! }).finally(|| {
//!     // this code is always run
//! })
//! ```

#![unstable(feature = "core")]
#![deprecated(since = "1.0.0",
              reason = "It is unclear if this module is more robust than implementing \
                        Drop on a custom type, and this module is being removed with no \
                        replacement. Use a custom Drop implementation to regain existing \
                        functionality.")]
#![allow(deprecated)]

use ops::{Drop, FnMut, FnOnce};

/// A trait for executing a destructor unconditionally after a block of code,
/// regardless of whether the blocked fails.
pub trait Finally<T> {
    /// Executes this object, unconditionally running `dtor` after this block of
    /// code has run.
    fn finally<F>(&mut self, dtor: F) -> T where F: FnMut();
}

impl<T, F> Finally<T> for F where F: FnMut() -> T {
    fn finally<G>(&mut self, mut dtor: G) -> T where G: FnMut() {
        try_finally(&mut (), self, |_, f| (*f)(), |_| dtor())
    }
}

/// The most general form of the `finally` functions. The function
/// `try_fn` will be invoked first; whether or not it panics, the
/// function `finally_fn` will be invoked next. The two parameters
/// `mutate` and `drop` are used to thread state through the two
/// closures. `mutate` is used for any shared, mutable state that both
/// closures require access to; `drop` is used for any state that the
/// `try_fn` requires ownership of.
///
/// **WARNING:** While shared, mutable state between the try and finally
/// function is often necessary, one must be very careful; the `try`
/// function could have panicked at any point, so the values of the shared
/// state may be inconsistent.
///
/// # Example
///
/// ```
/// use std::finally::try_finally;
///
/// struct State<'a> { buffer: &'a mut [u8], len: usize }
/// # let mut buf = [];
/// let mut state = State { buffer: &mut buf, len: 0 };
/// try_finally(
///     &mut state, (),
///     |state, ()| {
///         // use state.buffer, state.len
///     },
///     |state| {
///         // use state.buffer, state.len to cleanup
///     })
/// ```
pub fn try_finally<T, U, R, F, G>(mutate: &mut T, drop: U, try_fn: F, finally_fn: G) -> R where
    F: FnOnce(&mut T, U) -> R,
    G: FnMut(&mut T),
{
    let f = Finallyalizer {
        mutate: mutate,
        dtor: finally_fn,
    };
    try_fn(&mut *f.mutate, drop)
}

struct Finallyalizer<'a, A:'a, F> where F: FnMut(&mut A) {
    mutate: &'a mut A,
    dtor: F,
}

#[unsafe_destructor]
impl<'a, A, F> Drop for Finallyalizer<'a, A, F> where F: FnMut(&mut A) {
    #[inline]
    fn drop(&mut self) {
        (self.dtor)(self.mutate);
    }
}

<|endoftext|>