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

//! A wrapper around any Reader to treat it as an RNG.

use std::old_io::Reader;
use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// # Panics
///
/// It will panic if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::old_io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8)));
/// println!("{:x}", rng.gen::<uint>());
/// ```
pub struct ReaderRng<R> {
    reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read_at_least(v.len(), v) {
            Ok(_) => {}
            Err(e) => panic!("ReaderRng.fill_bytes error: {:?}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::old_io::MemReader;
    use std::num::Int;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
                     0  , 0, 0, 0, 0, 0, 0, 2,
                     0,   0, 0, 0, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u64(), 1_u64.to_be());
        assert_eq!(rng.next_u64(), 2_u64.to_be());
        assert_eq!(rng.next_u64(), 3_u64.to_be());
    }
    #[test]
    fn test_reader_rng_u32() {
        let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u32(), 1_u32.to_be());
        assert_eq!(rng.next_u32(), 2_u32.to_be());
        assert_eq!(rng.next_u32(), 3_u32.to_be());
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8; 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_vec()));
        rng.fill_bytes(&mut w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(vec!()));
        let mut v = [0u8; 3];
        rng.fill_bytes(&mut v);
    }
}
<commit_msg>Remove uint from Reader doctest<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around any Reader to treat it as an RNG.

use std::old_io::Reader;
use Rng;

/// An RNG that reads random bytes straight from a `Reader`. This will
/// work best with an infinite reader, but this is not required.
///
/// # Panics
///
/// It will panic if it there is insufficient data to fulfill a request.
///
/// # Example
///
/// ```rust
/// use rand::{reader, Rng};
/// use std::old_io::MemReader;
///
/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8)));
/// println!("{:x}", rng.gen::<u32>());
/// ```
pub struct ReaderRng<R> {
    reader: R
}

impl<R: Reader> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Reader`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Reader> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        if cfg!(target_endian="little") {
            self.reader.read_le_u32().unwrap()
        } else {
            self.reader.read_be_u32().unwrap()
        }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        if cfg!(target_endian="little") {
            self.reader.read_le_u64().unwrap()
        } else {
            self.reader.read_be_u64().unwrap()
        }
    }
    fn fill_bytes(&mut self, v: &mut [u8]) {
        if v.len() == 0 { return }
        match self.reader.read_at_least(v.len(), v) {
            Ok(_) => {}
            Err(e) => panic!("ReaderRng.fill_bytes error: {:?}", e)
        }
    }
}

#[cfg(test)]
mod test {
    use super::ReaderRng;
    use std::old_io::MemReader;
    use std::num::Int;
    use Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
                     0  , 0, 0, 0, 0, 0, 0, 2,
                     0,   0, 0, 0, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u64(), 1_u64.to_be());
        assert_eq!(rng.next_u64(), 2_u64.to_be());
        assert_eq!(rng.next_u64(), 3_u64.to_be());
    }
    #[test]
    fn test_reader_rng_u32() {
        let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
        let mut rng = ReaderRng::new(MemReader::new(v));

        assert_eq!(rng.next_u32(), 1_u32.to_be());
        assert_eq!(rng.next_u32(), 2_u32.to_be());
        assert_eq!(rng.next_u32(), 3_u32.to_be());
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1u8, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0u8; 8];

        let mut rng = ReaderRng::new(MemReader::new(v.to_vec()));
        rng.fill_bytes(&mut w);

        assert!(v == w);
    }

    #[test]
    #[should_fail]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(MemReader::new(vec!()));
        let mut v = [0u8; 3];
        rng.fill_bytes(&mut v);
    }
}
<|endoftext|>


<commit_before>pub use quickcheck::quickcheck;

pub use schema::connection;
pub use diesel::*;
pub use diesel::result::Error;
pub use diesel::data_types::*;
pub use diesel::types::{NativeSqlType, ToSql, Nullable, Array};

pub fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
    ST: NativeSqlType,
    T: ToSql<ST> + Queriable<ST> + PartialEq,
{
    let connection = connection();
    let query = format!("SELECT $1::{}", type_name);
    let result = connection.query_sql_params::<ST, T, ST, T>(&query, &value);
    match result {
        Ok(mut val) => value == val.nth(0).unwrap(),
        Err(Error::DatabaseError(msg)) =>
            &msg == "ERROR:  invalid byte sequence for encoding \"UTF8\": 0x00\n",
        Err(e) => panic!("Query failed: {:?}", e),
    }
}

macro_rules! test_round_trip {
    ($test_name:ident, $sql_type:ident, $tpe:ty, $sql_type_name:expr) => {
        #[test]
        fn $test_name() {
            fn round_trip(val: $tpe) -> bool {
                test_type_round_trips::<types::$sql_type, _>(val, $sql_type_name)
            }

            fn option_round_trip(val: Option<$tpe>) -> bool {
                test_type_round_trips::<Nullable<types::$sql_type>, _>(val, $sql_type_name)
            }

            fn vec_round_trip(val: Vec<$tpe>) -> bool {
                test_type_round_trips::<Array<types::$sql_type>, _>(val, concat!($sql_type_name, "[]"))
            }

            quickcheck(round_trip as fn($tpe) -> bool);
            quickcheck(option_round_trip as fn(Option<$tpe>) -> bool);
            quickcheck(vec_round_trip as fn(Vec<$tpe>) -> bool);
        }
    }
}

test_round_trip!(bool_roundtrips, Bool, bool, "boolean");
test_round_trip!(i16_roundtrips, SmallInt, i16, "int2");
test_round_trip!(i32_roundtrips, Integer, i32, "int4");
test_round_trip!(i64_roundtrips, BigInt, i64, "int8");
test_round_trip!(f32_roundtrips, Float, f32, "real");
test_round_trip!(f64_roundtrips, Double, f64, "double precision");
test_round_trip!(string_roundtrips, VarChar, String, "varchar");
test_round_trip!(text_roundtrips, Text, String, "text");
test_round_trip!(binary_roundtrips, Binary, Vec<u8>, "bytea");
test_round_trip!(date_roundtrips, Date, PgDate, "date");
test_round_trip!(time_roundtrips, Time, PgTime, "time");
test_round_trip!(timestamp_roundtrips, Timestamp, PgTimestamp, "timestamp");
test_round_trip!(interval_roundtrips, Interval, PgInterval, "interval");
test_round_trip!(numeric_roundtrips, Numeric, PgNumeric, "numeric");

#[cfg(feature = "unstable")]
mod unstable_types {
    use super::*;
    use std::time::SystemTime;

    test_round_trip!(systemtime_roundtrips, Timestamp, SystemTime, "timestamp");
}
<commit_msg>Fix travis build<commit_after>pub use quickcheck::quickcheck;

pub use schema::connection;
pub use diesel::*;
pub use diesel::result::Error;
pub use diesel::data_types::*;
pub use diesel::types::{NativeSqlType, ToSql, Nullable, Array};

pub fn test_type_round_trips<ST, T>(value: T, type_name: &str) -> bool where
    ST: NativeSqlType,
    T: ToSql<ST> + Queriable<ST> + PartialEq,
{
    let connection = connection();
    let query = format!("SELECT $1::{}", type_name);
    let result = connection.query_sql_params::<ST, T, ST, T>(&query, &value);
    match result {
        Ok(mut val) => value == val.nth(0).unwrap(),
        Err(Error::DatabaseError(msg)) =>
            &msg == "ERROR:  invalid byte sequence for encoding \"UTF8\": 0x00\n",
        Err(e) => panic!("Query failed: {:?}", e),
    }
}

pub fn id<A>(a: A) -> A { a }

macro_rules! test_round_trip {
    ($test_name:ident, $sql_type:ident, $tpe:ty, $sql_type_name:expr) => {
        test_round_trip!($test_name, $sql_type, $tpe, id, $sql_type_name);
    };

    ($test_name:ident, $sql_type:ident, $tpe:ty, $map_fn:ident, $sql_type_name:expr) => {
        #[test]
        fn $test_name() {
            fn round_trip(val: $tpe) -> bool {
                test_type_round_trips::<types::$sql_type, _>($map_fn(val), $sql_type_name)
            }

            fn option_round_trip(val: Option<$tpe>) -> bool {
                let val = val.map($map_fn);
                test_type_round_trips::<Nullable<types::$sql_type>, _>(val, $sql_type_name)
            }

            fn vec_round_trip(val: Vec<$tpe>) -> bool {
                let val: Vec<_> = val.into_iter().map($map_fn).collect();
                test_type_round_trips::<Array<types::$sql_type>, _>(val, concat!($sql_type_name, "[]"))
            }

            quickcheck(round_trip as fn($tpe) -> bool);
            quickcheck(option_round_trip as fn(Option<$tpe>) -> bool);
            quickcheck(vec_round_trip as fn(Vec<$tpe>) -> bool);
        }
    }
}

test_round_trip!(bool_roundtrips, Bool, bool, "boolean");
test_round_trip!(i16_roundtrips, SmallInt, i16, "int2");
test_round_trip!(i32_roundtrips, Integer, i32, "int4");
test_round_trip!(i64_roundtrips, BigInt, i64, "int8");
test_round_trip!(f32_roundtrips, Float, f32, "real");
test_round_trip!(f64_roundtrips, Double, f64, "double precision");
test_round_trip!(string_roundtrips, VarChar, String, "varchar");
test_round_trip!(text_roundtrips, Text, String, "text");
test_round_trip!(binary_roundtrips, Binary, Vec<u8>, "bytea");
test_round_trip!(date_roundtrips, Date, PgDate, "date");
test_round_trip!(time_roundtrips, Time, PgTime, "time");
test_round_trip!(timestamp_roundtrips, Timestamp, PgTimestamp, "timestamp");
test_round_trip!(interval_roundtrips, Interval, PgInterval, "interval");
test_round_trip!(numeric_roundtrips, Numeric, PgNumeric, "numeric");

#[cfg(feature = "unstable")]
mod unstable_types {
    use super::*;
    use std::time::*;

    fn strip_nanosecond_precision(time: SystemTime) -> SystemTime {
        match time.duration_from_earlier(UNIX_EPOCH) {
            Ok(duration) => time - Duration::new(0, duration.subsec_nanos() % 1000),
            Err(e) => time + Duration::new(0, e.duration().subsec_nanos() % 1000),
        }
    }

    test_round_trip!(systemtime_roundtrips, Timestamp, SystemTime, strip_nanosecond_precision, "timestamp");
}
<|endoftext|>


<commit_before>use ::*;

fn out<S: ToString>(screen : &mut RawTerminal<Stdout>, output : S) {
    write!(*screen, "{}", output.to_string()).unwrap();
}

fn curs(screen : &mut RawTerminal<Stdout>, coord : Coord) {
    // Coordinate translation assumes floor is being rendered at (1, 1)
    out(screen, termion::cursor::Goto(coord.col+1, coord.row+1));
}

fn color<C: Color>(screen : &mut RawTerminal<Stdout>, clr : C) {
    out(screen, Fg(clr));
}

pub fn render_loop(floor        : Arc<Mutex<Floor>>,
                   dirty_coords : Arc<Mutex<Vec<Coord>>>,
                   messages     : Arc<Mutex<Vec<String>>>,
                   player       : Arc<Mutex<Player>>,
                   monsters     : Arc<Mutex<Vec<Monster>>>,
                   stop         : Arc<Mutex<bool>>) {

    let mut screen = &mut stdout().into_raw_mode().unwrap();
    out(screen, termion::cursor::Hide); // Hide the cursor
    out(screen, termion::clear::All);   // Clear the screen

    // Draw the entire floor
    curs(screen, Coord::new(0,0));
    {
        let floor = floor.lock().unwrap();
        for row in &floor.tiles {
            for tile in row {
                if let Some(ref wall) = tile.wall {
                    out(screen, wall);
                } else {
                    out(screen, " ");
                }
            }
            out(screen, "\r\n");
        }
    }

    // Render Loop
    loop {
        // Don't render too hot.
        sleep(Duration::from_millis(10));

        // Time to stop?
        {
            if *stop.lock().unwrap() {
                break;
            }
        }

        // Once we can lock floor, we can lock anything else we want in this thread.
        let floor = floor.lock().unwrap();

        // Redraw any dirty coordinates
        let mut dirty_coords = dirty_coords.lock().unwrap();
        for coord in dirty_coords.drain(..) {
            curs(screen, coord);
            out(screen, floor.get_symbol(&coord));
        }

        // Render Player
        {
            let mut player = player.lock().unwrap();
            if player.dirty {
                player.dirty = false;
                // Player's sword
                curs(screen, player.sword_coord);
                color(screen, Red);
                out(screen, sword_symbol(&player.facing));
                // Player himself
                curs(screen, player.coord);
                color(screen, Blue);
                out(screen, &player.symbol);
                color(screen, Reset);
            }
            // Player Score
            let score_string = format!("Score: {}", player.score);
            curs(screen, Coord::new((floor.cols - score_string.len()) as u16,
                                               floor.rows as u16));
            out(screen, score_string);
        }

        // Render Monsters
        {
            let monsters = monsters.lock().unwrap();
            for monster in monsters.iter() {
                curs(screen, monster.coord);
                color(screen, Green);
                out(screen, &monster.symbol);
                color(screen, Reset);
            }
        }

        // Bottom text
        curs(screen, Coord::new(0, floor.rows as u16));
        out(screen, "Rusty Sword – Game of Infamy!");

        // Messages
        curs(screen, Coord::new(0, (floor.rows + 2) as u16));
        let mut messages = messages.lock().unwrap();
        if messages.len() > 4 {
            messages.remove(0);
        }
        for msg in messages.iter() {
            if msg.contains("spawned") {
                color(screen, Green);
            } else if msg.contains("You killed") {
                color(screen, Blue);
            } else if msg.contains("were eaten") {
                color(screen, Red);
            } else {
                color(screen, LightWhite);
            }
            out(screen, msg);
            out(screen, format!("{}\n\r", clear::UntilNewline));
            color(screen, Reset);
        }

        screen.flush().unwrap();
    }

    // Nice cleanup: Move cursor below the floor, so we can see how we finished
    {
        let floor = floor.lock().unwrap();
        curs(screen, Coord::new(0, (floor.rows+7) as u16));
    }
    out(screen, termion::cursor::Show); // Show the cursor again
    screen.flush().unwrap();
}

<commit_msg>Massage<commit_after>use ::*;

fn out<S: ToString>(screen : &mut RawTerminal<Stdout>, output : S) {
    write!(*screen, "{}", output.to_string()).unwrap();
}

fn curs(screen : &mut RawTerminal<Stdout>, coord : Coord) {
    // Coordinate translation assumes floor is being rendered at (1, 1)
    out(screen, termion::cursor::Goto(coord.col+1, coord.row+1));
}

fn color<C: Color>(screen : &mut RawTerminal<Stdout>, clr : C) {
    out(screen, Fg(clr));
}

pub fn render_loop(floor        : Arc<Mutex<Floor>>,
                   dirty_coords : Arc<Mutex<Vec<Coord>>>,
                   messages     : Arc<Mutex<Vec<String>>>,
                   player       : Arc<Mutex<Player>>,
                   monsters     : Arc<Mutex<Vec<Monster>>>,
                   stop         : Arc<Mutex<bool>>) {

    let mut screen = &mut stdout().into_raw_mode().unwrap();
    out(screen, termion::cursor::Hide); // Hide the cursor
    out(screen, termion::clear::All);   // Clear the screen

    // Draw the entire floor
    curs(screen, Coord::new(0,0));
    {
        let floor = floor.lock().unwrap();
        for row in &floor.tiles {
            for tile in row {
                if let Some(ref wall) = tile.wall {
                    out(screen, wall);
                } else {
                    out(screen, " ");
                }
            }
            out(screen, "\r\n");
        }
    }

    // Render Loop
    loop {
        sleep(Duration::from_millis(10));

        {
            if *stop.lock().unwrap() {
                break;
            }
        }

        // Lock floor first...
        let floor = floor.lock().unwrap();

        // Redraw any dirty coordinates with floor tiles
        let mut dirty_coords = dirty_coords.lock().unwrap();
        for coord in dirty_coords.drain(..) {
            curs(screen, coord);
            out(screen, floor.get_symbol(&coord));
        }

        // Render Player
        {
            let mut player = player.lock().unwrap();
            if player.dirty {
                player.dirty = false;
                // Player's sword
                curs(screen, player.sword_coord);
                color(screen, Red);
                out(screen, sword_symbol(&player.facing));
                // Player himself
                curs(screen, player.coord);
                color(screen, Blue);
                out(screen, &player.symbol);
                color(screen, Reset);
            }
            // Player Score
            let score_string = format!("Score: {}", player.score);
            curs(screen, Coord::new((floor.cols - score_string.len()) as u16,
                                    floor.rows as u16));
            out(screen, score_string);
        }

        // Render Monsters
        {
            let monsters = monsters.lock().unwrap();
            for monster in monsters.iter() {
                curs(screen, monster.coord);
                color(screen, Green);
                out(screen, &monster.symbol);
                color(screen, Reset);
            }
        }

        // Game Title
        curs(screen, Coord::new(0, floor.rows as u16));
        out(screen, "Rusty Sword – Game of Infamy!");

        // Messages
        curs(screen, Coord::new(0, (floor.rows + 2) as u16));
        let mut messages = messages.lock().unwrap();
        if messages.len() > 4 {
            messages.remove(0);
        }
        for msg in messages.iter() {
            if msg.contains("spawned") {
                color(screen, Green);
            } else if msg.contains("You killed") {
                color(screen, Blue);
            } else if msg.contains("were eaten") {
                color(screen, Red);
            } else {
                color(screen, LightWhite);
            }
            out(screen, msg);
            out(screen, format!("{}\n\r", clear::UntilNewline));
            color(screen, Reset);
        }

        screen.flush().unwrap();
    }

    // Nice cleanup: Move cursor below the floor, so we can see how we finished
    {
        let floor = floor.lock().unwrap();
        curs(screen, Coord::new(0, (floor.rows+7) as u16));
    }
    out(screen, termion::cursor::Show); // Show the cursor again
    screen.flush().unwrap();
}

<|endoftext|>


<commit_before>use hyper;
use webdriver::command::{GetParameters, LocatorParameters};
use webdriver::common::LocatorStrategy;
use webdriver::error::{WebDriverResult, ErrorStatus, WebDriverError};
use webdriver::response::{WebDriverResponse, ValueResponse};
use std::io::Read;
use std::ops::Drop;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};
use rustc_serialize::base64::{FromBase64Error, FromBase64};

use std::process::{Command, Child};
use std::env;
use std::net::TcpStream;
use std::time;
use std::thread;

use std::sync::{Arc, Mutex, MutexGuard};
use nickel::{Request, Response, Middleware, Continue, MiddlewareResult};
use plugin::Extensible;
use typemap::Key;

use rand;
use rand::Rng;

pub struct Webdriver {
    client: hyper::client::Client,
    host: String,
    port: u16,
    process: Child,
}

impl Default for Webdriver {
    fn default() -> Self {
        panic!("No good default for webdriver");
    }
}

pub struct WebdriverSession {
    client: hyper::client::Client,
    base_url: String,
    session_id: String,
}

fn decode_response(json_str: &str) -> WebDriverResult<Json> {
    let decoded = Json::from_str(json_str).unwrap();
    let status =
        decoded.find("status").expect("status code").as_u64().expect("numeric status code");
    let value = decoded.find("value").expect("value");
    match status {
        0 => Ok(decoded.clone()),
        _ => {
            let message = value.find("message")
                .expect("error message")
                .as_string()
                .expect("a string message")
                .to_string();
            let kind = match status {
                7 => ErrorStatus::NoSuchElement,
                _ => ErrorStatus::UnknownError,
            };
            Err(WebDriverError::new(kind, message))
        }
    }
}

trait DoesPost {
    fn do_post(&self, url: String, body: &str) -> WebDriverResult<Json> {
        debug!("Request: {:?}", body);
        let mut res = self.client()
            .post(&url)
            .body(body)
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        debug!("Buffer: {}", buffer);
        // assert_eq!(res.status, hyper::Ok);
        let decoded = decode_response(&buffer);
        debug!("Decoded: {:?}", decoded);
        decoded
    }

    fn client(&self) -> &hyper::client::Client;
}

impl Webdriver {
    pub fn new() -> Webdriver {
        let chromedriver_path = match env::var("CHROMEDRIVER") {
            Ok(val) => val,
            Err(_) => "./chromedriver".to_string(),
        };
        info!("Using {} as chromedriver path", chromedriver_path);

        let port: u16 = {
            let mut rng = rand::thread_rng();
            let mut candidate: u16;
            loop {
                candidate = rng.gen_range(2048, 65535);
                debug!("Candidate port {}", candidate);
                let stream = TcpStream::connect(("localhost", candidate));
                if stream.is_ok() {
                    debug!("Already used port {}", candidate);
                } else {
                    debug!("Good port {}", candidate);
                    break;
                }
            }
            candidate
        };

        let child = Command::new(&chromedriver_path)
            .arg(format!("--port={}", port))
            .spawn()
            .expect(&format!("spawning chromedriver from {}", &chromedriver_path));

        loop {
            let stream = TcpStream::connect(("localhost", port));
            if stream.is_ok() {
                debug!("Found chromedriver");
                break;
            } else {
                debug!("Can't connect to chromedriver yet");
                thread::sleep(time::Duration::from_secs(1));
            }
        }

        Webdriver {
            client: hyper::client::Client::new(),
            host: "localhost".to_string(),
            port: port,
            process: child,
        }
    }

    pub fn url(&self, rest: &str) -> String {
        format!("http://{}:{}/session{}", self.host, self.port, rest)
    }

    pub fn make_session(&self, device_name: &str) -> WebdriverSession {
        let mut mobile_emulation: json::Object = json::Object::new();
        mobile_emulation.insert("deviceName".to_string(), device_name.to_json());
        let mut chrome_options: json::Object = json::Object::new();
        chrome_options.insert("mobileEmulation".to_string(), mobile_emulation.to_json());
        chrome_options.insert("args".to_string(),
                              ["--start-maximized".to_string(), "--no-sandbox".to_string()]
                                  .to_json());
        let mut desired: json::Object = json::Object::new();
        desired.insert("chromeOptions".to_string(), chrome_options.to_json());
        let mut request: json::Object = json::Object::new();
        request.insert("desiredCapabilities".to_string(), desired.to_json());
        let json_str = (&request).to_json().to_string();
        let decoded = self.do_post(self.url(""), &json_str);
        let session_id = decoded.expect("ok response")
            .find("sessionId")
            .expect("sessionId")
            .as_string()
            .expect("string session id")
            .to_string();
        WebdriverSession {
            client: hyper::client::Client::new(),
            base_url: self.url(""),
            session_id: session_id,
        }
    }
}

impl Drop for Webdriver {
    fn drop(&mut self) {
        self.process.kill().unwrap();
        debug!("Killed chromedriver process");
    }
}

pub struct WebdriverMiddleware {
    pub mutex: Arc<Mutex<Webdriver>>,
}

impl WebdriverMiddleware {
    pub fn new(client: Webdriver) -> WebdriverMiddleware {
        WebdriverMiddleware { mutex: Arc::new(Mutex::new(client)) }
    }
}

impl<D> Middleware<D> for WebdriverMiddleware {
    fn invoke<'mw, 'conn>(&self,
                          req: &mut Request<'mw, 'conn, D>,
                          res: Response<'mw, D>)
                          -> MiddlewareResult<'mw, D> {
        req.extensions_mut().insert::<WebdriverMiddleware>(self.mutex.clone());
        Ok(Continue(res))
    }
}

impl Key for WebdriverMiddleware {
    type Value = Arc<Mutex<Webdriver>>;
}

pub trait WebdriverRequestExtensions {
    fn webdriver(&self) -> MutexGuard<Webdriver>;
}

impl<'a, 'b, D> WebdriverRequestExtensions for Request<'a, 'b, D> {
    fn webdriver(&self) -> MutexGuard<Webdriver> {
        self.extensions().get::<WebdriverMiddleware>().unwrap().lock().unwrap()
    }
}

impl DoesPost for Webdriver {
    fn client(&self) -> &hyper::client::Client {
        &self.client
    }
}
impl DoesPost for WebdriverSession {
    fn client(&self) -> &hyper::client::Client {
        &self.client
    }
}

impl Drop for WebdriverSession {
    fn drop(&mut self) {
        self.client()
            .delete(&self.url(format!("/{}", self.session_id)))
            .send()
            .unwrap();
    }
}

impl WebdriverSession {
    fn url(&self, rest: String) -> String {
        format!("{}{}", self.base_url, rest)
    }

    pub fn goto_url(&self, url: &String) {
        let params = GetParameters { url: url.clone() };
        self.client()
            .post(&self.url(format!("/{}/url", self.session_id)))
            .body(&params.to_json().to_string())
            .send()
            .unwrap();
    }

    pub fn get_page_source(&self) -> String {
        let mut res = self.client()
            .get(&self.url(format!("/{}/source", self.session_id)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        let decoded = decode_response(&buffer);
        decoded.unwrap().find("value").expect("value").as_string().unwrap().to_string()
    }

    pub fn find_element_by_xpath(&self, xpath: String) -> WebDriverResult<WebDriverResponse> {
        let params = LocatorParameters {
            value: xpath.clone(),
            using: LocatorStrategy::XPath,
        };
        let decoded = self.do_post(self.url(format!("/{}/element", self.session_id)),
                                   &params.to_json().to_string());
        match decoded {
            Err(val) => Err(val),
            Ok(val) => {
                Ok(WebDriverResponse::Generic(ValueResponse::new(val.find("value")
                    .expect("has value")
                    .clone())))
            }
        }
    }

    fn get_for_element(&self, element: &ValueResponse, kind: &str) -> WebDriverResult<Json> {
        let element_id =
            element.value.find("ELEMENT").expect("ELEMENT").as_string().expect("String ELEMENT");
        let mut res = self.client()
            .get(&self.url(format!("/{}/element/{}/{}", self.session_id, element_id, kind)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        debug!("Buffer: {}", buffer);
        // assert_eq!(res.status, hyper::Ok);
        let decoded = decode_response(&buffer);
        debug!("Decoded: {:?}", decoded);
        decoded
    }

    pub fn get_element_location(&self, element: &ValueResponse) -> WebDriverResult<Json> {
        self.get_for_element(element, "location")
    }

    pub fn get_element_size(&self, element: &ValueResponse) -> WebDriverResult<Json> {
        self.get_for_element(element, "size")
    }

    pub fn get_element_attribute(&self, element: &ValueResponse, name: &str) -> String {
        self.get_for_element(element, &format!("attribute/{}", name))
            .unwrap()
            .find("value")
            .expect("value")
            .as_string()
            .unwrap()
            .to_string()
    }

    pub fn get_screenshot_as_png(&self) -> Result<Vec<u8>, FromBase64Error> {
        let mut res = self.client()
            .get(&self.url(format!("/{}/screenshot", self.session_id)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        let decoded = decode_response(&buffer).expect("decoded");
        let value = decoded.find("value").expect("value").as_string().expect("string value");
        value.from_base64()
    }
}
<commit_msg>Cope with PoisonError<commit_after>use hyper;
use webdriver::command::{GetParameters, LocatorParameters};
use webdriver::common::LocatorStrategy;
use webdriver::error::{WebDriverResult, ErrorStatus, WebDriverError};
use webdriver::response::{WebDriverResponse, ValueResponse};
use std::io::Read;
use std::ops::Drop;

use rustc_serialize::json;
use rustc_serialize::json::{Json, ToJson};
use rustc_serialize::base64::{FromBase64Error, FromBase64};

use std::process::{Command, Child};
use std::env;
use std::net::TcpStream;
use std::time;
use std::thread;
use core::ops::DerefMut;

use std::sync::{Arc, Mutex, MutexGuard};
use nickel::{Request, Response, Middleware, Continue, MiddlewareResult};
use plugin::Extensible;
use typemap::Key;

use rand;
use rand::Rng;

pub struct Webdriver {
    client: hyper::client::Client,
    host: String,
    port: u16,
    process: Child,
}

impl Default for Webdriver {
    fn default() -> Self {
        panic!("No good default for webdriver");
    }
}

pub struct WebdriverSession {
    client: hyper::client::Client,
    base_url: String,
    session_id: String,
}

fn decode_response(json_str: &str) -> WebDriverResult<Json> {
    let decoded = Json::from_str(json_str).unwrap();
    let status =
        decoded.find("status").expect("status code").as_u64().expect("numeric status code");
    let value = decoded.find("value").expect("value");
    match status {
        0 => Ok(decoded.clone()),
        _ => {
            let message = value.find("message")
                .expect("error message")
                .as_string()
                .expect("a string message")
                .to_string();
            let kind = match status {
                7 => ErrorStatus::NoSuchElement,
                _ => ErrorStatus::UnknownError,
            };
            Err(WebDriverError::new(kind, message))
        }
    }
}

trait DoesPost {
    fn do_post(&self, url: String, body: &str) -> WebDriverResult<Json> {
        debug!("Request: {:?}", body);
        let mut res = self.client()
            .post(&url)
            .body(body)
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        debug!("Buffer: {}", buffer);
        // assert_eq!(res.status, hyper::Ok);
        let decoded = decode_response(&buffer);
        debug!("Decoded: {:?}", decoded);
        decoded
    }

    fn client(&self) -> &hyper::client::Client;
}

impl Webdriver {
    pub fn new() -> Webdriver {
        let chromedriver_path = match env::var("CHROMEDRIVER") {
            Ok(val) => val,
            Err(_) => "./chromedriver".to_string(),
        };
        info!("Using {} as chromedriver path", chromedriver_path);

        let port: u16 = {
            let mut rng = rand::thread_rng();
            let mut candidate: u16;
            loop {
                candidate = rng.gen_range(2048, 65535);
                debug!("Candidate port {}", candidate);
                let stream = TcpStream::connect(("localhost", candidate));
                if stream.is_ok() {
                    debug!("Already used port {}", candidate);
                } else {
                    debug!("Good port {}", candidate);
                    break;
                }
            }
            candidate
        };

        let child = Command::new(&chromedriver_path)
            .arg(format!("--port={}", port))
            .spawn()
            .expect(&format!("spawning chromedriver from {}", &chromedriver_path));

        loop {
            let stream = TcpStream::connect(("localhost", port));
            if stream.is_ok() {
                debug!("Found chromedriver");
                break;
            } else {
                debug!("Can't connect to chromedriver yet");
                thread::sleep(time::Duration::from_secs(1));
            }
        }

        Webdriver {
            client: hyper::client::Client::new(),
            host: "localhost".to_string(),
            port: port,
            process: child,
        }
    }

    pub fn url(&self, rest: &str) -> String {
        format!("http://{}:{}/session{}", self.host, self.port, rest)
    }

    pub fn make_session(&self, device_name: &str) -> WebdriverSession {
        let mut mobile_emulation: json::Object = json::Object::new();
        mobile_emulation.insert("deviceName".to_string(), device_name.to_json());
        let mut chrome_options: json::Object = json::Object::new();
        chrome_options.insert("mobileEmulation".to_string(), mobile_emulation.to_json());
        chrome_options.insert("args".to_string(),
                              ["--start-maximized".to_string(), "--no-sandbox".to_string()]
                                  .to_json());
        let mut desired: json::Object = json::Object::new();
        desired.insert("chromeOptions".to_string(), chrome_options.to_json());
        let mut request: json::Object = json::Object::new();
        request.insert("desiredCapabilities".to_string(), desired.to_json());
        let json_str = (&request).to_json().to_string();
        let decoded = self.do_post(self.url(""), &json_str);
        let session_id = decoded.expect("ok response")
            .find("sessionId")
            .expect("sessionId")
            .as_string()
            .expect("string session id")
            .to_string();
        WebdriverSession {
            client: hyper::client::Client::new(),
            base_url: self.url(""),
            session_id: session_id,
        }
    }
}

impl Drop for Webdriver {
    fn drop(&mut self) {
        self.process.kill().unwrap();
        debug!("Killed chromedriver process");
    }
}

pub struct WebdriverMiddleware {
    pub mutex: Arc<Mutex<Webdriver>>,
}

impl WebdriverMiddleware {
    pub fn new(client: Webdriver) -> WebdriverMiddleware {
        WebdriverMiddleware { mutex: Arc::new(Mutex::new(client)) }
    }
}

impl<D> Middleware<D> for WebdriverMiddleware {
    fn invoke<'mw, 'conn>(&self,
                          req: &mut Request<'mw, 'conn, D>,
                          res: Response<'mw, D>)
                          -> MiddlewareResult<'mw, D> {
        req.extensions_mut().insert::<WebdriverMiddleware>(self.mutex.clone());
        Ok(Continue(res))
    }
}

impl Key for WebdriverMiddleware {
    type Value = Arc<Mutex<Webdriver>>;
}

pub trait WebdriverRequestExtensions {
    fn webdriver(&self) -> MutexGuard<Webdriver>;
}

impl<'a, 'b, D> WebdriverRequestExtensions for Request<'a, 'b, D> {
    fn webdriver(&self) -> MutexGuard<Webdriver> {
        match self.extensions().get::<WebdriverMiddleware>().unwrap().lock() {
            Ok(val) => val,
            Err(mut err) => {
                let w = Webdriver::new();
                *err.get_mut().deref_mut() = w;
                self.extensions().get::<WebdriverMiddleware>().unwrap().lock().unwrap()
            }
        }
    }
}

impl DoesPost for Webdriver {
    fn client(&self) -> &hyper::client::Client {
        &self.client
    }
}
impl DoesPost for WebdriverSession {
    fn client(&self) -> &hyper::client::Client {
        &self.client
    }
}

impl Drop for WebdriverSession {
    fn drop(&mut self) {
        self.client()
            .delete(&self.url(format!("/{}", self.session_id)))
            .send()
            .unwrap();
    }
}

impl WebdriverSession {
    fn url(&self, rest: String) -> String {
        format!("{}{}", self.base_url, rest)
    }

    pub fn goto_url(&self, url: &String) {
        let params = GetParameters { url: url.clone() };
        self.client()
            .post(&self.url(format!("/{}/url", self.session_id)))
            .body(&params.to_json().to_string())
            .send()
            .unwrap();
    }

    pub fn get_page_source(&self) -> String {
        let mut res = self.client()
            .get(&self.url(format!("/{}/source", self.session_id)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        let decoded = decode_response(&buffer);
        decoded.unwrap().find("value").expect("value").as_string().unwrap().to_string()
    }

    pub fn find_element_by_xpath(&self, xpath: String) -> WebDriverResult<WebDriverResponse> {
        let params = LocatorParameters {
            value: xpath.clone(),
            using: LocatorStrategy::XPath,
        };
        let decoded = self.do_post(self.url(format!("/{}/element", self.session_id)),
                                   &params.to_json().to_string());
        match decoded {
            Err(val) => Err(val),
            Ok(val) => {
                Ok(WebDriverResponse::Generic(ValueResponse::new(val.find("value")
                    .expect("has value")
                    .clone())))
            }
        }
    }

    fn get_for_element(&self, element: &ValueResponse, kind: &str) -> WebDriverResult<Json> {
        let element_id =
            element.value.find("ELEMENT").expect("ELEMENT").as_string().expect("String ELEMENT");
        let mut res = self.client()
            .get(&self.url(format!("/{}/element/{}/{}", self.session_id, element_id, kind)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        debug!("Buffer: {}", buffer);
        // assert_eq!(res.status, hyper::Ok);
        let decoded = decode_response(&buffer);
        debug!("Decoded: {:?}", decoded);
        decoded
    }

    pub fn get_element_location(&self, element: &ValueResponse) -> WebDriverResult<Json> {
        self.get_for_element(element, "location")
    }

    pub fn get_element_size(&self, element: &ValueResponse) -> WebDriverResult<Json> {
        self.get_for_element(element, "size")
    }

    pub fn get_element_attribute(&self, element: &ValueResponse, name: &str) -> String {
        self.get_for_element(element, &format!("attribute/{}", name))
            .unwrap()
            .find("value")
            .expect("value")
            .as_string()
            .unwrap()
            .to_string()
    }

    pub fn get_screenshot_as_png(&self) -> Result<Vec<u8>, FromBase64Error> {
        let mut res = self.client()
            .get(&self.url(format!("/{}/screenshot", self.session_id)))
            .send()
            .unwrap();
        let mut buffer = String::new();
        res.read_to_string(&mut buffer).unwrap();
        let decoded = decode_response(&buffer).expect("decoded");
        let value = decoded.find("value").expect("value").as_string().expect("string value");
        value.from_base64()
    }
}
<|endoftext|>


<commit_before>//! Song decoding / analysis module.
//!
//! Use decoding, and features-extraction functions from other modules
//! e.g. tempo features, spectral features, etc to build a Song and its
//! corresponding Analysis.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

extern crate crossbeam;
extern crate ffmpeg_next as ffmpeg;
extern crate ndarray;
extern crate ndarray_npy;

use super::CHANNELS;
use crate::chroma::ChromaDesc;
use crate::misc::LoudnessDesc;
use crate::temporal::BPMDesc;
use crate::timbral::{SpectralDesc, ZeroCrossingRateDesc};
use crate::SAMPLE_RATE;
use crate::{Analysis, Song};
use crossbeam::thread;
use ffmpeg::codec::threading::{Config, Type as ThreadingType};
use ffmpeg::util;
use ffmpeg::util::format::sample::{Sample, Type};
use std::sync::mpsc;
use std::thread as std_thread;

pub fn push_to_sample_array(frame: &ffmpeg::frame::Audio, sample_array: &mut Vec<f32>) {
    if frame.samples() == 0 {
        return;
    }
    // Account for the padding
    let actual_size = util::format::sample::Buffer::size(
        Sample::F32(Type::Packed),
        CHANNELS,
        frame.samples(),
        false,
    );
    let f32_frame: Vec<f32> = frame.data(0)[..actual_size]
        .chunks_exact(4)
        .map(|x| {
            let mut a: [u8; 4] = [0; 4];
            a.copy_from_slice(x);
            f32::from_le_bytes(a)
        })
        .collect();
    sample_array.extend_from_slice(&f32_frame);
}

impl Song {
    pub fn new(path: &str) -> Result<Self, String> {
        // TODO error handling here
        let mut song = Song::decode(&path)?;

        song.analysis = (&song).analyze();
        Ok(song)
    }

    pub fn analyze(&self) -> Analysis {
        thread::scope(|s| {
            let child_chroma = s.spawn(|_| {
                let mut chroma_desc = ChromaDesc::new(self.sample_rate, 12);
                chroma_desc.do_(&self.sample_array);
                chroma_desc.get_values()
            });

            // These descriptors can be streamed
            let child_timbral = s.spawn(|_| {
                let mut spectral_desc = SpectralDesc::new(self.sample_rate);
                let windows = self
                    .sample_array
                    .windows(SpectralDesc::WINDOW_SIZE)
                    .step_by(SpectralDesc::HOP_SIZE);
                for window in windows {
                    spectral_desc.do_(&window);
                }
                let centroid = spectral_desc.get_centroid();
                let rolloff = spectral_desc.get_rolloff();
                let flatness = spectral_desc.get_flatness();
                (centroid, rolloff, flatness)
            });

            let child_zcr = s.spawn(|_| {
                let mut zcr_desc = ZeroCrossingRateDesc::default();
                let windows = self
                    .sample_array
                    .windows(SpectralDesc::WINDOW_SIZE)
                    .step_by(SpectralDesc::HOP_SIZE);
                for window in windows {
                    zcr_desc.do_(&window);
                }
                zcr_desc.get_value()
            });
            let child_tempo = s.spawn(|_| {
                let mut tempo_desc = BPMDesc::new(self.sample_rate);
                let windows = self
                    .sample_array
                    .windows(BPMDesc::WINDOW_SIZE)
                    .step_by(BPMDesc::HOP_SIZE);

                for window in windows {
                    tempo_desc.do_(&window);
                }
                tempo_desc.get_value()
            });

            let child_loudness = s.spawn(|_| {
                let mut loudness_desc = LoudnessDesc::default();
                let windows = self.sample_array.chunks(LoudnessDesc::WINDOW_SIZE);

                for window in windows {
                    loudness_desc.do_(&window);
                }
                loudness_desc.get_value()
            });

            // Non-streaming approach for that one
            let (is_major, fifth) = child_chroma.join().unwrap();
            let (centroid, rolloff, flatness) = child_timbral.join().unwrap();
            let tempo = child_tempo.join().unwrap();
            let loudness = child_loudness.join().unwrap();
            let zcr = child_zcr.join().unwrap();

            Analysis {
                tempo,
                spectral_centroid: centroid,
                zero_crossing_rate: zcr,
                spectral_rolloff: rolloff,
                spectral_flatness: flatness,
                loudness,
                is_major,
                fifth,
            }
        })
        .unwrap()
    }

    // TODO set av_logs to quiet
    pub fn decode(path: &str) -> Result<Song, String> {
        ffmpeg::init().map_err(|e| format!("FFmpeg init error: {:?}.", e))?;

        let mut song = Song::default();
        song.path = path.to_string();
        let mut format = ffmpeg::format::input(&path)
            .map_err(|e| format!("FFmpeg error while opening format: {:?}.", e))?;
        let (mut codec, stream, expected_sample_number) = {
            let stream = format
                .streams()
                .find(|s| s.codec().medium() == ffmpeg::media::Type::Audio)
                .ok_or("No audio stream found.")?;
            stream.codec().set_threading(Config {
                kind: ThreadingType::Frame,
                count: 0,
                safe: true,
            });
            let codec = stream
                .codec()
                .decoder()
                .audio()
                .map_err(|e| format!("FFmpeg error when finding codec: {:?}.", e))?;
            let expected_sample_number = (SAMPLE_RATE as f32 * stream.duration() as f32
                / stream.time_base().denominator() as f32)
                .ceil();
            (codec, stream.index(), expected_sample_number)
        };
        let mut sample_array: Vec<f32> = Vec::with_capacity(expected_sample_number as usize);

        if let Some(title) = format.metadata().get("title") {
            song.title = title.to_string();
        };
        if let Some(artist) = format.metadata().get("artist") {
            song.artist = artist.to_string();
        };
        if let Some(album) = format.metadata().get("album") {
            song.album = album.to_string();
        };
        if let Some(genre) = format.metadata().get("genre") {
            song.genre = genre.to_string();
        };
        if let Some(track_number) = format.metadata().get("track") {
            song.track_number = track_number.to_string();
        };

        // TODO handle WAV without a channel layout set (cf bruiblan.wav)
        let mut resample_context = ffmpeg::software::resampling::context::Context::get(
            codec.format(),
            codec.channel_layout(),
            codec.rate(),
            Sample::F32(Type::Packed),
            ffmpeg::util::channel_layout::ChannelLayout::MONO,
            SAMPLE_RATE,
        )
        .map_err(|e| {
            format!(
                "FFmpeg error trying to allocate resampling context: {:?}",
                e
            )
        })?;

        let (tx, rx) = mpsc::channel();
        let child = std_thread::spawn(move || -> Result<Vec<f32>, String> {
            let mut resampled = ffmpeg::frame::Audio::empty();
            for decoded in rx.iter() {
                resample_context
                    .run(&decoded, &mut resampled)
                    .map_err(|e| format!("FFmpeg error while trying to resample song: {:?}", e))?;
                push_to_sample_array(&resampled, &mut sample_array);
            }

            loop {
                match resample_context
                    .flush(&mut resampled)
                    .map_err(|e| format!("FFmpeg error while trying to resample song: {:?}", e))?
                {
                    Some(_) => {
                        push_to_sample_array(&resampled, &mut sample_array);
                    }
                    None => {
                        push_to_sample_array(&resampled, &mut sample_array);
                        break;
                    }
                };
            }
            Ok(sample_array)
        });
        for (s, packet) in format.packets() {
            if s.index() != stream {
                continue;
            }
            codec.send_packet(&packet).unwrap();
            loop {
                let mut decoded = ffmpeg::frame::Audio::empty();
                match codec.receive_frame(&mut decoded) {
                    Ok(_) => {
                        tx.send(decoded).map_err(|e| {
                            format!(
                                "Error while sending decoded frame to the resampling thread: {:?}",
                                e
                            )
                        })?;
                    },
                    Err(_) => break,
                }
            }
        }

        // Flush the stream
        // TODO check that it's still how to do this
        let packet = ffmpeg::codec::packet::Packet::empty();
        loop {
            codec.send_packet(&packet).unwrap();
            loop {
                let mut decoded = ffmpeg::frame::Audio::empty();
                match codec.receive_frame(&mut decoded) {
                    Ok(_) => {
                        tx.send(decoded).map_err(|e| {
                            format!(
                                "Error while sending decoded frame to the resampling thread: {:?}",
                                e
                            )
                        })?;
                    },
                    Err(_) => break,
                }
            }
            break;
        }

        drop(tx);
        song.sample_array = child.join().unwrap()?;
        song.sample_rate = SAMPLE_RATE;
        Ok(song)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ripemd160::{Digest, Ripemd160};
    use std::f32::consts::PI;

    #[test]
    fn test_analyze() {
        let song = Song::decode("data/s16_mono_22_5kHz.flac").unwrap();
        let expected_analysis = Analysis {
            tempo: 0.37860596,
            spectral_centroid: -0.75483,
            zero_crossing_rate: -0.85036564,
            spectral_rolloff: -0.6326486,
            spectral_flatness: -0.77610075,
            loudness: 0.27126348,
            is_major: -1.,
            fifth: (f32::cos(5. * PI / 3.), f32::sin(5. * PI / 3.)),
        };
        assert!(expected_analysis.approx_eq(&song.analyze()));
    }

    fn _test_decode(path: &str, expected_hash: &[u8]) {
        let song = Song::decode(path).unwrap();
        let mut hasher = Ripemd160::new();
        for sample in song.sample_array.iter() {
            hasher.update(sample.to_le_bytes().to_vec());
        }

        assert_eq!(expected_hash, hasher.finalize().as_slice());
    }

    #[test]
    fn tags() {
        let song = Song::decode("data/s16_mono_22_5kHz.flac").unwrap();
        assert_eq!(song.artist, "David TMX");
        assert_eq!(song.title, "Renaissance");
        assert_eq!(song.album, "Renaissance");
        assert_eq!(song.track_number, "02");
        assert_eq!(song.genre, "Pop");
    }

    #[test]
    fn resample_multi() {
        let path = String::from("data/s32_stereo_44_1_kHz.flac");
        let expected_hash = [
            0xc5, 0xf8, 0x23, 0xce, 0x63, 0x2c, 0xf4, 0xa0, 0x72, 0x66, 0xbb, 0x49, 0xad, 0x84,
            0xb6, 0xea, 0x48, 0x48, 0x9c, 0x50,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn resample_stereo() {
        let path = String::from("data/s16_stereo_22_5kHz.flac");
        let expected_hash = [
            0x24, 0xed, 0x45, 0x58, 0x06, 0xbf, 0xfb, 0x05, 0x57, 0x5f, 0xdc, 0x4d, 0xb4, 0x9b,
            0xa5, 0x2b, 0x05, 0x56, 0x10, 0x4f,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn decode_mono() {
        let path = String::from("data/s16_mono_22_5kHz.flac");
        // Obtained through
        // ffmpeg -i data/s16_mono_22_5kHz.flac -ar 22050 -ac 1 -c:a pcm_f32le
        // -f hash -hash ripemd160 -
        let expected_hash = [
            0x9d, 0x95, 0xa5, 0xf2, 0xd2, 0x9c, 0x68, 0xe8, 0x8a, 0x70, 0xcd, 0xf3, 0x54, 0x2c,
            0x5b, 0x45, 0x98, 0xb4, 0xf3, 0xb4,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn test_decode_right_capacity_vec() {
        let path = String::from("data/s16_mono_22_5kHz.flac");
        let song = Song::decode(&path).unwrap();
        assert_eq!(song.sample_array.len(), song.sample_array.capacity());

        let path = String::from("data/s32_stereo_44_1_kHz.flac");
        let song = Song::decode(&path).unwrap();
        assert_eq!(song.sample_array.len(), song.sample_array.capacity());

        // Not 100% sure that the number of samples for ogg is known
        // precisely in advance
        let path = String::from("data/capacity_fix.ogg");
        let song = Song::decode(&path).unwrap();
        assert!(song.sample_array.len() as f32 / song.sample_array.capacity() as f32 > 0.95);
        assert!(song.sample_array.len() as f32 / (song.sample_array.capacity() as f32) < 1.);
    }
}
<commit_msg>Make ZCR take the whole track<commit_after>//! Song decoding / analysis module.
//!
//! Use decoding, and features-extraction functions from other modules
//! e.g. tempo features, spectral features, etc to build a Song and its
//! corresponding Analysis.
#[cfg(feature = "aubio-lib")]
extern crate aubio_lib;

extern crate crossbeam;
extern crate ffmpeg_next as ffmpeg;
extern crate ndarray;
extern crate ndarray_npy;

use super::CHANNELS;
use crate::chroma::ChromaDesc;
use crate::misc::LoudnessDesc;
use crate::temporal::BPMDesc;
use crate::timbral::{SpectralDesc, ZeroCrossingRateDesc};
use crate::SAMPLE_RATE;
use crate::{Analysis, Song};
use crossbeam::thread;
use ffmpeg::codec::threading::{Config, Type as ThreadingType};
use ffmpeg::util;
use ffmpeg::util::format::sample::{Sample, Type};
use std::sync::mpsc;
use std::thread as std_thread;

pub fn push_to_sample_array(frame: &ffmpeg::frame::Audio, sample_array: &mut Vec<f32>) {
    if frame.samples() == 0 {
        return;
    }
    // Account for the padding
    let actual_size = util::format::sample::Buffer::size(
        Sample::F32(Type::Packed),
        CHANNELS,
        frame.samples(),
        false,
    );
    let f32_frame: Vec<f32> = frame.data(0)[..actual_size]
        .chunks_exact(4)
        .map(|x| {
            let mut a: [u8; 4] = [0; 4];
            a.copy_from_slice(x);
            f32::from_le_bytes(a)
        })
        .collect();
    sample_array.extend_from_slice(&f32_frame);
}

impl Song {
    pub fn new(path: &str) -> Result<Self, String> {
        // TODO error handling here
        let mut song = Song::decode(&path)?;

        song.analysis = (&song).analyze();
        Ok(song)
    }

    // TODO write down somewhere that this can be done windows by windows
    pub fn analyze(&self) -> Analysis {
        thread::scope(|s| {
            let child_chroma = s.spawn(|_| {
                let mut chroma_desc = ChromaDesc::new(self.sample_rate, 12);
                chroma_desc.do_(&self.sample_array);
                chroma_desc.get_values()
            });

            // These descriptors can be streamed
            let child_timbral = s.spawn(|_| {
                let mut spectral_desc = SpectralDesc::new(self.sample_rate);
                let windows = self
                    .sample_array
                    .windows(SpectralDesc::WINDOW_SIZE)
                    .step_by(SpectralDesc::HOP_SIZE);
                for window in windows {
                    spectral_desc.do_(&window);
                }
                let centroid = spectral_desc.get_centroid();
                let rolloff = spectral_desc.get_rolloff();
                let flatness = spectral_desc.get_flatness();
                (centroid, rolloff, flatness)
            });

            let child_zcr = s.spawn(|_| {
                let mut zcr_desc = ZeroCrossingRateDesc::default();
                zcr_desc.do_(&self.sample_array);
                zcr_desc.get_value()
            });
            let child_tempo = s.spawn(|_| {
                let mut tempo_desc = BPMDesc::new(self.sample_rate);
                let windows = self
                    .sample_array
                    .windows(BPMDesc::WINDOW_SIZE)
                    .step_by(BPMDesc::HOP_SIZE);

                for window in windows {
                    tempo_desc.do_(&window);
                }
                tempo_desc.get_value()
            });

            let child_loudness = s.spawn(|_| {
                let mut loudness_desc = LoudnessDesc::default();
                let windows = self.sample_array.chunks(LoudnessDesc::WINDOW_SIZE);

                for window in windows {
                    loudness_desc.do_(&window);
                }
                loudness_desc.get_value()
            });

            // Non-streaming approach for that one
            let (is_major, fifth) = child_chroma.join().unwrap();
            let (centroid, rolloff, flatness) = child_timbral.join().unwrap();
            let tempo = child_tempo.join().unwrap();
            let loudness = child_loudness.join().unwrap();
            let zcr = child_zcr.join().unwrap();

            Analysis {
                tempo,
                spectral_centroid: centroid,
                zero_crossing_rate: zcr,
                spectral_rolloff: rolloff,
                spectral_flatness: flatness,
                loudness,
                is_major,
                fifth,
            }
        })
        .unwrap()
    }

    // TODO set av_logs to quiet
    pub fn decode(path: &str) -> Result<Song, String> {
        ffmpeg::init().map_err(|e| format!("FFmpeg init error: {:?}.", e))?;

        let mut song = Song::default();
        song.path = path.to_string();
        let mut format = ffmpeg::format::input(&path)
            .map_err(|e| format!("FFmpeg error while opening format: {:?}.", e))?;
        let (mut codec, stream, expected_sample_number) = {
            let stream = format
                .streams()
                .find(|s| s.codec().medium() == ffmpeg::media::Type::Audio)
                .ok_or("No audio stream found.")?;
            stream.codec().set_threading(Config {
                kind: ThreadingType::Frame,
                count: 0,
                safe: true,
            });
            let codec = stream
                .codec()
                .decoder()
                .audio()
                .map_err(|e| format!("FFmpeg error when finding codec: {:?}.", e))?;
            let expected_sample_number = (SAMPLE_RATE as f32 * stream.duration() as f32
                / stream.time_base().denominator() as f32)
                .ceil();
            (codec, stream.index(), expected_sample_number)
        };
        let mut sample_array: Vec<f32> = Vec::with_capacity(expected_sample_number as usize);

        if let Some(title) = format.metadata().get("title") {
            song.title = title.to_string();
        };
        if let Some(artist) = format.metadata().get("artist") {
            song.artist = artist.to_string();
        };
        if let Some(album) = format.metadata().get("album") {
            song.album = album.to_string();
        };
        if let Some(genre) = format.metadata().get("genre") {
            song.genre = genre.to_string();
        };
        if let Some(track_number) = format.metadata().get("track") {
            song.track_number = track_number.to_string();
        };

        // TODO handle WAV without a channel layout set (cf bruiblan.wav)
        let mut resample_context = ffmpeg::software::resampling::context::Context::get(
            codec.format(),
            codec.channel_layout(),
            codec.rate(),
            Sample::F32(Type::Packed),
            ffmpeg::util::channel_layout::ChannelLayout::MONO,
            SAMPLE_RATE,
        )
        .map_err(|e| {
            format!(
                "FFmpeg error trying to allocate resampling context: {:?}",
                e
            )
        })?;

        let (tx, rx) = mpsc::channel();
        let child = std_thread::spawn(move || -> Result<Vec<f32>, String> {
            let mut resampled = ffmpeg::frame::Audio::empty();
            for decoded in rx.iter() {
                resample_context
                    .run(&decoded, &mut resampled)
                    .map_err(|e| format!("FFmpeg error while trying to resample song: {:?}", e))?;
                push_to_sample_array(&resampled, &mut sample_array);
            }

            loop {
                match resample_context
                    .flush(&mut resampled)
                    .map_err(|e| format!("FFmpeg error while trying to resample song: {:?}", e))?
                {
                    Some(_) => {
                        push_to_sample_array(&resampled, &mut sample_array);
                    }
                    None => {
                        push_to_sample_array(&resampled, &mut sample_array);
                        break;
                    }
                };
            }
            Ok(sample_array)
        });
        for (s, packet) in format.packets() {
            if s.index() != stream {
                continue;
            }
            codec.send_packet(&packet).unwrap();
            loop {
                let mut decoded = ffmpeg::frame::Audio::empty();
                match codec.receive_frame(&mut decoded) {
                    Ok(_) => {
                        tx.send(decoded).map_err(|e| {
                            format!(
                                "Error while sending decoded frame to the resampling thread: {:?}",
                                e
                            )
                        })?;
                    },
                    Err(_) => break,
                }
            }
        }

        // Flush the stream
        // TODO check that it's still how to do this
        let packet = ffmpeg::codec::packet::Packet::empty();
        loop {
            codec.send_packet(&packet).unwrap();
            loop {
                let mut decoded = ffmpeg::frame::Audio::empty();
                match codec.receive_frame(&mut decoded) {
                    Ok(_) => {
                        tx.send(decoded).map_err(|e| {
                            format!(
                                "Error while sending decoded frame to the resampling thread: {:?}",
                                e
                            )
                        })?;
                    },
                    Err(_) => break,
                }
            }
            break;
        }

        drop(tx);
        song.sample_array = child.join().unwrap()?;
        song.sample_rate = SAMPLE_RATE;
        Ok(song)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ripemd160::{Digest, Ripemd160};
    use std::f32::consts::PI;

    #[test]
    fn test_analyze() {
        let song = Song::decode("data/s16_mono_22_5kHz.flac").unwrap();
        let expected_analysis = Analysis {
            tempo: 0.37860596,
            spectral_centroid: -0.75483,
            zero_crossing_rate: -0.85036564,
            spectral_rolloff: -0.6326486,
            spectral_flatness: -0.77610075,
            loudness: 0.27126348,
            is_major: -1.,
            fifth: (f32::cos(5. * PI / 3.), f32::sin(5. * PI / 3.)),
        };
        assert!(expected_analysis.approx_eq(&song.analyze()));
    }

    fn _test_decode(path: &str, expected_hash: &[u8]) {
        let song = Song::decode(path).unwrap();
        let mut hasher = Ripemd160::new();
        for sample in song.sample_array.iter() {
            hasher.update(sample.to_le_bytes().to_vec());
        }

        assert_eq!(expected_hash, hasher.finalize().as_slice());
    }

    #[test]
    fn tags() {
        let song = Song::decode("data/s16_mono_22_5kHz.flac").unwrap();
        assert_eq!(song.artist, "David TMX");
        assert_eq!(song.title, "Renaissance");
        assert_eq!(song.album, "Renaissance");
        assert_eq!(song.track_number, "02");
        assert_eq!(song.genre, "Pop");
    }

    #[test]
    fn resample_multi() {
        let path = String::from("data/s32_stereo_44_1_kHz.flac");
        let expected_hash = [
            0xc5, 0xf8, 0x23, 0xce, 0x63, 0x2c, 0xf4, 0xa0, 0x72, 0x66, 0xbb, 0x49, 0xad, 0x84,
            0xb6, 0xea, 0x48, 0x48, 0x9c, 0x50,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn resample_stereo() {
        let path = String::from("data/s16_stereo_22_5kHz.flac");
        let expected_hash = [
            0x24, 0xed, 0x45, 0x58, 0x06, 0xbf, 0xfb, 0x05, 0x57, 0x5f, 0xdc, 0x4d, 0xb4, 0x9b,
            0xa5, 0x2b, 0x05, 0x56, 0x10, 0x4f,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn decode_mono() {
        let path = String::from("data/s16_mono_22_5kHz.flac");
        // Obtained through
        // ffmpeg -i data/s16_mono_22_5kHz.flac -ar 22050 -ac 1 -c:a pcm_f32le
        // -f hash -hash ripemd160 -
        let expected_hash = [
            0x9d, 0x95, 0xa5, 0xf2, 0xd2, 0x9c, 0x68, 0xe8, 0x8a, 0x70, 0xcd, 0xf3, 0x54, 0x2c,
            0x5b, 0x45, 0x98, 0xb4, 0xf3, 0xb4,
        ];
        _test_decode(&path, &expected_hash);
    }

    #[test]
    fn test_decode_right_capacity_vec() {
        let path = String::from("data/s16_mono_22_5kHz.flac");
        let song = Song::decode(&path).unwrap();
        assert_eq!(song.sample_array.len(), song.sample_array.capacity());

        let path = String::from("data/s32_stereo_44_1_kHz.flac");
        let song = Song::decode(&path).unwrap();
        assert_eq!(song.sample_array.len(), song.sample_array.capacity());

        // Not 100% sure that the number of samples for ogg is known
        // precisely in advance
        let path = String::from("data/capacity_fix.ogg");
        let song = Song::decode(&path).unwrap();
        assert!(song.sample_array.len() as f32 / song.sample_array.capacity() as f32 > 0.95);
        assert!(song.sample_array.len() as f32 / (song.sample_array.capacity() as f32) < 1.);
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate url;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path,PathBuf};

use cargo::core::shell::Verbosity;
use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
use cargo::util::CliError;

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_explain: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
    flag_locked: bool,
    flag_frozen: bool,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    --explain CODE      Run `rustc --explain CODE`
    -v, --verbose ...   Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never
    --frozen            Require Cargo.lock and cache are up to date
    --locked            Require Cargo.lock is up to date

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(check);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

macro_rules! declare_mod {
    ($name:ident) => ( pub mod $name; )
}
each_subcommand!(declare_mod);

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.configure(flags.flag_verbose,
                     flags.flag_quiet,
                     &flags.flag_color,
                     flags.flag_frozen,
                     flags.flag_locked)?;

    init_git_transports(config);
    let _token = cargo::util::job::setup();

    if flags.flag_version {
        println!("{}", cargo::version());
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    if let Some(ref code) = flags.flag_explain {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec().map_err(human)?;
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbosity(Verbosity::Verbose);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => {
            let mut default_alias = HashMap::new();
            default_alias.insert("b", "build".to_string());
            default_alias.insert("t", "test".to_string());
            default_alias.insert("r", "run".to_string());
            let mut args: Vec<String> = env::args().collect();
            if let Some(new_command) = default_alias.get(&args[1][..]){
                args[1] = new_command.clone();
            }
            args
        }
    };

    if try_execute(&config, &args) {
        return Ok(None)
    }

    let alias_list = aliased_command(&config, &args[1])?;
    let args = match alias_list {
        Some(alias_command) => {
            let chain = args.iter().take(1)
                .chain(alias_command.iter())
                .chain(args.iter().skip(2))
                .map(|s| s.to_string())
                .collect::<Vec<_>>();
            if try_execute(&config, &chain) {
                return Ok(None)
            } else {
                chain
            }
        }
        None => args,
    };
    execute_subcommand(config, &args[1], &args)?;
    Ok(None)
}

fn try_execute(config: &Config, args: &[String]) -> bool {
    macro_rules! cmd {
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbosity(Verbosity::Verbose);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return true
        })
    }
    each_subcommand!(cmd);

    return false
}

fn aliased_command(config: &Config, command: &String) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record.val.split_whitespace()
                                               .map(|s| s.to_string())
                                               .collect();
                result = Ok(Some(alias_commands));
            }
        },
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> = record.val.iter()
                                .map(|s| s.0.to_string()).collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CliResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand: `{}`\n\n\t\
                                          Did you mean `{}`?\n", cmd, closest),
                None => format!("no such subcommand: `{}`", cmd)
            }).into())
        }
    };
    let err = match util::process(&command).args(&args[1..]).exec() {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(code) = err.exit.as_ref().and_then(|c| c.code()) {
        Err(CliError::code(code))
    } else {
        Err(CliError::new(Box::new(err), 101))
    }
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(filename[prefix.len()..end].to_string());
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|metadata| {
        metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).map(|metadata| metadata.is_file()).unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>make `cargo --version --verbose` print extra information<commit_after>extern crate cargo;
extern crate url;
extern crate env_logger;
extern crate git2_curl;
extern crate rustc_serialize;
extern crate toml;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path,PathBuf};

use cargo::core::shell::Verbosity;
use cargo::execute_main_without_stdin;
use cargo::util::{self, CliResult, lev_distance, Config, human, CargoResult};
use cargo::util::CliError;

#[derive(RustcDecodable)]
pub struct Flags {
    flag_list: bool,
    flag_version: bool,
    flag_verbose: u32,
    flag_quiet: Option<bool>,
    flag_color: Option<String>,
    flag_explain: Option<String>,
    arg_command: String,
    arg_args: Vec<String>,
    flag_locked: bool,
    flag_frozen: bool,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help          Display this message
    -V, --version       Print version info and exit
    --list              List installed commands
    --explain CODE      Run `rustc --explain CODE`
    -v, --verbose ...   Use verbose output (-vv very verbose/build.rs output)
    -q, --quiet         No output printed to stdout
    --color WHEN        Coloring: auto, always, never
    --frozen            Require Cargo.lock and cache are up to date
    --locked            Require Cargo.lock is up to date

Some common cargo commands are (see all commands with --list):
    build       Compile the current project
    check       Analyze the current project and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    init        Create a new cargo project in an existing directory
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this project to the registry
    install     Install a Rust binary

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{
    ($mac:ident) => {
        $mac!(bench);
        $mac!(build);
        $mac!(check);
        $mac!(clean);
        $mac!(doc);
        $mac!(fetch);
        $mac!(generate_lockfile);
        $mac!(git_checkout);
        $mac!(help);
        $mac!(init);
        $mac!(install);
        $mac!(locate_project);
        $mac!(login);
        $mac!(metadata);
        $mac!(new);
        $mac!(owner);
        $mac!(package);
        $mac!(pkgid);
        $mac!(publish);
        $mac!(read_manifest);
        $mac!(run);
        $mac!(rustc);
        $mac!(rustdoc);
        $mac!(search);
        $mac!(test);
        $mac!(uninstall);
        $mac!(update);
        $mac!(verify_project);
        $mac!(version);
        $mac!(yank);
    }
}

macro_rules! declare_mod {
    ($name:ident) => ( pub mod $name; )
}
each_subcommand!(declare_mod);

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.configure(flags.flag_verbose,
                     flags.flag_quiet,
                     &flags.flag_color,
                     flags.flag_frozen,
                     flags.flag_locked)?;

    init_git_transports(config);
    let _token = cargo::util::job::setup();

    if flags.flag_version {
        let version = cargo::version();
        println!("{}", version);
        if flags.flag_verbose > 0{
            println!("release: {}.{}.{}",
                     version.major, version.minor, version.patch);
            if let Some(ref cfg) = version.cfg_info {
                if let Some(ref ci) = cfg.commit_info {
                    println!("commit-hash: {}", ci.commit_hash);
                    println!("commit-date: {}", ci.commit_date);
                }
            }
        }
        return Ok(None)
    }

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands(config) {
            println!("    {}", command);
        };
        return Ok(None)
    }

    if let Some(ref code) = flags.flag_explain {
        let mut procss = config.rustc()?.process();
        procss.arg("--explain").arg(code).exec().map_err(human)?;
        return Ok(None)
    }

    let args = match &flags.arg_command[..] {
        // For the commands `cargo` and `cargo help`, re-execute ourselves as
        // `cargo -h` so we can go through the normal process of printing the
        // help message.
        "" | "help" if flags.arg_args.is_empty() => {
            config.shell().set_verbosity(Verbosity::Verbose);
            let args = &["cargo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return Ok(None)
        }

        // For `cargo help -h` and `cargo help --help`, print out the help
        // message for `cargo help`
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" => {
            vec!["cargo".to_string(), "help".to_string(), "-h".to_string()]
        }

        // For `cargo help foo`, print out the usage message for the specified
        // subcommand by executing the command with the `-h` flag.
        "help" => vec!["cargo".to_string(), flags.arg_args[0].clone(),
                       "-h".to_string()],

        // For all other invocations, we're of the form `cargo foo args...`. We
        // use the exact environment arguments to preserve tokens like `--` for
        // example.
        _ => {
            let mut default_alias = HashMap::new();
            default_alias.insert("b", "build".to_string());
            default_alias.insert("t", "test".to_string());
            default_alias.insert("r", "run".to_string());
            let mut args: Vec<String> = env::args().collect();
            if let Some(new_command) = default_alias.get(&args[1][..]){
                args[1] = new_command.clone();
            }
            args
        }
    };

    if try_execute(&config, &args) {
        return Ok(None)
    }

    let alias_list = aliased_command(&config, &args[1])?;
    let args = match alias_list {
        Some(alias_command) => {
            let chain = args.iter().take(1)
                .chain(alias_command.iter())
                .chain(args.iter().skip(2))
                .map(|s| s.to_string())
                .collect::<Vec<_>>();
            if try_execute(&config, &chain) {
                return Ok(None)
            } else {
                chain
            }
        }
        None => args,
    };
    execute_subcommand(config, &args[1], &args)?;
    Ok(None)
}

fn try_execute(config: &Config, args: &[String]) -> bool {
    macro_rules! cmd {
        ($name:ident) => (if args[1] == stringify!($name).replace("_", "-") {
            config.shell().set_verbosity(Verbosity::Verbose);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut config.shell());
            return true
        })
    }
    each_subcommand!(cmd);

    return false
}

fn aliased_command(config: &Config, command: &String) -> CargoResult<Option<Vec<String>>> {
    let alias_name = format!("alias.{}", command);
    let mut result = Ok(None);
    match config.get_string(&alias_name) {
        Ok(value) => {
            if let Some(record) = value {
                let alias_commands = record.val.split_whitespace()
                                               .map(|s| s.to_string())
                                               .collect();
                result = Ok(Some(alias_commands));
            }
        },
        Err(_) => {
            let value = config.get_list(&alias_name)?;
            if let Some(record) = value {
                let alias_commands: Vec<String> = record.val.iter()
                                .map(|s| s.0.to_string()).collect();
                result = Ok(Some(alias_commands));
            }
        }
    }
    result
}

fn find_closest(config: &Config, cmd: &str) -> Option<String> {
    let cmds = list_commands(config);
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    let mut filtered = cmds.iter().map(|c| (lev_distance(&c, cmd), c))
                                  .filter(|&(d, _)| d < 4)
                                  .collect::<Vec<_>>();
    filtered.sort_by(|a, b| a.0.cmp(&b.0));
    filtered.get(0).map(|slot| slot.1.clone())
}

fn execute_subcommand(config: &Config,
                      cmd: &str,
                      args: &[String]) -> CliResult<()> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let path = search_directories(config)
                    .iter()
                    .map(|dir| dir.join(&command_exe))
                    .find(|file| is_executable(file));
    let command = match path {
        Some(command) => command,
        None => {
            return Err(human(match find_closest(config, cmd) {
                Some(closest) => format!("no such subcommand: `{}`\n\n\t\
                                          Did you mean `{}`?\n", cmd, closest),
                None => format!("no such subcommand: `{}`", cmd)
            }).into())
        }
    };
    let err = match util::process(&command).args(&args[1..]).exec() {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if let Some(code) = err.exit.as_ref().and_then(|c| c.code()) {
        Err(CliError::code(code))
    } else {
        Err(CliError::new(Box::new(err), 101))
    }
}

/// List all runnable commands
fn list_commands(config: &Config) -> BTreeSet<String> {
    let prefix = "cargo-";
    let suffix = env::consts::EXE_SUFFIX;
    let mut commands = BTreeSet::new();
    for dir in search_directories(config) {
        let entries = match fs::read_dir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.filter_map(|e| e.ok()) {
            let path = entry.path();
            let filename = match path.file_name().and_then(|s| s.to_str()) {
                Some(filename) => filename,
                _ => continue
            };
            if !filename.starts_with(prefix) || !filename.ends_with(suffix) {
                continue
            }
            if is_executable(entry.path()) {
                let end = filename.len() - suffix.len();
                commands.insert(filename[prefix.len()..end].to_string());
            }
        }
    }

    macro_rules! add_cmd {
        ($cmd:ident) => ({ commands.insert(stringify!($cmd).replace("_", "-")); })
    }
    each_subcommand!(add_cmd);
    commands
}

#[cfg(unix)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    use std::os::unix::prelude::*;
    fs::metadata(path).map(|metadata| {
        metadata.is_file() && metadata.permissions().mode() & 0o111 != 0
    }).unwrap_or(false)
}
#[cfg(windows)]
fn is_executable<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).map(|metadata| metadata.is_file()).unwrap_or(false)
}

fn search_directories(config: &Config) -> Vec<PathBuf> {
    let mut dirs = vec![config.home().clone().into_path_unlocked().join("bin")];
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>