<commit_before>extern crate mysql;
extern crate toml;
extern crate rustc_serialize;
#[macro_use]
extern crate lazy_static;

mod lib;

use lib::config;
use lib::downloader::DownloadDB;
use lib::downloader::Downloader;
use lib::DownloadError;
use lib::converter::Converter;

use std::fs::{remove_file,remove_dir};

static VERSION : &'static str = "0.1"; // String not valid
static SLEEP_MS: u32 = 5000;
static CODE_FAILED: i8 = 3;
static CODE_SUCCESS: i8 = 2;

lazy_static! {
    pub static ref CONFIG: config::Config = {
        println!("Starting yayd-backend v{}",&VERSION);
        config::init_config() //return
    };

}

//#[repr(i8)] broken, enum not usable as of #10292
// enum QueryCodes {
//     Waiting = 0,
//     InProgress = 1,
//     Finished = 2,
//     Failed = 3,
// }

fn main() {

    let pool = lib::db_connect(lib::mysql_options(), SLEEP_MS);

    let converter = Converter::new(&CONFIG.general.ffmpeg_bin,&CONFIG.general.mp3_quality , pool.clone());
    let mut print_pause = true;
    loop {
        if let Some(result) = lib::request_entry(& pool) {
            print_pause = true;
            let qid = result.qid.clone();                 //&QueryCodes::InProgress as i32
            lib::set_query_code(&mut pool.get_conn().unwrap(), &1, &result.qid).ok().expect("Failed to set query code!");
            lib::set_query_state(&pool.clone(),&qid, "started", false);

            let succes;
            {
                let mut left_files: Vec<String> = Vec::with_capacity(2);
                if result.playlist {
                    succes = match handle_playlist(result, &converter,&mut left_files) {
                        Ok(v) => Ok(v),
                        Err(e) => {println!("Playlist Error: {:?}", e); Err(e) }
                    };
                }else{
                    succes = match handle_download(result, &None, &converter,&mut left_files) {
                        Ok(v) => Ok(v),
                        Err(e) => {println!("Download Error: {:?}", e); Err(e) }
                    };
                }

                if !left_files.is_empty() {
                    println!("cleaning up files");
                    for i in &left_files {
                        match remove_file(&i) {
                            Ok(_) => (println!("cleaning up {}",i)),
                            Err(e) => println!("unable to remove file '{}' {}",i,e),
                        }
                    }
                }
            }

            let code: i8 = if succes.is_ok() {
                CODE_SUCCESS//QueryCode
            } else {
                CODE_FAILED//QueryCode
            };
            lib::set_query_code(&mut pool.get_conn().unwrap(), &code,&qid).ok().expect("Failed to set query code!");

            let state = if code == 2 {
                "finished"
            } else {
                "failed"
            };
            lib::set_query_state(&pool.clone(),&qid, state, true);

        } else {
            if print_pause { println!("Pausing.."); print_pause = false; }
            std::thread::sleep_ms(SLEEP_MS);
        }
    }
}

///Download handler
///Used by the playlist/file handler to download one file
///Based on the quality it needs to download audio & video separately and convert them together
///In case of a playlist download it depends on the target download folder & if it should be bezipped
///In case of a DMCA we need to download the file via the socket connector,
///which will output a mp3, or if requested, the video but with the highest quality.
///Thus in case of a DMCA we can't pick a quality anymore.
///Also the filename depends on the socket output then.
///
///If it's a non-zipped single file, it's moved after a successful download, converted etc to the
///main folder from which it should be downloadable.
///The original non-ascii & url_encode'd name of the file is stored in the DB
fn handle_download<'a>(downl_db: DownloadDB, folder: &Option<String>, converter: &Converter, file_db: &mut Vec<String>) -> Result<Option<String>,DownloadError>{
    //update progress
    let is_zipped = match *folder {
        Some(_) => true,
        None => false,
    };
    if !downl_db.compress {
        lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 1, 0,false);
    }

    let download = Downloader::new(&downl_db, &CONFIG.general);
    //get filename, check for DMCA
    let mut dmca = false; // "succ." dmca -> file already downloaded

    let name = match download.get_file_name() { // get filename
        Ok(v) => v,
        Err(DownloadError::DMCAError) => { //now request via lib.. // k if( k == Err(DownloadError::DMCAError) )
            println!("DMCA error!");
            match download.lib_request_video(1,0) {
                Err(err) => { println!("Offliberty-call error {:?}", err); return Err(err); },
                Ok(v) => { dmca = true; v },
            }
        },
        Err(e) => { // unknown error / restricted source etc.. abort
            println!("Unknown error: {:?}", e);
            return Err(e);
        },
    };

    let name_http_valid = lib::format_file_name(&name, &download, &downl_db.qid);

    let file_path = lib::format_file_path(&downl_db.qid, folder.clone(), false);
    file_db.push(file_path.clone());
    let save_path = lib::format_save_path(folder.clone(),&name, &download, &downl_db.qid);

    println!("Filename: {}", name);

    let is_splitted_video = if dmca {
        false
    } else {
        lib::is_split_container(&downl_db.quality)
    };
    let convert_audio = CONFIG.extensions.mp3.contains(&downl_db.quality);

    let total_steps = if dmca {
        if download.is_audio() {
            3
        } else {
            2
        }
    } else if is_splitted_video {
        4
    } else if download.is_audio() {
        3
    } else {
        2
    };

    if !dmca {
        if !downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 2, total_steps,false);
        }

        //download first file, download audio raw source if specified or video
        try!(download.download_file(&file_path, convert_audio));

        if is_splitted_video {
            // download audio file & convert together
            lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 3, total_steps,false);

            let audio_path = lib::format_file_path(&downl_db.qid, folder.clone(), true);
            file_db.push(audio_path.clone());

            println!("Downloading audio.. {}", audio_path);
            try!(download.download_file(&audio_path, true));

            if !downl_db.compress {
                lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 4, total_steps,false);
            }

            match converter.merge_files(&downl_db.qid,&file_path, &audio_path,&save_path, !downl_db.compress) {
                Err(e) => {println!("merge error: {:?}",e); return Err(e);},
                Ok(()) => {},
            }

            try!(remove_file(&audio_path));
            file_db.pop();

        }else{ // we're already done, only need to copy if it's not raw audio source
            if !download.is_audio() {
                try!(lib::move_file(&file_path, &save_path));
            }
        }
    }

    if download.is_audio(){ // if audio-> convert m4a to mp3, which converts directly to downl. dir
        if !downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, total_steps, total_steps, false);
        }
        try!(converter.extract_audio(&file_path, &save_path,convert_audio));
        try!(remove_file(&file_path));
    }else{
        if is_splitted_video {
            try!(remove_file(&file_path));
        }else{
            try!(lib::move_file(&file_path, &save_path));
        }
    }
    file_db.pop();

    if !is_zipped { // add file to list, except it's for zip-compression later (=folder set)
        lib::add_file_entry(&downl_db.pool.clone(), &downl_db.qid,&name_http_valid, &name);
    }
    if !downl_db.compress {
        lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, total_steps, total_steps, true);
    }

    if folder.is_some() {
        Ok(Some(save_path))
    } else {
        Ok(None)
    }
}

///Handles a playlist request
///If zipping isn't requested the downloads will be split up,
///so for each video in the playlist an own query entry will be created
fn handle_playlist(mut downl_db: DownloadDB, converter: &Converter, file_db: &mut Vec<String>) -> Result<Option<String>, DownloadError>{
    let mut max_steps: i32 = if downl_db.compress { 4 } else { 3 };
    lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 1, max_steps,false);

    let pl_id: i64 = downl_db.qid;
    downl_db.update_folder(format!("{}/{}",&CONFIG.general.save_dir,pl_id));
    println!("Folder:  {}",downl_db.folder);

    let db_copy = downl_db.clone();
    let download = Downloader::new(&db_copy, &CONFIG.general);

    let mut playlist_name = String::new();
    if downl_db.compress {
        playlist_name = try!(download.get_playlist_name());
        playlist_name = lib::url_encode(&playlist_name);
        println!("pl name {}",playlist_name);
        try!(std::fs::create_dir(&downl_db.folder));
        file_db.push(downl_db.folder.clone());
    }
    lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 2, max_steps,false);
    println!("retriving playlist videos..");
    let file_ids: Vec<String> = try!(download.get_playlist_ids());

    let handler_folder = if downl_db.compress {
        Some(pl_id.to_string())
    }else {
        None
    };

    println!("got em");
    max_steps += file_ids.len() as i32;
    let mut current_step = 2;
    let mut current_url: String;
    // we'll store all files and delete em later, so we don't need rm -rf
    let mut file_delete_list: Vec<String> = Vec::with_capacity(if downl_db.compress { file_ids.len() } else { 0 });
    for id in file_ids.iter() {
        current_step += 1;
        if downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        }
        downl_db.update_video(format!("https://wwww.youtube.com/watch?v={}",id), current_step as i64);
        println!("id: {}",id);
        let db_copy = downl_db.clone();
        match handle_download(db_copy, &handler_folder, converter, file_db) {
            Err(e) => println!("error downloading {}: {:?}",id,e),
            Ok(e) => {  if downl_db.compress {
                            file_delete_list.push(e.unwrap());
                        }
                },
        }
    }

    println!("downloaded all videos");
    if downl_db.compress { // zip to file, add to db & remove all sources
        current_step += 1;
        lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        let zip_name = format!("{}.zip",playlist_name);
        let zip_file = format!("{}/{}",&CONFIG.general.download_dir,zip_name);
        println!("zip file: {} \n zip source {}",zip_file, &downl_db.folder);
        try!(lib::zip_folder(&downl_db.folder, &zip_file));
        lib::add_file_entry(&downl_db.pool.clone(), &pl_id,&zip_name, &playlist_name);
        current_step += 1;
        lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        try!(lib::delete_files(file_delete_list));
        try!(remove_dir(downl_db.folder));
        file_db.pop();
    }

    Ok(None)
}
<commit_msg>fixed uncased steps update, leading to random false updates of other query entries version up<commit_after>extern crate mysql;
extern crate toml;
extern crate rustc_serialize;
#[macro_use]
extern crate lazy_static;

mod lib;

use lib::config;
use lib::downloader::DownloadDB;
use lib::downloader::Downloader;
use lib::DownloadError;
use lib::converter::Converter;

use std::fs::{remove_file,remove_dir};

static VERSION : &'static str = "0.2"; // String not valid
static SLEEP_MS: u32 = 5000;
static CODE_FAILED: i8 = 3;
static CODE_SUCCESS: i8 = 2;

lazy_static! {
    pub static ref CONFIG: config::Config = {
        println!("Starting yayd-backend v{}",&VERSION);
        config::init_config() //return
    };

}

//#[repr(i8)] broken, enum not usable as of #10292
// enum QueryCodes {
//     Waiting = 0,
//     InProgress = 1,
//     Finished = 2,
//     Failed = 3,
// }

fn main() {

    let pool = lib::db_connect(lib::mysql_options(), SLEEP_MS);

    let converter = Converter::new(&CONFIG.general.ffmpeg_bin,&CONFIG.general.mp3_quality , pool.clone());
    let mut print_pause = true;
    loop {
        if let Some(result) = lib::request_entry(& pool) {
            print_pause = true;
            let qid = result.qid.clone();                 //&QueryCodes::InProgress as i32
            lib::set_query_code(&mut pool.get_conn().unwrap(), &1, &result.qid).ok().expect("Failed to set query code!");
            lib::set_query_state(&pool.clone(),&qid, "started", false);

            let succes;
            {
                let mut left_files: Vec<String> = Vec::with_capacity(2);
                if result.playlist {
                    succes = match handle_playlist(result, &converter,&mut left_files) {
                        Ok(v) => Ok(v),
                        Err(e) => {println!("Playlist Error: {:?}", e); Err(e) }
                    };
                }else{
                    succes = match handle_download(result, &None, &converter,&mut left_files) {
                        Ok(v) => Ok(v),
                        Err(e) => {println!("Download Error: {:?}", e); Err(e) }
                    };
                }

                if !left_files.is_empty() {
                    println!("cleaning up files");
                    for i in &left_files {
                        match remove_file(&i) {
                            Ok(_) => (println!("cleaning up {}",i)),
                            Err(e) => println!("unable to remove file '{}' {}",i,e),
                        }
                    }
                }
            }

            let code: i8 = if succes.is_ok() {
                CODE_SUCCESS//QueryCode
            } else {
                CODE_FAILED//QueryCode
            };
            lib::set_query_code(&mut pool.get_conn().unwrap(), &code,&qid).ok().expect("Failed to set query code!");

            let state = if code == 2 {
                "finished"
            } else {
                "failed"
            };
            lib::set_query_state(&pool.clone(),&qid, state, true);

        } else {
            if print_pause { println!("Pausing.."); print_pause = false; }
            std::thread::sleep_ms(SLEEP_MS);
        }
    }
}

///Download handler
///Used by the playlist/file handler to download one file
///Based on the quality it needs to download audio & video separately and convert them together
///In case of a playlist download it depends on the target download folder & if it should be bezipped
///In case of a DMCA we need to download the file via the socket connector,
///which will output a mp3, or if requested, the video but with the highest quality.
///Thus in case of a DMCA we can't pick a quality anymore.
///Also the filename depends on the socket output then.
///
///If it's a non-zipped single file, it's moved after a successful download, converted etc to the
///main folder from which it should be downloadable.
///The original non-ascii & url_encode'd name of the file is stored in the DB
fn handle_download<'a>(downl_db: DownloadDB, folder: &Option<String>, converter: &Converter, file_db: &mut Vec<String>) -> Result<Option<String>,DownloadError>{
    //update progress
    let is_zipped = match *folder {
        Some(_) => true,
        None => false,
    };
    if !downl_db.compress {
        lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 1, 0,false);
    }

    let download = Downloader::new(&downl_db, &CONFIG.general);
    //get filename, check for DMCA
    let mut dmca = false; // "succ." dmca -> file already downloaded

    let name = match download.get_file_name() { // get filename
        Ok(v) => v,
        Err(DownloadError::DMCAError) => { //now request via lib.. // k if( k == Err(DownloadError::DMCAError) )
            println!("DMCA error!");
            match download.lib_request_video(1,0) {
                Err(err) => { println!("Offliberty-call error {:?}", err); return Err(err); },
                Ok(v) => { dmca = true; v },
            }
        },
        Err(e) => { // unknown error / restricted source etc.. abort
            println!("Unknown error: {:?}", e);
            return Err(e);
        },
    };

    let name_http_valid = lib::format_file_name(&name, &download, &downl_db.qid);

    let file_path = lib::format_file_path(&downl_db.qid, folder.clone(), false);
    file_db.push(file_path.clone());
    let save_path = lib::format_save_path(folder.clone(),&name, &download, &downl_db.qid);

    println!("Filename: {}", name);

    let is_splitted_video = if dmca {
        false
    } else {
        lib::is_split_container(&downl_db.quality)
    };
    let convert_audio = CONFIG.extensions.mp3.contains(&downl_db.quality);

    let total_steps = if dmca {
        if download.is_audio() {
            3
        } else {
            2
        }
    } else if is_splitted_video {
        4
    } else if download.is_audio() {
        3
    } else {
        2
    };

    if !dmca {
        if !downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 2, total_steps,false);
        }

        //download first file, download audio raw source if specified or video
        try!(download.download_file(&file_path, convert_audio));

        if is_splitted_video {
            // download audio file & convert together
			if !downl_db.compress {
                lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 3, total_steps,false);
			}

            let audio_path = lib::format_file_path(&downl_db.qid, folder.clone(), true);
            file_db.push(audio_path.clone());

            println!("Downloading audio.. {}", audio_path);
            try!(download.download_file(&audio_path, true));

            if !downl_db.compress {
                lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 4, total_steps,false);
            }

            match converter.merge_files(&downl_db.qid,&file_path, &audio_path,&save_path, !downl_db.compress) {
                Err(e) => {println!("merge error: {:?}",e); return Err(e);},
                Ok(()) => {},
            }

            try!(remove_file(&audio_path));
            file_db.pop();

        }else{ // we're already done, only need to copy if it's not raw audio source
            if !download.is_audio() {
                try!(lib::move_file(&file_path, &save_path));
            }
        }
    }

    if download.is_audio(){ // if audio-> convert m4a to mp3, which converts directly to downl. dir
        if !downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, total_steps, total_steps, false);
        }
        try!(converter.extract_audio(&file_path, &save_path,convert_audio));
        try!(remove_file(&file_path));
    }else{
        if is_splitted_video {
            try!(remove_file(&file_path));
        }else{
            try!(lib::move_file(&file_path, &save_path));
        }
    }
    file_db.pop();

    if !is_zipped { // add file to list, except it's for zip-compression later (=folder set)
        lib::add_file_entry(&downl_db.pool.clone(), &downl_db.qid,&name_http_valid, &name);
    }
    if !downl_db.compress {
        lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, total_steps, total_steps, true);
    }

    if folder.is_some() {
        Ok(Some(save_path))
    } else {
        Ok(None)
    }
}

///Handles a playlist request
///If zipping isn't requested the downloads will be split up,
///so for each video in the playlist an own query entry will be created
fn handle_playlist(mut downl_db: DownloadDB, converter: &Converter, file_db: &mut Vec<String>) -> Result<Option<String>, DownloadError>{
    let mut max_steps: i32 = if downl_db.compress { 4 } else { 3 };
    lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 1, max_steps,false);

    let pl_id: i64 = downl_db.qid;
    downl_db.update_folder(format!("{}/{}",&CONFIG.general.save_dir,pl_id));
    println!("Folder:  {}",downl_db.folder);

    let db_copy = downl_db.clone();
    let download = Downloader::new(&db_copy, &CONFIG.general);

    let mut playlist_name = String::new();
    if downl_db.compress {
        playlist_name = try!(download.get_playlist_name());
        playlist_name = lib::url_encode(&playlist_name);
        println!("pl name {}",playlist_name);
        try!(std::fs::create_dir(&downl_db.folder));
        file_db.push(downl_db.folder.clone());
    }
    lib::update_steps(&downl_db.pool.clone(),&downl_db.qid, 2, max_steps,false);
    println!("retriving playlist videos..");
    let file_ids: Vec<String> = try!(download.get_playlist_ids());

    let handler_folder = if downl_db.compress {
        Some(pl_id.to_string())
    }else {
        None
    };

    println!("got em");
    max_steps += file_ids.len() as i32;
    let mut current_step = 2;
    let mut current_url: String;
    // we'll store all files and delete em later, so we don't need rm -rf
    let mut file_delete_list: Vec<String> = Vec::with_capacity(if downl_db.compress { file_ids.len() } else { 0 });
    for id in file_ids.iter() {
        current_step += 1;
        if downl_db.compress {
            lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        }
        downl_db.update_video(format!("https://wwww.youtube.com/watch?v={}",id), current_step as i64);
        println!("id: {}",id);
        let db_copy = downl_db.clone();
        match handle_download(db_copy, &handler_folder, converter, file_db) {
            Err(e) => println!("error downloading {}: {:?}",id,e),
            Ok(e) => {  if downl_db.compress {
                            file_delete_list.push(e.unwrap());
                        }
                },
        }
    }

    println!("downloaded all videos");
    if downl_db.compress { // zip to file, add to db & remove all sources
        current_step += 1;
        lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        let zip_name = format!("{}.zip",playlist_name);
        let zip_file = format!("{}/{}",&CONFIG.general.download_dir,zip_name);
        println!("zip file: {} \n zip source {}",zip_file, &downl_db.folder);
        try!(lib::zip_folder(&downl_db.folder, &zip_file));
        lib::add_file_entry(&downl_db.pool.clone(), &pl_id,&zip_name, &playlist_name);
        current_step += 1;
        lib::update_steps(&downl_db.pool.clone(),&pl_id, current_step, max_steps,false);
        try!(lib::delete_files(file_delete_list));
        try!(remove_dir(downl_db.folder));
        file_db.pop();
    }

    Ok(None)
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate peekable_reader;
extern crate getopts;
extern crate tempdir;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter, Write};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;
use std::error::Error;

use getopts::Options;

use tempdir::TempDir;

/** Create an InvalidData io::Error with the description being a
 * formatted string */
macro_rules! io_error {
    ($fmtstr:tt) => { io_error!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData,
                                  format!($fmtstr, $( $args ),* )));
    };
}

/** Alternative to println! that prints to stderr instead of stdout */
macro_rules! printerrln {
    ($fmtstr:tt) => { printerrln!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        writeln!(&mut io::stderr(), $fmtstr, $( $args ),* )
            .expect("Error writing to stderr")
    }
}

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = match opts.parse(&args[1..]) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error parsing options: {:?}", e.description()))
        },
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("{}", env!("CARGO_PKG_HOMEPAGE"));
        return;
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = match matches.opt_str("input") {
        Some(x) => x,
        None => {
            match matches.opts_str(&["edit".to_string(),
                                     "print".to_string(),
                                     "reverse".to_string()]) {

                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    /* Analogous to the input */
    let output = match matches.opt_str("output") {
        Some(x) => x,
        None => {
            match matches.opt_str("edit") {
                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    if matches.opt_present("print") {
        print(&input, &output);
        return;
    }

    if matches.opt_present("reverse") {
        reverse(&input, &output);
        return;
    }

    /* Default to --edit */
    edit(&input, &output);
}

/** When the user wants to edit a specific file in place */
fn edit(input: &str, output: &str) {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        let mut f = io::stdin();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = match TempDir::new("nbted") {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to create temporary directory: {:?}",
                           e.description()))
        },
    };

    let tmp_path = tmpdir.path().join(format!("{}.txt", &input));

    {
        let mut f = match File::create(&tmp_path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to create temporary file: {:?}",
                               e.description()))
            },
        };

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to write temporary file: {:?}",
                               e.description()))
            },
        };

        match f.sync_all() {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to synchronize file: {:?}",
                               e.description()))
            },
        }
    }

    /* Then we open the user's $EDITOR on the temporary file */
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => error("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = match cmd.spawn() {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error opening editor: {:?}", e.description()))
        },
    };

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Err(e) => {
            error(&format!("Error executing editor: {:?}", e.description()))
        },
        _ => error("Editor did not exit correctly"),
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = match File::open(&tmp_path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read temporary file: {:?}.
        Nothing was changed",
                           e.description()))
        },
    };

    let new_nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse edited file: {:?}.
        Nothing was changed",
                           e.description()))
        },
    };

    if nbt == new_nbt {
        printerrln!("No changes, will do nothing.");
        return;
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let mut f = io::stdout();
        write::write_file(&mut f, &new_nbt).expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }

    printerrln!("File edited successfully.");
}

/** When the user wants to print an NBT file to text format */
fn print(input: &str, output: &str) {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let mut f = io::stdin();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let mut f = io::stdout();
        string_write::write_file(&mut f, &nbt)
            .expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }
}

/** When the user wants to convert a text format file into an NBT file */
fn reverse(input: &str, output: &str) {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = match File::open(&path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read text file {}: {:?}",
                           input,
                           e.description()))
        },
    };

    let nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse text file {}: {:?}",
                           input,
                           e.description()))
        },
    };

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let mut f = io::stdout();
        write::write_file(&mut f, &nbt).expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }
}

/** Print the given message and exit with status code 1 */
fn error(message: &str) -> ! {
    printerrln!("Error: {}", message);
    printerrln!("Run with --help for help, or read the manpage.");
    exit(1);
}

fn print_usage(opts: Options) {
    let brief = "Usage: nbted [options] FILE";
    print!("{}", opts.usage(&brief));
    println!("\nFor detailed usage information, read the manpage.");
}
<commit_msg>Fix the breaking of multiline strings<commit_after>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate peekable_reader;
extern crate getopts;
extern crate tempdir;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter, Write};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;
use std::error::Error;

use getopts::Options;

use tempdir::TempDir;

/** Create an InvalidData io::Error with the description being a
 * formatted string */
macro_rules! io_error {
    ($fmtstr:tt) => { io_error!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData,
                                  format!($fmtstr, $( $args ),* )));
    };
}

/** Alternative to println! that prints to stderr instead of stdout */
macro_rules! printerrln {
    ($fmtstr:tt) => { printerrln!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        writeln!(&mut io::stderr(), $fmtstr, $( $args ),* )
            .expect("Error writing to stderr")
    }
}

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = match opts.parse(&args[1..]) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error parsing options: {:?}", e.description()))
        },
    };

    if matches.opt_present("h") {
        print_usage(opts);
        return;
    }

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("{}", env!("CARGO_PKG_HOMEPAGE"));
        return;
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = match matches.opt_str("input") {
        Some(x) => x,
        None => {
            match matches.opts_str(&["edit".to_string(),
                                     "print".to_string(),
                                     "reverse".to_string()]) {

                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    /* Analogous to the input */
    let output = match matches.opt_str("output") {
        Some(x) => x,
        None => {
            match matches.opt_str("edit") {
                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    if matches.opt_present("print") {
        print(&input, &output);
        return;
    }

    if matches.opt_present("reverse") {
        reverse(&input, &output);
        return;
    }

    /* Default to --edit */
    edit(&input, &output);
}

/** When the user wants to edit a specific file in place */
fn edit(input: &str, output: &str) {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        let mut f = io::stdin();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = match TempDir::new("nbted") {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to create temporary directory: {:?}",
                           e.description()))
        },
    };

    let tmp_path = tmpdir.path().join(format!("{}.txt", &input));

    {
        let mut f = match File::create(&tmp_path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to create temporary file: {:?}",
                               e.description()))
            },
        };

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to write temporary file: {:?}",
                               e.description()))
            },
        };

        match f.sync_all() {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to synchronize file: {:?}",
                               e.description()))
            },
        }
    }

    /* Then we open the user's $EDITOR on the temporary file */
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => error("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = match cmd.spawn() {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error opening editor: {:?}", e.description()))
        },
    };

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Err(e) => {
            error(&format!("Error executing editor: {:?}", e.description()))
        },
        _ => error("Editor did not exit correctly"),
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = match File::open(&tmp_path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read temporary file: {:?}.\n\
        Nothing was changed",
                           e.description()))
        },
    };

    let new_nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse edited file: {:?}.\n\
        Nothing was changed",
                           e.description()))
        },
    };

    if nbt == new_nbt {
        printerrln!("No changes, will do nothing.");
        return;
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let mut f = io::stdout();
        write::write_file(&mut f, &new_nbt).expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }

    printerrln!("File edited successfully.");
}

/** When the user wants to print an NBT file to text format */
fn print(input: &str, output: &str) {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let mut f = io::stdin();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                               input))
            },
        }
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let mut f = io::stdout();
        string_write::write_file(&mut f, &nbt)
            .expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }
}

/** When the user wants to convert a text format file into an NBT file */
fn reverse(input: &str, output: &str) {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = match File::open(&path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read text file {}: {:?}",
                           input,
                           e.description()))
        },
    };

    let nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse text file {}: {:?}",
                           input,
                           e.description()))
        },
    };

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let mut f = io::stdout();
        write::write_file(&mut f, &nbt).expect("Error writing to stdout");
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                               output,
                               e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                               output,
                               e.description()))
            },
        }
    }
}

/** Print the given message and exit with status code 1 */
fn error(message: &str) -> ! {
    printerrln!("Error: {}", message);
    printerrln!("Run with --help for help, or read the manpage.");
    exit(1);
}

fn print_usage(opts: Options) {
    let brief = "Usage: nbted [options] FILE";
    print!("{}", opts.usage(&brief));
    println!("\nFor detailed usage information, read the manpage.");
}
<|endoftext|>


<commit_before>extern crate json;
extern crate tiled;

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate specs;
extern crate genmesh;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate image;
extern crate rodio;

mod gfx_app;
mod game;
mod data;
mod critter;
mod graphics;
mod terrain;
mod character;
mod shaders;
mod zombie;

fn main() {
  let mut window = gfx_app::GlutinWindow::new();
  loop {
    match gfx_app::init::run(&mut window) {
      gfx_app::GameStatus::Quit => {
        println!("Game was quit");
        break;
      }
      gfx_app::GameStatus::Render => (),
    }
  }
}
<commit_msg>Remove print on game exit<commit_after>extern crate json;
extern crate tiled;

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate specs;
extern crate genmesh;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate image;
extern crate rodio;

mod gfx_app;
mod game;
mod data;
mod critter;
mod graphics;
mod terrain;
mod character;
mod shaders;
mod zombie;

fn main() {
  let mut window = gfx_app::GlutinWindow::new();
  loop {
    match gfx_app::init::run(&mut window) {
      gfx_app::GameStatus::Quit => break,
      gfx_app::GameStatus::Render => (),
    }
  }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend::{self, Sink, BACKENDS};
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer::{self, Mixer};
use librespot::util::SpotifyId;

use librespot::version;

fn usage(program: &str, opts: &getopts::Options) -> String {
    let brief = format!("Usage: {} [options]", program);
    opts.usage(&brief)
}

fn setup_logging(verbose: bool) {
    let mut builder = LogBuilder::new();
    match env::var("RUST_LOG") {
        Ok(config) => {
            builder.parse(&config);
            builder.init().unwrap();

            if verbose {
                warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
            }
        }
        Err(_) => {
            if verbose {
                builder.parse("mdns=info,librespot=trace");
            } else {
                builder.parse("mdns=error,librespot=warn");
            }
            builder.init().unwrap();
        }
    }
}

fn list_backends() {
    println!("Available Backends : ");
    for (&(name, _), idx) in BACKENDS.iter().zip(0..) {
        if idx == 0 {
            println!("- {} (default)", name);
        } else {
            println!("- {}", name);
        }
    }
}

#[derive(Clone)]
struct Setup {
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,

    mixer: fn() -> Box<Mixer>,

    cache: Option<Cache>,
    config: Config,
    credentials: Option<Credentials>,
    enable_discovery: bool,

    single_track: Option<String>,
    start_position: u32,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optopt("", "single-track", "Play a single track ID and exit.", "ID")
        .optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND")
        .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE")
        .optopt("", "mixer", "Mixer to use", "MIXER");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
            exit(1);
        }
    };

    let verbose = matches.opt_present("verbose");
    setup_logging(verbose);

    info!("librespot {} ({}). Built on {}.",
             version::short_sha(),
             version::commit_date(),
             version::short_now());

    let backend_name = matches.opt_str("backend");
    if backend_name == Some("?".into()) {
        list_backends();
        exit(0);
    }

    let backend = audio_backend::find(backend_name.as_ref())
        .expect("Invalid backend");

    let mixer_name = matches.opt_str("mixer");
    let mixer = mixer::find(mixer_name.as_ref())
        .expect("Invalid mixer");

    let bitrate = matches.opt_str("b").as_ref()
        .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate"))
        .unwrap_or(Bitrate::Bitrate160);

    let name = matches.opt_str("name").unwrap();
    let device_id = librespot::session::device_id(&name);

    let cache = matches.opt_str("c").map(|cache_location| {
        Cache::new(PathBuf::from(cache_location))
    });

    let cached_credentials = cache.as_ref().and_then(Cache::credentials);

    let credentials = get_credentials(matches.opt_str("username"),
                                      matches.opt_str("password"),
                                      cached_credentials);

    let enable_discovery = !matches.opt_present("disable-discovery");

    let start_position = matches.opt_str("start-position")
    	.unwrap_or("0".to_string())
    	.parse().unwrap_or(0);

    let config = Config {
        user_agent: version::version_string(),
        name: name,
        device_id: device_id,
        bitrate: bitrate,
        onstart: matches.opt_str("onstart"),
        onstop: matches.opt_str("onstop"),
    };

    let device = matches.opt_str("device");

    Setup {
        backend: backend,
        cache: cache,
        config: config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        mixer: mixer,

        single_track: matches.opt_str("single-track"),
        start_position: start_position * 1000,
    }
}

struct Main {
    cache: Option<Cache>,
    config: Config,
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

    discovery: Option<DiscoveryStream>,
    signal: IoStream<()>,

    spirc: Option<Spirc>,
    spirc_task: Option<SpircTask>,
    connect: Box<Future<Item=Session, Error=io::Error>>,

    player: Option<Player>,

    single_track: Option<String>,
    start_position: u32,
    single_track_playing: bool,

    shutdown: bool,
}

impl Main {
    fn new(handle: Handle,
           config: Config,
           cache: Option<Cache>,
           backend: fn(Option<String>) -> Box<Sink>,
           device: Option<String>,
           mixer: fn() -> Box<Mixer>,
           single_track: Option<String>,
           start_position: u32,
    ) -> Main
    {
        Main {
            handle: handle.clone(),
            cache: cache,
            config: config,
            backend: backend,
            device: device,
            mixer: mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,

            player: None,
            single_track: single_track,
            start_position: start_position,
            single_track_playing: false,

            shutdown: false,
            signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
        }
    }

    fn discovery(&mut self) {
        let name = self.config.name.clone();
        let device_id = self.config.device_id.clone();
        self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.config.clone();
        let handle = self.handle.clone();

        let connection = Session::connect(config, credentials, self.cache.clone(), handle);

        self.connect = connection;
        self.spirc = None;
        let task = mem::replace(&mut self.spirc_task, None);
        if let Some(task) = task {
            self.handle.spawn(task);
        }
    }
}

impl Future for Main {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            let mut progress = false;

            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }

            if let Async::Ready(session) = self.connect.poll().unwrap() {
                self.connect = Box::new(futures::future::empty());
                let device = self.device.clone();
                let mixer = (self.mixer)();

                let audio_filter = mixer.get_audio_filter();
                let backend = self.backend;
                let player = Player::new(session.clone(), audio_filter, move || {
                    (backend)(device)
                });

                self.player = Some(player.clone());

                let (spirc, spirc_task) = Spirc::new(session, player, mixer);
                self.spirc = Some(spirc);
                self.spirc_task = Some(spirc_task);

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    }
                    self.shutdown = true;
                } else {
                    return Ok(Async::Ready(()));
                }

                progress = true;
            }

            if let Some(ref mut spirc_task) = self.spirc_task {
                if let Async::Ready(()) = spirc_task.poll().unwrap() {
                    if self.shutdown {
                        return Ok(Async::Ready(()));
                    } else {
                        panic!("Spirc shut down unexpectedly");
                    }
                }
            }

            if let Some(ref mut player) = self.player {
				if let Some(ref track_id) = self.single_track {
					if !self.single_track_playing {
						self.single_track_playing = true;

						if let Async::Ready(()) = player.load( SpotifyId::from_base62(
										track_id.replace("spotty://", "")
										.replace("spotify://", "")
										.replace("track:", "")
										.as_str()
									), true, self.start_position ).poll().unwrap() {
										println!("yo!!!");
panic!("yo!");
progress = true;
									}

//						rx.map(|x| exit(0) ).poll();
					}
				}
            }

            if !progress {
                return Ok(Async::NotReady);
            }
        }
    }
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();
    let Setup { backend, config, device, cache, enable_discovery, credentials, mixer, single_track, start_position } = setup(&args);

    let mut task = Main::new(handle, config.clone(), cache, backend, device, mixer, single_track, start_position);
    if enable_discovery {
        task.discovery();
    }
    if let Some(credentials) = credentials {
        task.credentials(credentials);
    }

    core.run(task).unwrap()
}

<commit_msg>Fix the single-track use case. Don't just exit(0), but shot down properly.<commit_after>#[macro_use] extern crate log;
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend::{self, Sink, BACKENDS};
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer::{self, Mixer};
use librespot::util::SpotifyId;

use librespot::version;

fn usage(program: &str, opts: &getopts::Options) -> String {
    let brief = format!("Usage: {} [options]", program);
    opts.usage(&brief)
}

fn setup_logging(verbose: bool) {
    let mut builder = LogBuilder::new();
    match env::var("RUST_LOG") {
        Ok(config) => {
            builder.parse(&config);
            builder.init().unwrap();

            if verbose {
                warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
            }
        }
        Err(_) => {
            if verbose {
                builder.parse("mdns=info,librespot=trace");
            } else {
                builder.parse("mdns=error,librespot=warn");
            }
            builder.init().unwrap();
        }
    }
}

fn list_backends() {
    println!("Available Backends : ");
    for (&(name, _), idx) in BACKENDS.iter().zip(0..) {
        if idx == 0 {
            println!("- {} (default)", name);
        } else {
            println!("- {}", name);
        }
    }
}

#[derive(Clone)]
struct Setup {
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,

    mixer: fn() -> Box<Mixer>,

    cache: Option<Cache>,
    config: Config,
    credentials: Option<Credentials>,
    enable_discovery: bool,

    single_track: Option<String>,
    start_position: u32,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optopt("", "single-track", "Play a single track ID and exit.", "ID")
        .optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND")
        .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE")
        .optopt("", "mixer", "Mixer to use", "MIXER");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
            exit(1);
        }
    };

    let verbose = matches.opt_present("verbose");
    setup_logging(verbose);

    info!("librespot {} ({}). Built on {}.",
             version::short_sha(),
             version::commit_date(),
             version::short_now());

    let backend_name = matches.opt_str("backend");
    if backend_name == Some("?".into()) {
        list_backends();
        exit(0);
    }

    let backend = audio_backend::find(backend_name.as_ref())
        .expect("Invalid backend");

    let mixer_name = matches.opt_str("mixer");
    let mixer = mixer::find(mixer_name.as_ref())
        .expect("Invalid mixer");

    let bitrate = matches.opt_str("b").as_ref()
        .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate"))
        .unwrap_or(Bitrate::Bitrate160);

    let name = matches.opt_str("name").unwrap();
    let device_id = librespot::session::device_id(&name);

    let cache = matches.opt_str("c").map(|cache_location| {
        Cache::new(PathBuf::from(cache_location))
    });

    let cached_credentials = cache.as_ref().and_then(Cache::credentials);

    let credentials = get_credentials(matches.opt_str("username"),
                                      matches.opt_str("password"),
                                      cached_credentials);

    let enable_discovery = !matches.opt_present("disable-discovery");

    let start_position = matches.opt_str("start-position")
    	.unwrap_or("0".to_string())
    	.parse().unwrap_or(0);

    let config = Config {
        user_agent: version::version_string(),
        name: name,
        device_id: device_id,
        bitrate: bitrate,
        onstart: matches.opt_str("onstart"),
        onstop: matches.opt_str("onstop"),
    };

    let device = matches.opt_str("device");

    Setup {
        backend: backend,
        cache: cache,
        config: config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        mixer: mixer,

        single_track: matches.opt_str("single-track"),
        start_position: start_position * 1000,
    }
}

struct Main {
    cache: Option<Cache>,
    config: Config,
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

    discovery: Option<DiscoveryStream>,
    signal: IoStream<()>,

    spirc: Option<Spirc>,
    spirc_task: Option<SpircTask>,
    connect: Box<Future<Item=Session, Error=io::Error>>,

    player: Option<Player>,

    single_track: Option<String>,
    start_position: u32,
    single_track_playing: Option<futures::sync::oneshot::Receiver<()>>,

    shutdown: bool,
}

impl Main {
    fn new(handle: Handle,
           config: Config,
           cache: Option<Cache>,
           backend: fn(Option<String>) -> Box<Sink>,
           device: Option<String>,
           mixer: fn() -> Box<Mixer>,
           single_track: Option<String>,
           start_position: u32,
    ) -> Main
    {
        Main {
            handle: handle.clone(),
            cache: cache,
            config: config,
            backend: backend,
            device: device,
            mixer: mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,

            player: None,
            single_track: single_track,
            start_position: start_position,
            single_track_playing: None,

            shutdown: false,
            signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
        }
    }

    fn discovery(&mut self) {
        let name = self.config.name.clone();
        let device_id = self.config.device_id.clone();
        self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.config.clone();
        let handle = self.handle.clone();

        let connection = Session::connect(config, credentials, self.cache.clone(), handle);

        self.connect = connection;
        self.spirc = None;
        let task = mem::replace(&mut self.spirc_task, None);
        if let Some(task) = task {
            self.handle.spawn(task);
        }
    }
}

impl Future for Main {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            let mut progress = false;

            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }

            if let Async::Ready(session) = self.connect.poll().unwrap() {
                self.connect = Box::new(futures::future::empty());
                let device = self.device.clone();
                let mixer = (self.mixer)();

                let audio_filter = mixer.get_audio_filter();
                let backend = self.backend;
                let player = Player::new(session.clone(), audio_filter, move || {
                    (backend)(device)
                });

                self.player = Some(player.clone());

                let (spirc, spirc_task) = Spirc::new(session, player, mixer);
                self.spirc = Some(spirc);
                self.spirc_task = Some(spirc_task);

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    }
                    self.shutdown = true;
                } else {
                    return Ok(Async::Ready(()));
                }

                progress = true;
            }

            if let Some(ref mut spirc_task) = self.spirc_task {
                if let Async::Ready(()) = spirc_task.poll().unwrap() {
                    if self.shutdown {
                        return Ok(Async::Ready(()));
                    } else {
                        panic!("Spirc shut down unexpectedly");
                    }
                }
            }

            if let Some(ref mut player) = self.player {
				if let Some(ref track_id) = self.single_track {
					if self.single_track_playing.is_none() {
						self.single_track_playing = Some(player.load( SpotifyId::from_base62(
							track_id.replace("spotty://", "")
							.replace("spotify://", "")
							.replace("track:", "")
							.as_str()
						), true, self.start_position ));

						self.single_track_playing.poll().unwrap();
						progress = true;
					}
					else {
						let result = self.single_track_playing.poll();

						if result.is_err() {
							if !self.shutdown {
								if let Some(ref spirc) = self.spirc {
									spirc.shutdown();
								}
								self.shutdown = true;
							} else {
								return Ok(Async::Ready(()));
							}

							progress = true;
						}
						else {
							if let Async::Ready(Some(())) = result.unwrap() {
								progress = true;
							}
						}
					}
				}
            }

            if !progress {
                return Ok(Async::NotReady);
            }
        }
    }
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();
    let Setup { backend, config, device, cache, enable_discovery, credentials, mixer, single_track, start_position } = setup(&args);

    let mut task = Main::new(handle, config.clone(), cache, backend, device, mixer, single_track, start_position);
    if enable_discovery {
        task.discovery();
    }
    if let Some(credentials) = credentials {
        task.credentials(credentials);
    }

    core.run(task).unwrap()
}

<|endoftext|>


<commit_before>// Copyright 2012-2014 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.

use core::num::NonZeroU32;
use core::option::Option;
use core::option::Option::{Some, None};
use std::mem::size_of;

#[test]
fn test_create_nonzero_instance() {
    let _a = unsafe {
        NonZeroU32::new_unchecked(21)
    };
}

#[test]
fn test_size_nonzero_in_option() {
    assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
}

#[test]
fn test_match_on_nonzero_option() {
    let a = Some(unsafe {
        NonZeroU32::new_unchecked(42)
    });
    match a {
        Some(val) => assert_eq!(val.get(), 42),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
    }

    match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
        Some(val) => assert_eq!(val.get(), 43),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
    }
}

#[test]
fn test_match_option_empty_vec() {
    let a: Option<Vec<isize>> = Some(vec![]);
    match a {
        None => panic!("unexpected None while matching on Some(vec![])"),
        _ => {}
    }
}

#[test]
fn test_match_option_vec() {
    let a = Some(vec![1, 2, 3, 4]);
    match a {
        Some(v) => assert_eq!(v, [1, 2, 3, 4]),
        None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])")
    }
}

#[test]
fn test_match_option_rc() {
    use std::rc::Rc;

    let five = Rc::new(5);
    match Some(five) {
        Some(r) => assert_eq!(*r, 5),
        None => panic!("unexpected None while matching on Some(Rc::new(5))")
    }
}

#[test]
fn test_match_option_arc() {
    use std::sync::Arc;

    let five = Arc::new(5);
    match Some(five) {
        Some(a) => assert_eq!(*a, 5),
        None => panic!("unexpected None while matching on Some(Arc::new(5))")
    }
}

#[test]
fn test_match_option_empty_string() {
    let a = Some(String::new());
    match a {
        None => panic!("unexpected None while matching on Some(String::new())"),
        _ => {}
    }
}

#[test]
fn test_match_option_string() {
    let five = "Five".to_string();
    match Some(five) {
        Some(s) => assert_eq!(s, "Five"),
        None => panic!("unexpected None while matching on Some(String { ... })")
    }
}
<commit_msg>Test NonZero in a const item in a pattern.<commit_after>// Copyright 2012-2014 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.

use core::num::NonZeroU32;
use core::option::Option;
use core::option::Option::{Some, None};
use std::mem::size_of;

#[test]
fn test_create_nonzero_instance() {
    let _a = unsafe {
        NonZeroU32::new_unchecked(21)
    };
}

#[test]
fn test_size_nonzero_in_option() {
    assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
}

#[test]
fn test_match_on_nonzero_option() {
    let a = Some(unsafe {
        NonZeroU32::new_unchecked(42)
    });
    match a {
        Some(val) => assert_eq!(val.get(), 42),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
    }

    match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
        Some(val) => assert_eq!(val.get(), 43),
        None => panic!("unexpected None while matching on Some(NonZeroU32(_))")
    }
}

#[test]
fn test_match_option_empty_vec() {
    let a: Option<Vec<isize>> = Some(vec![]);
    match a {
        None => panic!("unexpected None while matching on Some(vec![])"),
        _ => {}
    }
}

#[test]
fn test_match_option_vec() {
    let a = Some(vec![1, 2, 3, 4]);
    match a {
        Some(v) => assert_eq!(v, [1, 2, 3, 4]),
        None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])")
    }
}

#[test]
fn test_match_option_rc() {
    use std::rc::Rc;

    let five = Rc::new(5);
    match Some(five) {
        Some(r) => assert_eq!(*r, 5),
        None => panic!("unexpected None while matching on Some(Rc::new(5))")
    }
}

#[test]
fn test_match_option_arc() {
    use std::sync::Arc;

    let five = Arc::new(5);
    match Some(five) {
        Some(a) => assert_eq!(*a, 5),
        None => panic!("unexpected None while matching on Some(Arc::new(5))")
    }
}

#[test]
fn test_match_option_empty_string() {
    let a = Some(String::new());
    match a {
        None => panic!("unexpected None while matching on Some(String::new())"),
        _ => {}
    }
}

#[test]
fn test_match_option_string() {
    let five = "Five".to_string();
    match Some(five) {
        Some(s) => assert_eq!(s, "Five"),
        None => panic!("unexpected None while matching on Some(String { ... })")
    }
}

mod atom {
    use core::num::NonZeroU32;

    #[derive(PartialEq, Eq)]
    pub struct Atom {
        index: NonZeroU32, // private
    }
    pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } };
}

macro_rules! atom {
    ("foo") => { atom::FOO_ATOM }
}

#[test]
fn test_match_nonzero_const_pattern() {
    match atom!("foo") {
        // Using as a pattern is supported by the compiler:
        atom!("foo") => {}
        _ => panic!("Expected the const item as a pattern to match.")
    }
}
<|endoftext|>


<commit_before>use num::Num;
use set::identity;

#[inline(always)]
pub fn inverse<T: Num>(out: &mut [T; 4], a: [T; 4]) -> &mut [T; 4] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];

    let d = m11 * m22 - m12 * m21;
    if d != T::zero() {
        let inv_d = T::one() / d;

        out[0] = m22 * inv_d;
        out[1] = -m12 * inv_d;
        out[2] = -m21 * inv_d;
        out[3] = m11 * inv_d;
        out
    } else {
        identity(out)
    }
}
#[test]
fn test_inverse() {
    let mut v = [0, 0, 0, 0];
    inverse(&mut v, [1, 0, 0, 1]);
    assert!(v == [1, 0, 0, 1]);
}

#[inline(always)]
pub fn determinant<T: Num>(out: [T; 4]) -> T {
    out[0] * out[3] - out[2] * out[1]
}
#[test]
fn test_determinant() {
    assert_eq!(determinant([1, 0, 0, 1]), 1);
}

#[inline(always)]
pub fn transpose<T: Num>(out: &mut [T; 4], a: [T; 4]) -> &mut [T; 4] {
    if *out == a {
        let tmp = a[1];
        out[1] = a[2];
        out[2] = tmp;
    } else {
        out[0] = a[0];
        out[1] = a[2];
        out[2] = a[1];
        out[3] = a[3];
    }

    out
}
#[test]
fn test_transpose() {
    let mut v = [0, 0, 0, 0];
    transpose(&mut v, [1, 0, 0, 1]);
    assert_eq!(v, [1, 0, 0, 1]);
}
<commit_msg>updates<commit_after>use num::Num;
use set::identity;

#[inline(always)]
pub fn inverse<T: Num>(out: &mut [T; 4], a: [T; 4]) -> &mut [T; 4] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];

    let d = m11 * m22 - m12 * m21;
    if d != T::zero() {
        let inv_d = T::one() / d;

        out[0] = m22 * inv_d;
        out[1] = -m12 * inv_d;
        out[2] = -m21 * inv_d;
        out[3] = m11 * inv_d;
        out
    } else {
        identity(out)
    }
}
#[test]
fn test_inverse() {
    let mut v = [0, 0, 0, 0];
    inverse(&mut v, [1, 0, 0, 1]);
    assert!(v == [1, 0, 0, 1]);
}

#[inline(always)]
pub fn determinant<T: Num>(out: [T; 4]) -> T {
    out[0] * out[3] - out[2] * out[1]
}
#[test]
fn test_determinant() {
    assert_eq!(determinant([1, 0, 0, 1]), 1);
}

#[inline(always)]
pub fn transpose<T: Num>(out: &mut [T; 4], a: [T; 4]) -> &mut [T; 4] {
    out[0] = a[0];
    out[1] = a[2];
    out[2] = a[1];
    out[3] = a[3];
    out
}
#[test]
fn test_transpose() {
    let mut v = [0, 0, 0, 0];
    transpose(&mut v, [1, 0, 0, 1]);
    assert_eq!(v, [1, 0, 0, 1]);
}
<|endoftext|>


<commit_before><commit_msg>Update hammer.rs to be compatible with the current rust master<commit_after><|endoftext|>


<commit_before>
use super::raw_vec::RawVec;
use super::plan::Plan;
use super::enums::*;
use super::r2r::*;

use num_complex::Complex64 as c64;
use std::ops::Mul;

pub struct Pair<A, B> {
    pub field: RawVec<A>,
    pub coef: RawVec<B>,
    logical_size: usize,
    forward: Plan<A, B>,
    backward: Plan<B, A>,
}

impl<A, B> Pair<A, B> {
    pub fn logical_size(&self) -> usize { self.logical_size }

    pub fn forward(&mut self) {
        unsafe {
            self.forward.execute();
        }
    }

    pub fn backward(&mut self) {
        unsafe {
            self.backward.execute();
        }
    }

    pub fn normalize_field_by(&mut self, factor: f64)
        where A: Mul<f64, Output = A> + Copy
    {
        for val in self.field.iter_mut() {
            *val = *val * factor;
        }
    }

    pub fn normalize_coef_by(&mut self, factor: f64)
        where B: Mul<f64, Output = B> + Copy
    {
        for val in self.coef.iter_mut() {
            *val = *val * factor;
        }
    }
}

impl Pair<f32, f32> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::<f32>::new(n);
        let mut coef = RawVec::<f32>::new(n);
        let forward = Plan::<f32, f32>::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::<f32, f32>::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<f64, f64> {
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<f64>::new(n);
        let forward = Plan::<f64, f64>::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::<f64, f64>::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<f64, c64> {
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let mut field = RawVec::<f64>::new(n);
        let mut coef = RawVec::<c64>::new(n / 2 + 1);
        let forward = Plan::r2c_1d(n, &mut field, &mut coef, flag);
        let backward = Plan::c2r_1d(n, &mut coef, &mut field, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}

impl Pair<c64, c64> {
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let mut field = RawVec::<c64>::new(n);
        let mut coef = RawVec::<c64>::new(n);
        let forward = Plan::c2c_1d(n, &mut field, &mut coef, sign, flag);
        let backward = Plan::c2c_1d(n, &mut coef, &mut field, -sign, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}
<commit_msg>Rewrite Pair in generic way<commit_after>
use super::raw_vec::*;
use super::plan::*;
use super::enums::*;
use super::r2r::*;

use num_traits::Zero;
use std::ops::Mul;

pub struct Pair<A, B> {
    pub field: RawVec<A>,
    pub coef: RawVec<B>,
    logical_size: usize,
    forward: Plan<A, B>,
    backward: Plan<B, A>,
}

impl<A, B> Pair<A, B> {
    pub fn logical_size(&self) -> usize { self.logical_size }

    pub fn forward(&mut self) {
        unsafe {
            self.forward.execute();
        }
    }

    pub fn backward(&mut self) {
        unsafe {
            self.backward.execute();
        }
    }

    pub fn normalize_field_by(&mut self, factor: f64)
        where A: Mul<f64, Output = A> + Copy
    {
        for val in self.field.iter_mut() {
            *val = *val * factor;
        }
    }

    pub fn normalize_coef_by(&mut self, factor: f64)
        where B: Mul<f64, Output = B> + Copy
    {
        for val in self.coef.iter_mut() {
            *val = *val * factor;
        }
    }
}

impl<R> Pair<R, R>
    where R: R2RPlanCreate + AlignedAllocable + Zero
{
    pub fn r2r_1d(n: usize, kind: R2R_KIND, flag: FLAG) -> Self {
        let mut field = RawVec::new(n);
        let mut coef = RawVec::new(n);
        let forward = Plan::r2r_1d(n, &mut field, &mut coef, forward(kind), flag);
        let backward = Plan::r2r_1d(n, &mut coef, &mut field, backward(kind), flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: logical_size(n, kind),
            forward: forward,
            backward: backward,
        }
    }
}

impl<C> Pair<C, C>
    where C: C2CPlanCreate + AlignedAllocable + Zero
{
    pub fn c2c_1d(n: usize, sign: SIGN, flag: FLAG) -> Self {
        let mut field = RawVec::new(n);
        let mut coef = RawVec::new(n);
        let forward = Plan::c2c_1d(n, &mut field, &mut coef, sign, flag);
        let backward = Plan::c2c_1d(n, &mut coef, &mut field, -sign, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}

impl<R, C> Pair<R, C>
    where (C, R): C2RPlanCreate<Real = R, Complex = C>,
          R: AlignedAllocable + Zero,
          C: AlignedAllocable + Zero
{
    pub fn r2c_1d(n: usize, flag: FLAG) -> Self {
        let mut field = RawVec::<R>::new(n);
        let mut coef = RawVec::<C>::new(n / 2 + 1);
        let forward = Plan::r2c_1d(n, &mut field, &mut coef, flag);
        let backward = Plan::c2r_1d(n, &mut coef, &mut field, flag);
        Pair {
            field: field,
            coef: coef,
            logical_size: n,
            forward: forward,
            backward: backward,
        }
    }
}
<|endoftext|>