<commit_before>use std::fmt;
use std::io;
use std::str::FromStr;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;

use chrono::{DateTime, Local};
use slog;
use slog::DrainExt;
use slog_atomic::{AtomicSwitch, AtomicSwitchCtrl};
use slog_stream::{stream, Format, Streamer};
use slog::Level as SlogLevel;
use slog::{LevelFilter, Logger};
use slog::{OwnedKeyValueList, Record};
use slog_stdlog;

lazy_static! {
    static ref ATOMIC_DRAIN: AtomicSwitchCtrl<io::Error> = AtomicSwitch::new(
        slog::Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should not happen"))
    ).ctrl();
    static ref FIRST_RUN: AtomicBool = AtomicBool::new(true);
}

static DEFAULT_LEVEL: &'static LogLevel = &LogLevel::Info;

/// Logger levels from [Log.jsm]
/// (https://developer.mozilla.org/en/docs/Mozilla/JavaScript_code_modules/Log.jsm).
#[derive(Debug, Clone)]
pub enum LogLevel {
    Fatal,
    Error,
    Warn,
    Info,
    Config,
    Debug,
    Trace,
}

impl fmt::Display for LogLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            LogLevel::Fatal => "FATAL",
            LogLevel::Error => "ERROR",
            LogLevel::Warn => "WARN",
            LogLevel::Info => "INFO",
            LogLevel::Config => "CONFIG",
            LogLevel::Debug => "DEBUG",
            LogLevel::Trace => "TRACE",
        };
        write!(f, "{}", s)
    }
}

impl FromStr for LogLevel {
    type Err = ();

    fn from_str(s: &str) -> Result<LogLevel, ()> {
        match s {
            "fatal" => Ok(LogLevel::Fatal),
            "error" => Ok(LogLevel::Error),
            "warn" => Ok(LogLevel::Warn),
            "info" => Ok(LogLevel::Info),
            "config" => Ok(LogLevel::Config),
            "debug" => Ok(LogLevel::Debug),
            "trace" => Ok(LogLevel::Trace),
            _ => Err(()),
        }
    }
}

trait ToSlogLevel {
    fn to_slog(&self) -> SlogLevel;
}

impl ToSlogLevel for LogLevel {
    fn to_slog(&self) -> SlogLevel {
        match *self {
            LogLevel::Fatal => SlogLevel::Critical,
            LogLevel::Error => SlogLevel::Error,
            LogLevel::Warn => SlogLevel::Warning,
            LogLevel::Info => SlogLevel::Info,
            LogLevel::Config | LogLevel::Debug => SlogLevel::Debug,
            LogLevel::Trace => SlogLevel::Trace,
        }
    }
}

trait ToGeckoLevel {
    fn to_gecko(&self) -> LogLevel;
}

impl ToGeckoLevel for SlogLevel {
    fn to_gecko(&self) -> LogLevel {
        match *self {
            SlogLevel::Critical => LogLevel::Fatal,
            SlogLevel::Error => LogLevel::Error,
            SlogLevel::Warning => LogLevel::Warn,
            SlogLevel::Info => LogLevel::Info,
            SlogLevel::Debug => LogLevel::Debug,
            SlogLevel::Trace => LogLevel::Trace,
        }
    }
}

/// Initialise logger if it has not been already.  The provided `level`
/// filters out log records below this granularity.
pub fn init(level: &Option<LogLevel>) {
    let effective_level = level.as_ref().unwrap_or(DEFAULT_LEVEL);

    let drain = filtered_gecko_log(&effective_level);
    ATOMIC_DRAIN.set(drain);

    let first_run = FIRST_RUN.load(SeqCst);
    FIRST_RUN.store(false, SeqCst);
    if first_run {
        let log = Logger::root(ATOMIC_DRAIN.drain().fuse(), o!());
        slog_stdlog::set_logger(log.clone()).unwrap();
    }
}

fn filtered_gecko_log(level: &LogLevel) -> LevelFilter<Streamer<io::Stderr, GeckoFormat>> {
    let io = stream(io::stderr(), GeckoFormat {});
    slog::level_filter(level.to_slog(), io)
}

struct GeckoFormat;

impl Format for GeckoFormat {
    fn format(&self, io: &mut io::Write, record: &Record, _: &OwnedKeyValueList) -> io::Result<()> {
        let ts = format_ts(Local::now());
        let level = record.level().to_gecko();
        let _ = try!(write!(io,
                            "{}\t{}\t{}\t{}\n",
                            ts,
                            record.module(),
                            level,
                            record.msg()));
        Ok(())
    }
}

/// Produces a 13-digit Unix Epoch timestamp similar to Gecko.
fn format_ts(ts: DateTime<Local>) -> String {
    format!("{}{:03}", ts.timestamp(), ts.timestamp_subsec_millis())
}

#[cfg(test)]
mod tests {
    use chrono::Local;
    use super::format_ts;

    #[test]
    fn test_format_ts() {
        let ts = Local::now();
        let s = format_ts(ts);
        assert_eq!(s.len(), 13);
    }
}
<commit_msg>logging: ignore records from other modules<commit_after>use std::fmt;
use std::io;
use std::str::FromStr;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;

use chrono::{DateTime, Local};
use slog;
use slog::DrainExt;
use slog_atomic::{AtomicSwitch, AtomicSwitchCtrl};
use slog_stream::{stream, Format, Streamer};
use slog::Level as SlogLevel;
use slog::{LevelFilter, Logger};
use slog::{OwnedKeyValueList, Record};
use slog_stdlog;

lazy_static! {
    static ref ATOMIC_DRAIN: AtomicSwitchCtrl<io::Error> = AtomicSwitch::new(
        slog::Discard.map_err(|_| io::Error::new(io::ErrorKind::Other, "should not happen"))
    ).ctrl();
    static ref FIRST_RUN: AtomicBool = AtomicBool::new(true);
}

static DEFAULT_LEVEL: &'static LogLevel = &LogLevel::Info;

/// Logger levels from [Log.jsm]
/// (https://developer.mozilla.org/en/docs/Mozilla/JavaScript_code_modules/Log.jsm).
#[derive(Debug, Clone)]
pub enum LogLevel {
    Fatal,
    Error,
    Warn,
    Info,
    Config,
    Debug,
    Trace,
}

impl fmt::Display for LogLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s = match *self {
            LogLevel::Fatal => "FATAL",
            LogLevel::Error => "ERROR",
            LogLevel::Warn => "WARN",
            LogLevel::Info => "INFO",
            LogLevel::Config => "CONFIG",
            LogLevel::Debug => "DEBUG",
            LogLevel::Trace => "TRACE",
        };
        write!(f, "{}", s)
    }
}

impl FromStr for LogLevel {
    type Err = ();

    fn from_str(s: &str) -> Result<LogLevel, ()> {
        match s {
            "fatal" => Ok(LogLevel::Fatal),
            "error" => Ok(LogLevel::Error),
            "warn" => Ok(LogLevel::Warn),
            "info" => Ok(LogLevel::Info),
            "config" => Ok(LogLevel::Config),
            "debug" => Ok(LogLevel::Debug),
            "trace" => Ok(LogLevel::Trace),
            _ => Err(()),
        }
    }
}

trait ToSlogLevel {
    fn to_slog(&self) -> SlogLevel;
}

impl ToSlogLevel for LogLevel {
    fn to_slog(&self) -> SlogLevel {
        match *self {
            LogLevel::Fatal => SlogLevel::Critical,
            LogLevel::Error => SlogLevel::Error,
            LogLevel::Warn => SlogLevel::Warning,
            LogLevel::Info => SlogLevel::Info,
            LogLevel::Config | LogLevel::Debug => SlogLevel::Debug,
            LogLevel::Trace => SlogLevel::Trace,
        }
    }
}

trait ToGeckoLevel {
    fn to_gecko(&self) -> LogLevel;
}

impl ToGeckoLevel for SlogLevel {
    fn to_gecko(&self) -> LogLevel {
        match *self {
            SlogLevel::Critical => LogLevel::Fatal,
            SlogLevel::Error => LogLevel::Error,
            SlogLevel::Warning => LogLevel::Warn,
            SlogLevel::Info => LogLevel::Info,
            SlogLevel::Debug => LogLevel::Debug,
            SlogLevel::Trace => LogLevel::Trace,
        }
    }
}

/// Initialise logger if it has not been already.  The provided `level`
/// filters out log records below this granularity.
pub fn init(level: &Option<LogLevel>) {
    let effective_level = level.as_ref().unwrap_or(DEFAULT_LEVEL);

    let drain = filtered_gecko_log(&effective_level);
    ATOMIC_DRAIN.set(drain);

    let first_run = FIRST_RUN.load(SeqCst);
    FIRST_RUN.store(false, SeqCst);
    if first_run {
        let log = Logger::root(ATOMIC_DRAIN.drain().fuse(), o!());
        slog_stdlog::set_logger(log.clone()).unwrap();
    }
}

fn filtered_gecko_log(level: &LogLevel) -> LevelFilter<Streamer<io::Stderr, GeckoFormat>> {
    let io = stream(io::stderr(), GeckoFormat {});
    slog::level_filter(level.to_slog(), io)
}

struct GeckoFormat;

impl Format for GeckoFormat {
    fn format(&self, io: &mut io::Write, record: &Record, _: &OwnedKeyValueList) -> io::Result<()> {
        // TODO(ato): Quite sure this is the wrong way to filter records with slog,
        // but I do not comprehend how slog works.
        let module = record.module();
        if module.starts_with("geckodriver") || module.starts_with("webdriver") {
            let ts = format_ts(Local::now());
            let level = record.level().to_gecko();
            let _ = try!(write!(io, "{}\t{}\t{}\t{}\n", ts, module, level, record.msg()));
        }
        Ok(())
    }
}

/// Produces a 13-digit Unix Epoch timestamp similar to Gecko.
fn format_ts(ts: DateTime<Local>) -> String {
    format!("{}{:03}", ts.timestamp(), ts.timestamp_subsec_millis())
}

#[cfg(test)]
mod tests {
    use chrono::Local;
    use super::format_ts;

    #[test]
    fn test_format_ts() {
        let ts = Local::now();
        let s = format_ts(ts);
        assert_eq!(s.len(), 13);
    }
}
<|endoftext|>


<commit_before>// min-llvm-version: 10.0.1
// FIXME(#84025): codegen-units=1 leads to linkage errors
// compile-flags: -C codegen-units=2
// only-x86_64
// only-linux
// run-pass

#![feature(asm, thread_local)]

extern "C" fn f1() -> i32 {
    111
}

// The compiler will generate a shim to hide the caller location parameter.
#[track_caller]
fn f2() -> i32 {
    222
}

macro_rules! call {
    ($func:path) => {
        unsafe {
            let result: i32;
            asm!("call {}", sym $func,
                out("rax") result,
                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
            );
            result
        }
    }
}

macro_rules! static_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            // LEA performs a RIP-relative address calculation and returns the address
            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
            result
        }
    }
}
macro_rules! static_tls_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            asm!(
                "
                    # Load TLS base address
                    mov {out}, qword ptr fs:[0]
                    # Calculate the address of sym in the TLS block. The @tpoff
                    # relocation gives the offset of the symbol from the start
                    # of the TLS block.
                    lea {out}, [{out} + {sym}@tpoff]
                ",
                out = out(reg) result,
                sym = sym $s
            );
            result
        }
    }
}

static S1: u32 = 111;
#[thread_local]
static S2: u32 = 222;

fn main() {
    assert_eq!(call!(f1), 111);
    assert_eq!(call!(f2), 222);
    assert_eq!(static_addr!(S1), &S1 as *const u32);
    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    std::thread::spawn(|| {
        assert_eq!(static_addr!(S1), &S1 as *const u32);
        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    }).join().unwrap();
}
<commit_msg>Update LLVM submodule<commit_after>// min-llvm-version: 10.0.1
// only-x86_64
// only-linux
// run-pass

#![feature(asm, thread_local)]

extern "C" fn f1() -> i32 {
    111
}

// The compiler will generate a shim to hide the caller location parameter.
#[track_caller]
fn f2() -> i32 {
    222
}

macro_rules! call {
    ($func:path) => {
        unsafe {
            let result: i32;
            asm!("call {}", sym $func,
                out("rax") result,
                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
            );
            result
        }
    }
}

macro_rules! static_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            // LEA performs a RIP-relative address calculation and returns the address
            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
            result
        }
    }
}
macro_rules! static_tls_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            asm!(
                "
                    # Load TLS base address
                    mov {out}, qword ptr fs:[0]
                    # Calculate the address of sym in the TLS block. The @tpoff
                    # relocation gives the offset of the symbol from the start
                    # of the TLS block.
                    lea {out}, [{out} + {sym}@tpoff]
                ",
                out = out(reg) result,
                sym = sym $s
            );
            result
        }
    }
}

static S1: u32 = 111;
#[thread_local]
static S2: u32 = 222;

fn main() {
    assert_eq!(call!(f1), 111);
    assert_eq!(call!(f2), 222);
    assert_eq!(static_addr!(S1), &S1 as *const u32);
    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    std::thread::spawn(|| {
        assert_eq!(static_addr!(S1), &S1 as *const u32);
        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    }).join().unwrap();
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add, Div, Sub, Neg};

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

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

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> 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>Implemented basic 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::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];
                    }
                }
            }
        }
    }

    /// Eigendecomposition of a square matrix.
    ///
    /// Returns a Vec of eigen values and the eigen vectors.
    ///
    /// # 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)
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use crate::with_unknown;

with_unknown! {
    /// From `//sw/device/lib/base/hardened.h`.
    pub enum HardenedBool: u32 {
        True= bindgen::hardened::hardened_bool_kHardenedBoolTrue as u32,
        False= bindgen::hardened::hardened_bool_kHardenedBoolFalse as u32,
    }

    /// From `//sw/device/lib/base/hardened.h`.
    pub enum HardenedByteBool: u8 {
        True= bindgen::hardened::hardened_byte_bool_kHardenedByteBoolTrue as u8,
        False= bindgen::hardened::hardened_byte_bool_kHardenedByteBoolFalse as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool4: u8 {
        True= bindgen::multibits::multi_bit_bool_kMultiBitBool4True as u8,
        False= bindgen::multibits::multi_bit_bool_kMultiBitBool4False as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool8: u8 {
        True= bindgen::multibits::multi_bit_bool_kMultiBitBool8True as u8,
        False= bindgen::multibits::multi_bit_bool_kMultiBitBool8False as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool12: u16 {
        True= bindgen::multibits::multi_bit_bool_kMultiBitBool12True as u16,
        False= bindgen::multibits::multi_bit_bool_kMultiBitBool12False as u16,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool16: u16 {
        True= bindgen::multibits::multi_bit_bool_kMultiBitBool16True as u16,
        False= bindgen::multibits::multi_bit_bool_kMultiBitBool16False as u16,
    }
}
<commit_msg>[cleanup] Fix formatting<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use crate::with_unknown;

with_unknown! {
    /// From `//sw/device/lib/base/hardened.h`.
    pub enum HardenedBool: u32 {
        True = bindgen::hardened::hardened_bool_kHardenedBoolTrue as u32,
        False = bindgen::hardened::hardened_bool_kHardenedBoolFalse as u32,
    }

    /// From `//sw/device/lib/base/hardened.h`.
    pub enum HardenedByteBool: u8 {
        True = bindgen::hardened::hardened_byte_bool_kHardenedByteBoolTrue as u8,
        False = bindgen::hardened::hardened_byte_bool_kHardenedByteBoolFalse as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool4: u8 {
        True = bindgen::multibits::multi_bit_bool_kMultiBitBool4True as u8,
        False = bindgen::multibits::multi_bit_bool_kMultiBitBool4False as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool8: u8 {
        True = bindgen::multibits::multi_bit_bool_kMultiBitBool8True as u8,
        False = bindgen::multibits::multi_bit_bool_kMultiBitBool8False as u8,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool12: u16 {
        True = bindgen::multibits::multi_bit_bool_kMultiBitBool12True as u16,
        False = bindgen::multibits::multi_bit_bool_kMultiBitBool12False as u16,
    }

    /// From `//sw/device/lib/base/multibits.h`.
    pub enum MultiBitBool16: u16 {
        True = bindgen::multibits::multi_bit_bool_kMultiBitBool16True as u16,
        False = bindgen::multibits::multi_bit_bool_kMultiBitBool16False as u16,
    }
}
<|endoftext|>


<commit_before>use std::io::{IoResult, IoError, OtherIoError, MemReader};
use std::mem;

use io::Timeout;
use types::Oid;

use self::BackendMessage::*;
use self::FrontendMessage::*;

pub const PROTOCOL_VERSION: u32 = 0x0003_0000;
pub const CANCEL_CODE: u32 = 80877102;
pub const SSL_CODE: u32 = 80877103;

pub enum BackendMessage {
    AuthenticationCleartextPassword,
    AuthenticationGSS,
    AuthenticationKerberosV5,
    AuthenticationMD5Password {
        salt: [u8, ..4]
    },
    AuthenticationOk,
    AuthenticationSCMCredential,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: u32,
        secret_key: u32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: String,
    },
    CopyInResponse {
        format: u8,
        column_formats: Vec<u16>,
    },
    DataRow {
        row: Vec<Option<Vec<u8>>>
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: Vec<(u8, String)>
    },
    NoData,
    NoticeResponse {
        fields: Vec<(u8, String)>
    },
    NotificationResponse {
        pid: u32,
        channel: String,
        payload: String,
    },
    ParameterDescription {
        types: Vec<Oid>
    },
    ParameterStatus {
        parameter: String,
        value: String,
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        _state: u8
    },
    RowDescription {
        descriptions: Vec<RowDescriptionEntry>
    }
}

pub struct RowDescriptionEntry {
    pub name: String,
    pub table_oid: Oid,
    pub column_id: i16,
    pub type_oid: Oid,
    pub type_size: i16,
    pub type_modifier: i32,
    pub format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<Vec<u8>>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: u32,
        process_id: u32,
        secret_key: u32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    CopyData {
        data: &'a [u8],
    },
    CopyDone,
    CopyFail {
        message: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [Oid]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    SslRequest {
        code: u32
    },
    StartupMessage {
        version: u32,
        parameters: &'a [(String, String)]
    },
    Sync,
    Terminate
}

#[doc(hidden)]
trait WriteCStr {
    fn write_cstr(&mut self, s: &str) -> IoResult<()>;
}

impl<W: Writer> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) -> IoResult<()> {
        try!(self.write(s.as_bytes()));
        self.write_u8(0)
    }
}

#[doc(hidden)]
pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage) -> IoResult<()> ;
}

impl<W: Writer> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) -> IoResult<()> {
        let mut buf = vec![];
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some(b'B');
                try!(buf.write_cstr(portal));
                try!(buf.write_cstr(statement));

                try!(buf.write_be_i16(formats.len() as i16));
                for format in formats.iter() {
                    try!(buf.write_be_i16(*format));
                }

                try!(buf.write_be_i16(values.len() as i16));
                for value in values.iter() {
                    match *value {
                        None => try!(buf.write_be_i32(-1)),
                        Some(ref value) => {
                            try!(buf.write_be_i32(value.len() as i32));
                            try!(buf.write(value[]));
                        }
                    }
                }

                try!(buf.write_be_i16(result_formats.len() as i16));
                for format in result_formats.iter() {
                    try!(buf.write_be_i16(*format));
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                try!(buf.write_be_u32(code));
                try!(buf.write_be_u32(process_id));
                try!(buf.write_be_u32(secret_key));
            }
            Close { variant, name } => {
                ident = Some(b'C');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            CopyData { data } => {
                ident = Some(b'd');
                try!(buf.write(data));
            }
            CopyDone => ident = Some(b'c'),
            CopyFail { message } => {
                ident = Some(b'f');
                try!(buf.write_cstr(message));
            }
            Describe { variant, name } => {
                ident = Some(b'D');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            Execute { portal, max_rows } => {
                ident = Some(b'E');
                try!(buf.write_cstr(portal));
                try!(buf.write_be_i32(max_rows));
            }
            Parse { name, query, param_types } => {
                ident = Some(b'P');
                try!(buf.write_cstr(name));
                try!(buf.write_cstr(query));
                try!(buf.write_be_i16(param_types.len() as i16));
                for ty in param_types.iter() {
                    try!(buf.write_be_u32(*ty));
                }
            }
            PasswordMessage { password } => {
                ident = Some(b'p');
                try!(buf.write_cstr(password));
            }
            Query { query } => {
                ident = Some(b'Q');
                try!(buf.write_cstr(query));
            }
            StartupMessage { version, parameters } => {
                try!(buf.write_be_u32(version));
                for &(ref k, ref v) in parameters.iter() {
                    try!(buf.write_cstr(k[]));
                    try!(buf.write_cstr(v[]));
                }
                try!(buf.write_u8(0));
            }
            SslRequest { code } => try!(buf.write_be_u32(code)),
            Sync => ident = Some(b'S'),
            Terminate => ident = Some(b'X'),
        }

        if let Some(ident) = ident {
            try!(self.write_u8(ident));
        }

        // add size of length value
        try!(self.write_be_i32((buf.len() + mem::size_of::<i32>()) as i32));
        try!(self.write(buf[]));

        Ok(())
    }
}

#[doc(hidden)]
trait ReadCStr {
    fn read_cstr(&mut self) -> IoResult<String>;
}

impl<R: Buffer> ReadCStr for R {
    fn read_cstr(&mut self) -> IoResult<String> {
        let mut buf = try!(self.read_until(0));
        buf.pop();
        String::from_utf8(buf).map_err(|_| IoError {
            kind: OtherIoError,
            desc: "Received a non-utf8 string from server",
            detail: None
        })
    }
}

#[doc(hidden)]
pub trait ReadMessage {
    fn read_message(&mut self) -> IoResult<BackendMessage>;
}

impl<R: Reader+Timeout> ReadMessage for R {
    fn read_message(&mut self) -> IoResult<BackendMessage> {
        // The first byte read is a bit complex to make
        // Notifications::next_block_for work.
        let ident = self.read_u8();
        // At this point we've got to turn off any read timeout to prevent
        // stream desynchronization. We're assuming that if we've got the first
        // byte, there's more stuff to follow.
        self.set_read_timeout(None);
        let ident = try!(ident);

        // subtract size of length value
        let len = try!(self.read_be_u32()) as uint - mem::size_of::<i32>();
        let mut buf = MemReader::new(try!(self.read_exact(len)));

        let ret = match ident {
            b'1' => ParseComplete,
            b'2' => BindComplete,
            b'3' => CloseComplete,
            b'A' => NotificationResponse {
                pid: try!(buf.read_be_u32()),
                channel: try!(buf.read_cstr()),
                payload: try!(buf.read_cstr())
            },
            b'C' => CommandComplete { tag: try!(buf.read_cstr()) },
            b'D' => try!(read_data_row(&mut buf)),
            b'E' => ErrorResponse { fields: try!(read_fields(&mut buf)) },
            b'G' => {
                let format = try!(buf.read_u8());
                let mut column_formats = vec![];
                for _ in range(0, try!(buf.read_be_u16())) {
                    column_formats.push(try!(buf.read_be_u16()));
                }
                CopyInResponse {
                    format: format,
                    column_formats: column_formats,
                }
            }
            b'I' => EmptyQueryResponse,
            b'K' => BackendKeyData {
                process_id: try!(buf.read_be_u32()),
                secret_key: try!(buf.read_be_u32())
            },
            b'n' => NoData,
            b'N' => NoticeResponse { fields: try!(read_fields(&mut buf)) },
            b'R' => try!(read_auth_message(&mut buf)),
            b's' => PortalSuspended,
            b'S' => ParameterStatus {
                parameter: try!(buf.read_cstr()),
                value: try!(buf.read_cstr())
            },
            b't' => try!(read_parameter_description(&mut buf)),
            b'T' => try!(read_row_description(&mut buf)),
            b'Z' => ReadyForQuery { _state: try!(buf.read_u8()) },
            ident => return Err(IoError {
                kind: OtherIoError,
                desc: "Unexpected message tag",
                detail: Some(format!("got {}", ident)),
            })
        };
        Ok(ret)
    }
}

fn read_fields(buf: &mut MemReader) -> IoResult<Vec<(u8, String)>> {
    let mut fields = vec![];
    loop {
        let ty = try!(buf.read_u8());
        if ty == 0 {
            break;
        }

        fields.push((ty, try!(buf.read_cstr())));
    }

    Ok(fields)
}

fn read_data_row(buf: &mut MemReader) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut values = Vec::with_capacity(len);

    for _ in range(0, len) {
        let val = match try!(buf.read_be_i32()) {
            -1 => None,
            len => Some(try!(buf.read_exact(len as uint)))
        };
        values.push(val);
    }

    Ok(DataRow { row: values })
}

fn read_auth_message(buf: &mut MemReader) -> IoResult<BackendMessage> {
    Ok(match try!(buf.read_be_i32()) {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => {
            let mut salt = [0, ..4];
            try!(buf.read_at_least(salt.len(), &mut salt));
            AuthenticationMD5Password { salt: salt }
        },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        val => return Err(IoError {
            kind: OtherIoError,
            desc: "Unexpected authentication tag",
            detail: Some(format!("got {}", val)),
        })
    })
}

fn read_parameter_description(buf: &mut MemReader) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut types = Vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(try!(buf.read_be_u32()));
    }

    Ok(ParameterDescription { types: types })
}

fn read_row_description(buf: &mut MemReader) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut types = Vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(RowDescriptionEntry {
            name: try!(buf.read_cstr()),
            table_oid: try!(buf.read_be_u32()),
            column_id: try!(buf.read_be_i16()),
            type_oid: try!(buf.read_be_u32()),
            type_size: try!(buf.read_be_i16()),
            type_modifier: try!(buf.read_be_i32()),
            format: try!(buf.read_be_i16())
        })
    }

    Ok(RowDescription { descriptions: types })
}
<commit_msg>Cut out some allocation in read_message<commit_after>use std::io::{IoResult, IoError, OtherIoError, ByRefReader};
use std::io::util::LimitReader;
use std::mem;

use io::Timeout;
use types::Oid;

use self::BackendMessage::*;
use self::FrontendMessage::*;

pub const PROTOCOL_VERSION: u32 = 0x0003_0000;
pub const CANCEL_CODE: u32 = 80877102;
pub const SSL_CODE: u32 = 80877103;

pub enum BackendMessage {
    AuthenticationCleartextPassword,
    AuthenticationGSS,
    AuthenticationKerberosV5,
    AuthenticationMD5Password {
        salt: [u8, ..4]
    },
    AuthenticationOk,
    AuthenticationSCMCredential,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: u32,
        secret_key: u32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: String,
    },
    CopyInResponse {
        format: u8,
        column_formats: Vec<u16>,
    },
    DataRow {
        row: Vec<Option<Vec<u8>>>
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: Vec<(u8, String)>
    },
    NoData,
    NoticeResponse {
        fields: Vec<(u8, String)>
    },
    NotificationResponse {
        pid: u32,
        channel: String,
        payload: String,
    },
    ParameterDescription {
        types: Vec<Oid>
    },
    ParameterStatus {
        parameter: String,
        value: String,
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        _state: u8
    },
    RowDescription {
        descriptions: Vec<RowDescriptionEntry>
    }
}

pub struct RowDescriptionEntry {
    pub name: String,
    pub table_oid: Oid,
    pub column_id: i16,
    pub type_oid: Oid,
    pub type_size: i16,
    pub type_modifier: i32,
    pub format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<Vec<u8>>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: u32,
        process_id: u32,
        secret_key: u32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    CopyData {
        data: &'a [u8],
    },
    CopyDone,
    CopyFail {
        message: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [Oid]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    SslRequest {
        code: u32
    },
    StartupMessage {
        version: u32,
        parameters: &'a [(String, String)]
    },
    Sync,
    Terminate
}

#[doc(hidden)]
trait WriteCStr {
    fn write_cstr(&mut self, s: &str) -> IoResult<()>;
}

impl<W: Writer> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) -> IoResult<()> {
        try!(self.write(s.as_bytes()));
        self.write_u8(0)
    }
}

#[doc(hidden)]
pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage) -> IoResult<()> ;
}

impl<W: Writer> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) -> IoResult<()> {
        let mut buf = vec![];
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some(b'B');
                try!(buf.write_cstr(portal));
                try!(buf.write_cstr(statement));

                try!(buf.write_be_i16(formats.len() as i16));
                for format in formats.iter() {
                    try!(buf.write_be_i16(*format));
                }

                try!(buf.write_be_i16(values.len() as i16));
                for value in values.iter() {
                    match *value {
                        None => try!(buf.write_be_i32(-1)),
                        Some(ref value) => {
                            try!(buf.write_be_i32(value.len() as i32));
                            try!(buf.write(value[]));
                        }
                    }
                }

                try!(buf.write_be_i16(result_formats.len() as i16));
                for format in result_formats.iter() {
                    try!(buf.write_be_i16(*format));
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                try!(buf.write_be_u32(code));
                try!(buf.write_be_u32(process_id));
                try!(buf.write_be_u32(secret_key));
            }
            Close { variant, name } => {
                ident = Some(b'C');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            CopyData { data } => {
                ident = Some(b'd');
                try!(buf.write(data));
            }
            CopyDone => ident = Some(b'c'),
            CopyFail { message } => {
                ident = Some(b'f');
                try!(buf.write_cstr(message));
            }
            Describe { variant, name } => {
                ident = Some(b'D');
                try!(buf.write_u8(variant));
                try!(buf.write_cstr(name));
            }
            Execute { portal, max_rows } => {
                ident = Some(b'E');
                try!(buf.write_cstr(portal));
                try!(buf.write_be_i32(max_rows));
            }
            Parse { name, query, param_types } => {
                ident = Some(b'P');
                try!(buf.write_cstr(name));
                try!(buf.write_cstr(query));
                try!(buf.write_be_i16(param_types.len() as i16));
                for ty in param_types.iter() {
                    try!(buf.write_be_u32(*ty));
                }
            }
            PasswordMessage { password } => {
                ident = Some(b'p');
                try!(buf.write_cstr(password));
            }
            Query { query } => {
                ident = Some(b'Q');
                try!(buf.write_cstr(query));
            }
            StartupMessage { version, parameters } => {
                try!(buf.write_be_u32(version));
                for &(ref k, ref v) in parameters.iter() {
                    try!(buf.write_cstr(k[]));
                    try!(buf.write_cstr(v[]));
                }
                try!(buf.write_u8(0));
            }
            SslRequest { code } => try!(buf.write_be_u32(code)),
            Sync => ident = Some(b'S'),
            Terminate => ident = Some(b'X'),
        }

        if let Some(ident) = ident {
            try!(self.write_u8(ident));
        }

        // add size of length value
        try!(self.write_be_i32((buf.len() + mem::size_of::<i32>()) as i32));
        try!(self.write(buf[]));

        Ok(())
    }
}

#[doc(hidden)]
trait ReadCStr {
    fn read_cstr(&mut self) -> IoResult<String>;
}

impl<R: Buffer> ReadCStr for R {
    fn read_cstr(&mut self) -> IoResult<String> {
        let mut buf = try!(self.read_until(0));
        buf.pop();
        String::from_utf8(buf).map_err(|_| IoError {
            kind: OtherIoError,
            desc: "Received a non-utf8 string from server",
            detail: None
        })
    }
}

#[doc(hidden)]
pub trait ReadMessage {
    fn read_message(&mut self) -> IoResult<BackendMessage>;
}

impl<R: Buffer+Timeout> ReadMessage for R {
    fn read_message(&mut self) -> IoResult<BackendMessage> {
        // The first byte read is a bit complex to make
        // Notifications::next_block_for work.
        let ident = self.read_u8();
        // At this point we've got to turn off any read timeout to prevent
        // stream desynchronization. We're assuming that if we've got the first
        // byte, there's more stuff to follow.
        self.set_read_timeout(None);
        let ident = try!(ident);

        // subtract size of length value
        let len = try!(self.read_be_u32()) as uint - mem::size_of::<i32>();
        let mut rdr = LimitReader::new(self.by_ref(), len);

        let ret = match ident {
            b'1' => ParseComplete,
            b'2' => BindComplete,
            b'3' => CloseComplete,
            b'A' => NotificationResponse {
                pid: try!(rdr.read_be_u32()),
                channel: try!(rdr.read_cstr()),
                payload: try!(rdr.read_cstr())
            },
            b'C' => CommandComplete { tag: try!(rdr.read_cstr()) },
            b'D' => try!(read_data_row(&mut rdr)),
            b'E' => ErrorResponse { fields: try!(read_fields(&mut rdr)) },
            b'G' => {
                let format = try!(rdr.read_u8());
                let mut column_formats = vec![];
                for _ in range(0, try!(rdr.read_be_u16())) {
                    column_formats.push(try!(rdr.read_be_u16()));
                }
                CopyInResponse {
                    format: format,
                    column_formats: column_formats,
                }
            }
            b'I' => EmptyQueryResponse,
            b'K' => BackendKeyData {
                process_id: try!(rdr.read_be_u32()),
                secret_key: try!(rdr.read_be_u32())
            },
            b'n' => NoData,
            b'N' => NoticeResponse { fields: try!(read_fields(&mut rdr)) },
            b'R' => try!(read_auth_message(&mut rdr)),
            b's' => PortalSuspended,
            b'S' => ParameterStatus {
                parameter: try!(rdr.read_cstr()),
                value: try!(rdr.read_cstr())
            },
            b't' => try!(read_parameter_description(&mut rdr)),
            b'T' => try!(read_row_description(&mut rdr)),
            b'Z' => ReadyForQuery { _state: try!(rdr.read_u8()) },
            ident => return Err(IoError {
                kind: OtherIoError,
                desc: "Unexpected message tag",
                detail: Some(format!("got {}", ident)),
            })
        };
        if rdr.limit() != 0 {
            return Err(IoError {
                kind: OtherIoError,
                desc: "didn't read entire message",
                detail: None,
            });
        }
        Ok(ret)
    }
}

fn read_fields<R: Buffer>(buf: &mut R) -> IoResult<Vec<(u8, String)>> {
    let mut fields = vec![];
    loop {
        let ty = try!(buf.read_u8());
        if ty == 0 {
            break;
        }

        fields.push((ty, try!(buf.read_cstr())));
    }

    Ok(fields)
}

fn read_data_row<R: Buffer>(buf: &mut R) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut values = Vec::with_capacity(len);

    for _ in range(0, len) {
        let val = match try!(buf.read_be_i32()) {
            -1 => None,
            len => Some(try!(buf.read_exact(len as uint)))
        };
        values.push(val);
    }

    Ok(DataRow { row: values })
}

fn read_auth_message<R: Buffer>(buf: &mut R) -> IoResult<BackendMessage> {
    Ok(match try!(buf.read_be_i32()) {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => {
            let mut salt = [0, ..4];
            try!(buf.read_at_least(salt.len(), &mut salt));
            AuthenticationMD5Password { salt: salt }
        },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        val => return Err(IoError {
            kind: OtherIoError,
            desc: "Unexpected authentication tag",
            detail: Some(format!("got {}", val)),
        })
    })
}

fn read_parameter_description<R: Buffer>(buf: &mut R) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut types = Vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(try!(buf.read_be_u32()));
    }

    Ok(ParameterDescription { types: types })
}

fn read_row_description<R: Buffer>(buf: &mut R) -> IoResult<BackendMessage> {
    let len = try!(buf.read_be_i16()) as uint;
    let mut types = Vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(RowDescriptionEntry {
            name: try!(buf.read_cstr()),
            table_oid: try!(buf.read_be_u32()),
            column_id: try!(buf.read_be_i16()),
            type_oid: try!(buf.read_be_u32()),
            type_size: try!(buf.read_be_i16()),
            type_modifier: try!(buf.read_be_i32()),
            format: try!(buf.read_be_i16())
        })
    }

    Ok(RowDescription { descriptions: types })
}
<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self) {
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let io_registers_state = memory.ppu_ctrl_registers_status();
        for (index, state) in io_registers_state.iter().enumerate() {
            println!("PPU REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let io_registers_state = memory.misc_ctrl_registers_status();
        for (index, state) in io_registers_state.iter().enumerate() {
            println!("MISC REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);

        log::log("ppu", "PPU cycle complete", &self.runtime_options);
        0
    }
}
<commit_msg>Added DMA stub code<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

use nes::memory::{
    MISC_CTRL_REGISTERS_SIZE,
};

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self) {
    }

    /// Reads the contents of the DMA register and executes DMA if written since
    /// the last PPU cycle.
    fn handle_dma_register<M: Memory>(&mut self, index: usize, state: MiscRegisterStatus, memory: &mut M) {
        if state != MiscRegisterStatus::Written {
            return;
        }
        let register = memory.misc_ctrl_registers()[index];
        println!("{}", register);
        panic!("Implement DMA to continue!");
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let io_registers_state = memory.ppu_ctrl_registers_status();
        for (index, state) in io_registers_state.iter().enumerate() {
            println!("PPU REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [MiscRegisterStatus::Untouched; MISC_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.misc_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            println!("MISC REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);

            match index {
                0x14 => self.handle_dma_register(index, state.clone(), memory),
                _    => {},
            };
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);

        log::log("ppu", "PPU cycle complete", &self.runtime_options);
        0
    }
}
<|endoftext|>


<commit_before>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```no_run
//! # use cargo_update::Options;
//! let opts = Options::parse();
//! println!("{:#?}", opts);
//! ```

use self::super::ops::{PackageFilterElement, ConfigOperation};
use semver::{VersionReq as SemverReq, Version as Semver};
use clap::{self, AppSettings, SubCommand, App, Arg};
use array_tool::vec::Uniq;
use std::path::PathBuf;
use std::str::FromStr;
use dirs::home_dir;
use std::env;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// (Additional) packages to update. Default: `[]`
    pub to_update: Vec<(String, Option<Semver>)>,
    /// Whether to update all packages. Default: `false`
    pub all: bool,
    /// Whether to update packages or just list them. Default: `true`
    pub update: bool,
    /// Whether to allow for just installing packages. Default: `false`
    pub install: bool,
    /// Update all packages. Default: `false`
    pub force: bool,
    /// Update git packages too (it's expensive). Default: `false`
    pub update_git: bool,
    /// Update all packages. Default: empty
    pub filter: Vec<PackageFilterElement>,
    /// The `.crates.toml` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// The `cargo` home directory. Default: `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub cargo_dir: (String, PathBuf),
    /// The temporary directory to clone git repositories to. Default: `"$TEMP/cargo-update"`
    pub temp_dir: (String, PathBuf),
}

/// Representation of the config application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ConfigOptions {
    /// The `config` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// Crate to modify config for
    pub package: String,
    /// What to do to the config, or display with empty
    pub ops: Vec<ConfigOperation>,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("cargo-install-update")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .visible_alias("root")
                            .validator(|s| existing_dir_validator("Cargo", &s)),
                        Arg::from_usage("-t --temp-dir=[TEMP_DIR] 'The temporary directory. Default: $TEMP/cargo-update'")
                            .validator(|s| existing_dir_validator("Temporary", &s)),
                        Arg::from_usage("-a --all 'Update all packages'"),
                        Arg::from_usage("-l --list 'Don't update packages, only list and check if they need an update'"),
                        Arg::from_usage("-f --force 'Update all packages regardless if they need updating'"),
                        Arg::from_usage("-i --allow-no-update 'Allow for fresh-installing packages'"),
                        Arg::from_usage("-g --git 'Also update git packages'"),
                        Arg::from_usage("-s --filter=[PACKAGE_FILTER]... 'Specify a filter a package must match to be considered'")
                            .validator(|s| PackageFilterElement::parse(&s).map(|_| ())),
                        Arg::from_usage("[PACKAGE]... 'Packages to update'")
                            .empty_values(false)
                            .min_values(1)
                            .validator(|s| package_parse(s).map(|_| ()))]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update").unwrap();

        let all = matches.is_present("all");
        let cdir = cargo_dir();
        Options {
            to_update: match (all, matches.values_of("PACKAGE")) {
                (_, Some(pkgs)) => {
                    let packages: Vec<_> = pkgs.map(String::from).map(package_parse).map(Result::unwrap).collect();
                    packages.unique_via(|l, r| l.0 == r.0)
                }
                (true, None) => vec![],
                (false, None) => {
                    clap::Error {
                            message: format!("Need at least one PACKAGE without --all"),
                            kind: clap::ErrorKind::MissingRequiredArgument,
                            info: None,
                        }
                        .exit()
                }
            },
            all: all,
            update: !matches.is_present("list"),
            install: matches.is_present("allow-no-update"),
            force: matches.is_present("force"),
            update_git: matches.is_present("git"),
            filter: matches.values_of("filter").map(|pfs| pfs.flat_map(PackageFilterElement::parse).collect()).unwrap_or_else(|| vec![]),
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            cargo_dir: cdir,
            temp_dir: {
                let (temp_s, temp_pb) = if let Some(tmpdir) = matches.value_of("temp-dir") {
                    (tmpdir.to_string(), fs::canonicalize(tmpdir).unwrap())
                } else {
                    ("$TEMP".to_string(), env::temp_dir())
                };

                (format!("{}{}cargo-update",
                         temp_s,
                         if temp_s.ends_with('/') || temp_s.ends_with('\\') {
                             ""
                         } else {
                             "/"
                         }),
                 temp_pb.join("cargo-update"))
            },
        }
    }
}

impl ConfigOptions {
    /// Parse `env`-wide command-line arguments into a `ConfigOptions` instance
    pub fn parse() -> ConfigOptions {
        let matches = App::new("cargo-install-update-config")
            .bin_name("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update-config")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables -- configuration")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .validator(|s| existing_dir_validator("Cargo", &s)),
                        Arg::from_usage("-t --toolchain=[TOOLCHAIN] 'Toolchain to use or empty for default'"),
                        Arg::from_usage("-f --feature=[FEATURE]... 'Feature to enable'"),
                        Arg::from_usage("-n --no-feature=[DISABLED_FEATURE]... 'Feature to disable'"),
                        Arg::from_usage("-d --default-features=[DEFAULT_FEATURES] 'Whether to allow default features'")
                            .possible_values(&["1", "yes", "true", "0", "no", "false"])
                            .hide_possible_values(true),
                        Arg::from_usage("--debug 'Compile the package in debug mode'").conflicts_with("release"),
                        Arg::from_usage("--release 'Compile the package in release mode'").conflicts_with("debug"),
                        Arg::from_usage("-v --version=[VERSION_REQ] 'Require a cargo-compatible version range'")
                            .validator(|s| SemverReq::from_str(&s).map(|_| ()).map_err(|e| e.to_string()))
                            .conflicts_with("any-version"),
                        Arg::from_usage("-a --any-version 'Allow any version'").conflicts_with("version"),
                        Arg::from_usage("<PACKAGE> 'Package to configure'").empty_values(false)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update-config").unwrap();

        let cdir = cargo_dir();
        ConfigOptions {
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            package: matches.value_of("PACKAGE").unwrap().to_string(),
            ops: matches.value_of("toolchain")
                .map(|t| if t.is_empty() {
                    ConfigOperation::RemoveToolchain
                } else {
                    ConfigOperation::SetToolchain(t.to_string())
                })
                .into_iter()
                .chain(matches.values_of("feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::AddFeature))
                .chain(matches.values_of("no-feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::RemoveFeature))
                .chain(matches.value_of("default-features").map(|d| ["1", "yes", "true"].contains(&d)).map(ConfigOperation::DefaultFeatures).into_iter())
                .chain(match (matches.is_present("debug"), matches.is_present("release")) {
                        (true, _) => Some(ConfigOperation::SetDebugMode(true)),
                        (_, true) => Some(ConfigOperation::SetDebugMode(false)),
                        _ => None,
                    }
                    .into_iter())
                .chain(match (matches.is_present("any-version"), matches.value_of("version")) {
                        (true, _) => Some(ConfigOperation::RemoveTargetVersion),
                        (false, Some(vr)) => Some(ConfigOperation::SetTargetVersion(SemverReq::from_str(vr).unwrap())),
                        _ => None,
                    }
                    .into_iter())
                .collect(),
        }
    }
}

fn cargo_dir() -> (String, PathBuf) {
    match env::var("CARGO_HOME").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
        Ok(ch) => ("$CARGO_HOME".to_string(), ch),
        Err(()) =>
                match home_dir().and_then(|hd| hd.canonicalize().ok()) {
                    Some(mut hd) => {
                        hd.push(".cargo");

                        fs::create_dir_all(&hd).unwrap();
                        ("$HOME/.cargo".to_string(), hd)
                    }
                    None => {
                        clap::Error {
                                message: "$CARGO_HOME and home directory invalid, please specify the cargo home directory with the -c option".to_string(),
                                kind: clap::ErrorKind::MissingRequiredArgument,
                                info: None,
                            }
                            .exit()
                    }
                },
    }
}

fn existing_dir_validator(label: &str, s: &str) -> Result<(), String> {
    fs::canonicalize(s).map(|_| ()).map_err(|_| format!("{} directory \"{}\" not found", label, s))
}

fn package_parse(s: String) -> Result<(String, Option<Semver>), String> {
    if let Some(idx) = s.find(':') {
        Ok((s[0..idx].to_string(),
            Some(Semver::parse(&s[idx + 1..]).map_err(|e| format!("Version {} provided for package {} invalid: {}", &s[idx + 1..], &s[0..idx], e))?)))
    } else {
        Ok((s, None))
    }
}
<commit_msg>Rename root clap app names to cargo<commit_after>//! Option parsing and management.
//!
//! Use the `Options::parse()` function to get the program's configuration,
//! as parsed from the commandline.
//!
//! # Examples
//!
//! ```no_run
//! # use cargo_update::Options;
//! let opts = Options::parse();
//! println!("{:#?}", opts);
//! ```

use self::super::ops::{PackageFilterElement, ConfigOperation};
use semver::{VersionReq as SemverReq, Version as Semver};
use clap::{self, AppSettings, SubCommand, App, Arg};
use array_tool::vec::Uniq;
use std::path::PathBuf;
use std::str::FromStr;
use dirs::home_dir;
use std::env;
use std::fs;

/// Representation of the application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Options {
    /// (Additional) packages to update. Default: `[]`
    pub to_update: Vec<(String, Option<Semver>)>,
    /// Whether to update all packages. Default: `false`
    pub all: bool,
    /// Whether to update packages or just list them. Default: `true`
    pub update: bool,
    /// Whether to allow for just installing packages. Default: `false`
    pub install: bool,
    /// Update all packages. Default: `false`
    pub force: bool,
    /// Update git packages too (it's expensive). Default: `false`
    pub update_git: bool,
    /// Update all packages. Default: empty
    pub filter: Vec<PackageFilterElement>,
    /// The `.crates.toml` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// The `cargo` home directory. Default: `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub cargo_dir: (String, PathBuf),
    /// The temporary directory to clone git repositories to. Default: `"$TEMP/cargo-update"`
    pub temp_dir: (String, PathBuf),
}

/// Representation of the config application's all configurable values.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ConfigOptions {
    /// The `config` file in the `cargo` home directory.
    /// Default: in `"$CARGO_INSTALL_ROOT"`, then `"$CARGO_HOME"`, then `"$HOME/.cargo"`
    pub crates_file: (String, PathBuf),
    /// Crate to modify config for
    pub package: String,
    /// What to do to the config, or display with empty
    pub ops: Vec<ConfigOperation>,
}

impl Options {
    /// Parse `env`-wide command-line arguments into an `Options` instance
    pub fn parse() -> Options {
        let matches = App::new("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .visible_alias("root")
                            .validator(|s| existing_dir_validator("Cargo", &s)),
                        Arg::from_usage("-t --temp-dir=[TEMP_DIR] 'The temporary directory. Default: $TEMP/cargo-update'")
                            .validator(|s| existing_dir_validator("Temporary", &s)),
                        Arg::from_usage("-a --all 'Update all packages'"),
                        Arg::from_usage("-l --list 'Don't update packages, only list and check if they need an update'"),
                        Arg::from_usage("-f --force 'Update all packages regardless if they need updating'"),
                        Arg::from_usage("-i --allow-no-update 'Allow for fresh-installing packages'"),
                        Arg::from_usage("-g --git 'Also update git packages'"),
                        Arg::from_usage("-s --filter=[PACKAGE_FILTER]... 'Specify a filter a package must match to be considered'")
                            .validator(|s| PackageFilterElement::parse(&s).map(|_| ())),
                        Arg::from_usage("[PACKAGE]... 'Packages to update'")
                            .empty_values(false)
                            .min_values(1)
                            .validator(|s| package_parse(s).map(|_| ()))]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update").unwrap();

        let all = matches.is_present("all");
        let cdir = cargo_dir();
        Options {
            to_update: match (all, matches.values_of("PACKAGE")) {
                (_, Some(pkgs)) => {
                    let packages: Vec<_> = pkgs.map(String::from).map(package_parse).map(Result::unwrap).collect();
                    packages.unique_via(|l, r| l.0 == r.0)
                }
                (true, None) => vec![],
                (false, None) => {
                    clap::Error {
                            message: format!("Need at least one PACKAGE without --all"),
                            kind: clap::ErrorKind::MissingRequiredArgument,
                            info: None,
                        }
                        .exit()
                }
            },
            all: all,
            update: !matches.is_present("list"),
            install: matches.is_present("allow-no-update"),
            force: matches.is_present("force"),
            update_git: matches.is_present("git"),
            filter: matches.values_of("filter").map(|pfs| pfs.flat_map(PackageFilterElement::parse).collect()).unwrap_or_else(|| vec![]),
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            cargo_dir: cdir,
            temp_dir: {
                let (temp_s, temp_pb) = if let Some(tmpdir) = matches.value_of("temp-dir") {
                    (tmpdir.to_string(), fs::canonicalize(tmpdir).unwrap())
                } else {
                    ("$TEMP".to_string(), env::temp_dir())
                };

                (format!("{}{}cargo-update",
                         temp_s,
                         if temp_s.ends_with('/') || temp_s.ends_with('\\') {
                             ""
                         } else {
                             "/"
                         }),
                 temp_pb.join("cargo-update"))
            },
        }
    }
}

impl ConfigOptions {
    /// Parse `env`-wide command-line arguments into a `ConfigOptions` instance
    pub fn parse() -> ConfigOptions {
        let matches = App::new("cargo")
            .settings(&[AppSettings::ColoredHelp, AppSettings::ArgRequiredElseHelp, AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
            .subcommand(SubCommand::with_name("install-update-config")
                .version(crate_version!())
                .author(crate_authors!("\n"))
                .about("A cargo subcommand for checking and applying updates to installed executables -- configuration")
                .args(&[Arg::from_usage("-c --cargo-dir=[CARGO_DIR] 'The cargo home directory. Default: $CARGO_HOME or $HOME/.cargo'")
                            .validator(|s| existing_dir_validator("Cargo", &s)),
                        Arg::from_usage("-t --toolchain=[TOOLCHAIN] 'Toolchain to use or empty for default'"),
                        Arg::from_usage("-f --feature=[FEATURE]... 'Feature to enable'"),
                        Arg::from_usage("-n --no-feature=[DISABLED_FEATURE]... 'Feature to disable'"),
                        Arg::from_usage("-d --default-features=[DEFAULT_FEATURES] 'Whether to allow default features'")
                            .possible_values(&["1", "yes", "true", "0", "no", "false"])
                            .hide_possible_values(true),
                        Arg::from_usage("--debug 'Compile the package in debug mode'").conflicts_with("release"),
                        Arg::from_usage("--release 'Compile the package in release mode'").conflicts_with("debug"),
                        Arg::from_usage("-v --version=[VERSION_REQ] 'Require a cargo-compatible version range'")
                            .validator(|s| SemverReq::from_str(&s).map(|_| ()).map_err(|e| e.to_string()))
                            .conflicts_with("any-version"),
                        Arg::from_usage("-a --any-version 'Allow any version'").conflicts_with("version"),
                        Arg::from_usage("<PACKAGE> 'Package to configure'").empty_values(false)]))
            .get_matches();
        let matches = matches.subcommand_matches("install-update-config").unwrap();

        let cdir = cargo_dir();
        ConfigOptions {
            crates_file: match matches.value_of("cargo-dir") {
                Some(dir) => (format!("{}/.crates.toml", dir), fs::canonicalize(dir).unwrap().join(".crates.toml")),
                None => {
                    match env::var("CARGO_INSTALL_ROOT").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
                        Ok(ch) => ("$CARGO_INSTALL_ROOT/.crates.toml".to_string(), ch.join(".crates.toml")),
                        Err(()) => (format!("{}/.crates.toml", cdir.0), cdir.1.join(".crates.toml")),
                    }
                }
            },
            package: matches.value_of("PACKAGE").unwrap().to_string(),
            ops: matches.value_of("toolchain")
                .map(|t| if t.is_empty() {
                    ConfigOperation::RemoveToolchain
                } else {
                    ConfigOperation::SetToolchain(t.to_string())
                })
                .into_iter()
                .chain(matches.values_of("feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::AddFeature))
                .chain(matches.values_of("no-feature").into_iter().flat_map(|f| f).map(str::to_string).map(ConfigOperation::RemoveFeature))
                .chain(matches.value_of("default-features").map(|d| ["1", "yes", "true"].contains(&d)).map(ConfigOperation::DefaultFeatures).into_iter())
                .chain(match (matches.is_present("debug"), matches.is_present("release")) {
                        (true, _) => Some(ConfigOperation::SetDebugMode(true)),
                        (_, true) => Some(ConfigOperation::SetDebugMode(false)),
                        _ => None,
                    }
                    .into_iter())
                .chain(match (matches.is_present("any-version"), matches.value_of("version")) {
                        (true, _) => Some(ConfigOperation::RemoveTargetVersion),
                        (false, Some(vr)) => Some(ConfigOperation::SetTargetVersion(SemverReq::from_str(vr).unwrap())),
                        _ => None,
                    }
                    .into_iter())
                .collect(),
        }
    }
}

fn cargo_dir() -> (String, PathBuf) {
    match env::var("CARGO_HOME").map_err(|_| ()).and_then(|ch| fs::canonicalize(ch).map_err(|_| ())) {
        Ok(ch) => ("$CARGO_HOME".to_string(), ch),
        Err(()) =>
                match home_dir().and_then(|hd| hd.canonicalize().ok()) {
                    Some(mut hd) => {
                        hd.push(".cargo");

                        fs::create_dir_all(&hd).unwrap();
                        ("$HOME/.cargo".to_string(), hd)
                    }
                    None => {
                        clap::Error {
                                message: "$CARGO_HOME and home directory invalid, please specify the cargo home directory with the -c option".to_string(),
                                kind: clap::ErrorKind::MissingRequiredArgument,
                                info: None,
                            }
                            .exit()
                    }
                },
    }
}

fn existing_dir_validator(label: &str, s: &str) -> Result<(), String> {
    fs::canonicalize(s).map(|_| ()).map_err(|_| format!("{} directory \"{}\" not found", label, s))
}

fn package_parse(s: String) -> Result<(String, Option<Semver>), String> {
    if let Some(idx) = s.find(':') {
        Ok((s[0..idx].to_string(),
            Some(Semver::parse(&s[idx + 1..]).map_err(|e| format!("Version {} provided for package {} invalid: {}", &s[idx + 1..], &s[0..idx], e))?)))
    } else {
        Ok((s, None))
    }
}
<|endoftext|>