<commit_before>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(50) };
    let bike_two = Coordinates { x: Cell::new(100), y: Cell::new(50) };
    let mut one_pos = vec![];
    let mut two_pos = vec![];
    let mut all_pos = vec![];

    move_up(&bike_one.y);
    move_up(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_down(&bike_one.y);
    move_down(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_right(&bike_one.x);
    move_left(&bike_two.x);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_left(&bike_one.x);
    move_left(&bike_two.x);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    println!("Bike One");
    println!("X is {:?}, Y is {:?}", bike_one.x, bike_one.y);
    println!("{:?}", one_pos);

    println!("Bike Two");
    println!("X is {:?}, Y is {:?}", bike_two.x, bike_two.y);
    println!("{:?}", two_pos);

    println!("Final combined positions are: {:?}", all_pos)

}

fn add_positions<'a>(v_cc: &'a mut Vec<i32>, y: &Cell<i32>, x: &Cell<i32>) -> &'a mut Vec<i32> {
    v_cc.push(x.get());
    v_cc.push(y.get());
    v_cc
}

fn combined_positions<'a>(a_p: &'a mut Vec<i32>, o_p: &mut Vec<i32>, t_p: &mut Vec<i32>) -> &'a mut Vec<i32> {
    a_p.extend_from_slice(o_p);
    a_p.extend_from_slice(t_p);
    a_p
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    y_cord.set(y_cord.get() + 1);
    y_cord
}

fn move_down(y_cord: &Cell<i32>) -> &Cell<i32> {
    y_cord.set(y_cord.get() - 1);
    y_cord
}

fn move_right(x_cord: &Cell<i32>) -> &Cell<i32> {
    x_cord.set(x_cord.get() + 1);
    x_cord
}

fn move_left(x_cord: &Cell<i32>) -> &Cell<i32> {
    x_cord.set(x_cord.get() - 1);
    x_cord
}

#[test]
fn it_can_move() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(0) };
    let mut one_pos = vec![];

    // test it starts at 0

    assert_eq!(0, bike_one.y.get());

    // test it can move up one and can add positions to the vector

    move_up(&bike_one.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);

    assert_eq!(1, bike_one.y.get());
    assert_eq!(0, one_pos[0]);
    assert_eq!(1, one_pos[1]);

    // test it can continue to move up and theat move logic is valid

    move_up(&bike_one.y);
    move_up(&bike_one.y);
    move_up(&bike_one.y);

    assert_eq!(4, bike_one.y.get());

    for _ in 0..19 { // _ instead of x so that rust does not complain about x not being used
        move_up(&bike_one.y); // moves up 19 times
    }

    assert_eq!(23, bike_one.y.get());

    // test it can move down

    for _ in 0..19 {
        move_down(&bike_one.y);
    }

    assert_eq!(4, bike_one.y.get());

    // test it can move right

    for _ in 0..19 {
        move_right(&bike_one.x);
    }

    assert_eq!(19, bike_one.x.get());

    // test it can move left

    for _ in 0..10 {
        move_left(&bike_one.x);
    }

    assert_eq!(9, bike_one.x.get());
}

#[test]
fn it_can_log_all_positions() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(50) };
    let bike_two = Coordinates { x: Cell::new(100), y: Cell::new(50) };
    let mut one_pos = vec![];
    let mut two_pos = vec![];
    let mut all_pos = vec![];

    move_up(&bike_one.y);
    move_up(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);

    assert_eq!(51, bike_one.x.get() + bike_one.y.get());

    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);

    assert_eq!(51, bike_one.x.get() + bike_one.y.get());

    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    let sum = all_pos.iter()
           .fold(0, |acc, &x| acc + x);

    assert_eq!(202, sum);
}
<commit_msg>proper test for second bike<commit_after>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(50) };
    let bike_two = Coordinates { x: Cell::new(100), y: Cell::new(50) };
    let mut one_pos = vec![];
    let mut two_pos = vec![];
    let mut all_pos = vec![];

    move_up(&bike_one.y);
    move_up(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_down(&bike_one.y);
    move_down(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_right(&bike_one.x);
    move_left(&bike_two.x);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    move_left(&bike_one.x);
    move_left(&bike_two.x);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);
    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);
    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    println!("Bike One");
    println!("X is {:?}, Y is {:?}", bike_one.x, bike_one.y);
    println!("{:?}", one_pos);

    println!("Bike Two");
    println!("X is {:?}, Y is {:?}", bike_two.x, bike_two.y);
    println!("{:?}", two_pos);

    println!("Final combined positions are: {:?}", all_pos)

}

fn add_positions<'a>(v_cc: &'a mut Vec<i32>, y: &Cell<i32>, x: &Cell<i32>) -> &'a mut Vec<i32> {
    v_cc.push(x.get());
    v_cc.push(y.get());
    v_cc
}

fn combined_positions<'a>(a_p: &'a mut Vec<i32>, o_p: &mut Vec<i32>, t_p: &mut Vec<i32>) -> &'a mut Vec<i32> {
    a_p.extend_from_slice(o_p);
    a_p.extend_from_slice(t_p);
    a_p
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    y_cord.set(y_cord.get() + 1);
    y_cord
}

fn move_down(y_cord: &Cell<i32>) -> &Cell<i32> {
    y_cord.set(y_cord.get() - 1);
    y_cord
}

fn move_right(x_cord: &Cell<i32>) -> &Cell<i32> {
    x_cord.set(x_cord.get() + 1);
    x_cord
}

fn move_left(x_cord: &Cell<i32>) -> &Cell<i32> {
    x_cord.set(x_cord.get() - 1);
    x_cord
}

#[test]
fn it_can_move() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(0) };
    let mut one_pos = vec![];

    // test it starts at 0

    assert_eq!(0, bike_one.y.get());

    // test it can move up one and can add positions to the vector

    move_up(&bike_one.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);

    assert_eq!(1, bike_one.y.get());
    assert_eq!(0, one_pos[0]);
    assert_eq!(1, one_pos[1]);

    // test it can continue to move up and theat move logic is valid

    move_up(&bike_one.y);
    move_up(&bike_one.y);
    move_up(&bike_one.y);

    assert_eq!(4, bike_one.y.get());

    for _ in 0..19 { // _ instead of x so that rust does not complain about x not being used
        move_up(&bike_one.y); // moves up 19 times
    }

    assert_eq!(23, bike_one.y.get());

    // test it can move down

    for _ in 0..19 {
        move_down(&bike_one.y);
    }

    assert_eq!(4, bike_one.y.get());

    // test it can move right

    for _ in 0..19 {
        move_right(&bike_one.x);
    }

    assert_eq!(19, bike_one.x.get());

    // test it can move left

    for _ in 0..10 {
        move_left(&bike_one.x);
    }

    assert_eq!(9, bike_one.x.get());
}

#[test]
fn it_can_log_all_positions() {
    let bike_one = Coordinates { x: Cell::new(0), y: Cell::new(50) };
    let bike_two = Coordinates { x: Cell::new(100), y: Cell::new(50) };
    let mut one_pos = vec![];
    let mut two_pos = vec![];
    let mut all_pos = vec![];

    move_up(&bike_one.y);
    move_up(&bike_two.y);
    add_positions(&mut one_pos, &bike_one.y, &bike_one.x);

    assert_eq!(51, bike_one.x.get() + bike_one.y.get());

    add_positions(&mut two_pos, &bike_two.y, &bike_two.x);

    assert_eq!(151, bike_two.x.get() + bike_two.y.get());

    combined_positions(&mut all_pos, &mut one_pos, &mut two_pos);

    let sum = all_pos.iter()
           .fold(0, |acc, &x| acc + x);

    assert_eq!(202, sum);
}
<|endoftext|>


<commit_before>use result::NSSResult;
use ffi::nspr;
use ffi::nspr::PRBool;
use libc::{c_uint, c_uchar};
use std::{mem, ptr};
use std::kinds::marker::ContravariantLifetime;

#[must_use]
#[repr(C)]
#[allow(dead_code)] // List all available options
pub enum SECStatus
{
    WouldBlock = -2,
    Failure = -1,
    Success = 0
}

impl SECStatus
{
    pub fn to_result(&self) -> ::result::NSSResult<()>
    {
        match *self
        {
            SECStatus::Success => Ok(()),
            SECStatus::Failure => Err(nspr::get_error_code()),
            SECStatus::WouldBlock => panic!("Unexpectedly got SECWouldBlock"),
        }
    }
}

#[repr(C)]
#[allow(dead_code)] // We just list all available in NSS
enum SECItemType
{
    Buffer = 0,
    ClearDataBuffer = 1,
    CipherDataBuffer = 2,
    DERCertBuffer = 3,
    EncodedCertBuffer = 4,
    DERNameBuffer = 5,
    EncodedNameBuffer = 6,
    AsciiNameString = 7,
    AsciiString = 8,
    DEROID = 9,
    UnsignedInteger = 10,
    UTCTime = 11,
    GeneralizedTime = 12,
    VisibleString = 13,
    UTF8String = 14,
    BMPString = 15,
}

#[repr(C)]
pub struct SECItemFFI
{
    typ: SECItemType,
    data: *const c_uchar,
    len: c_uint,
}

pub enum SECItem<'a>
{
    Boxed(*mut SECItemFFI),
    Data(SECItemFFI, ContravariantLifetime<'a>)
}

impl SECItem<'static>
{
    pub fn wrap(data: *mut SECItemFFI) -> NSSResult<SECItem<'static>>
    {
        match data.is_null()
        {
            true => Err(nspr::get_error_code()),
            false => Ok(SECItem::Boxed(data)),
        }
    }

    pub fn empty() -> SECItem<'static>
    {
        SECItem::Data(SECItemFFI {
            typ: SECItemType::Buffer,
            data: ptr::null(),
            len: 0,
        }, ContravariantLifetime)
    }
}

impl<'a> SECItem<'a>
{
    pub fn from_buf(buffer: &'a [u8]) -> SECItem<'a>
    {
        let si = SECItemFFI
        {
            typ: SECItemType::Buffer,
            data: buffer.as_ptr(),
            len: buffer.len() as c_uint,
        };
        SECItem::Data(si, ContravariantLifetime)
    }

    pub fn from_struct<T>(data: &'a T) -> SECItem<'a>
    {
        let len = mem::size_of::<T>() as c_uint;
        let ptr = match len
        {
            0 => ptr::null(),
            _ => unsafe { mem::transmute(data) },
        };
        let si = SECItemFFI
        {
            typ: SECItemType::Buffer,
            data: ptr,
            len: len,
        };
        SECItem::Data(si, ContravariantLifetime)
    }

    pub fn get<'b>(&'b self) -> &'b SECItemFFI
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { ptr.as_ref().unwrap() },
            SECItem::Data(ref si, _) => si,
        }
    }

    pub fn get_mut<'b>(&'b mut self) -> &'b mut SECItemFFI
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { ptr.as_mut().unwrap() },
            SECItem::Data(ref mut si, _) => si,
        }
    }

    pub fn copy_buf(&self) -> Vec<u8>
    {
        let si = self.get();
        let buf : &[u8] = unsafe { mem::transmute(::std::raw::Slice { data: si.data, len: si.len as usize, }) };
        buf.to_vec()
    }
}

#[unsafe_destructor]
impl<'a> Drop for SECItem<'a>
{
    fn drop(&mut self)
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { SECITEM_FreeItem(ptr, PRBool::True) },
            _ => {},
        }
    }
}

#[link(name="nss3")]
extern "C"
{
    fn SECITEM_FreeItem(item: *mut SECItemFFI, freeitem: PRBool);
}
<commit_msg>kinds::marker -> marker<commit_after>use result::NSSResult;
use ffi::nspr;
use ffi::nspr::PRBool;
use libc::{c_uint, c_uchar};
use std::{mem, ptr};
use std::marker::ContravariantLifetime;

#[must_use]
#[repr(C)]
#[allow(dead_code)] // List all available options
pub enum SECStatus
{
    WouldBlock = -2,
    Failure = -1,
    Success = 0
}

impl SECStatus
{
    pub fn to_result(&self) -> ::result::NSSResult<()>
    {
        match *self
        {
            SECStatus::Success => Ok(()),
            SECStatus::Failure => Err(nspr::get_error_code()),
            SECStatus::WouldBlock => panic!("Unexpectedly got SECWouldBlock"),
        }
    }
}

#[repr(C)]
#[allow(dead_code)] // We just list all available in NSS
enum SECItemType
{
    Buffer = 0,
    ClearDataBuffer = 1,
    CipherDataBuffer = 2,
    DERCertBuffer = 3,
    EncodedCertBuffer = 4,
    DERNameBuffer = 5,
    EncodedNameBuffer = 6,
    AsciiNameString = 7,
    AsciiString = 8,
    DEROID = 9,
    UnsignedInteger = 10,
    UTCTime = 11,
    GeneralizedTime = 12,
    VisibleString = 13,
    UTF8String = 14,
    BMPString = 15,
}

#[repr(C)]
pub struct SECItemFFI
{
    typ: SECItemType,
    data: *const c_uchar,
    len: c_uint,
}

pub enum SECItem<'a>
{
    Boxed(*mut SECItemFFI),
    Data(SECItemFFI, ContravariantLifetime<'a>)
}

impl SECItem<'static>
{
    pub fn wrap(data: *mut SECItemFFI) -> NSSResult<SECItem<'static>>
    {
        match data.is_null()
        {
            true => Err(nspr::get_error_code()),
            false => Ok(SECItem::Boxed(data)),
        }
    }

    pub fn empty() -> SECItem<'static>
    {
        SECItem::Data(SECItemFFI {
            typ: SECItemType::Buffer,
            data: ptr::null(),
            len: 0,
        }, ContravariantLifetime)
    }
}

impl<'a> SECItem<'a>
{
    pub fn from_buf(buffer: &'a [u8]) -> SECItem<'a>
    {
        let si = SECItemFFI
        {
            typ: SECItemType::Buffer,
            data: buffer.as_ptr(),
            len: buffer.len() as c_uint,
        };
        SECItem::Data(si, ContravariantLifetime)
    }

    pub fn from_struct<T>(data: &'a T) -> SECItem<'a>
    {
        let len = mem::size_of::<T>() as c_uint;
        let ptr = match len
        {
            0 => ptr::null(),
            _ => unsafe { mem::transmute(data) },
        };
        let si = SECItemFFI
        {
            typ: SECItemType::Buffer,
            data: ptr,
            len: len,
        };
        SECItem::Data(si, ContravariantLifetime)
    }

    pub fn get<'b>(&'b self) -> &'b SECItemFFI
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { ptr.as_ref().unwrap() },
            SECItem::Data(ref si, _) => si,
        }
    }

    pub fn get_mut<'b>(&'b mut self) -> &'b mut SECItemFFI
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { ptr.as_mut().unwrap() },
            SECItem::Data(ref mut si, _) => si,
        }
    }

    pub fn copy_buf(&self) -> Vec<u8>
    {
        let si = self.get();
        let buf : &[u8] = unsafe { mem::transmute(::std::raw::Slice { data: si.data, len: si.len as usize, }) };
        buf.to_vec()
    }
}

#[unsafe_destructor]
impl<'a> Drop for SECItem<'a>
{
    fn drop(&mut self)
    {
        match *self
        {
            SECItem::Boxed(ptr) => unsafe { SECITEM_FreeItem(ptr, PRBool::True) },
            _ => {},
        }
    }
}

#[link(name="nss3")]
extern "C"
{
    fn SECITEM_FreeItem(item: *mut SECItemFFI, freeitem: PRBool);
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate ansi_term;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    servers.sort_by(|a, b| b.players.cmp(&a.players));

    // TODO: Error handling
    let cols = Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output().unwrap();
    let cols = String::from_utf8(cols.stdout).unwrap();
    let cols: usize = cols.split_whitespace().last().unwrap().parse().unwrap();

    println!("{}", cols);

    for server in servers {
        if server.players == 0 {
            break;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }
}
<commit_msg>Don't crash if the stty command is not available<commit_after>extern crate hyper;
extern crate ansi_term;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    servers.sort_by(|a, b| b.players.cmp(&a.players));

    let cols:usize = match Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output() {
        Ok(out) => String::from_utf8(out.stdout).unwrap().split_whitespace().last().unwrap().parse().unwrap(),
        Err(_) => 80,
    };

    println!("{}", cols);

    for server in servers {
        if server.players == 0 {
            break;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate iron;
#[macro_use] extern crate router;
extern crate mount;
extern crate staticfile;
extern crate handlebars_iron as hbs;
extern crate pulldown_cmark as cmark;

use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status;
use mount::Mount;
use staticfile::Static;
use hbs::{Template, HandlebarsEngine, DirectorySource};

/// Entry point
fn main() {
    //
    // Configs
    //
    let addr = "localhost:8000";

    // Routes & Mounts
    let mut chain = Chain::new(router! {
        get "/" => index,
        get "/pages/:name" => page,
    });

    //
    // 이 뒤는 더럽습니다
    // Reference: https://namu.wiki/w/%EC%96%B4%EC%9D%B4%20%EA%B7%B8%20%EC%95%9E%EC%9D%80%20%EC%A7%80%EC%98%A5%EC%9D%B4%EB%8B%A4
    //

    // Compile templates
    let mut hbse = HandlebarsEngine::new();
    hbse.add(Box::new(DirectorySource::new("templates", ".hbs")));
    // load templates from all registered sources
    if let Err(r) = hbse.reload() {
        use std::error::Error;
        panic!("{}", r.description());
    }
    // Register handlebar middleware
    chain.link_after(hbse);

    // Mount '/static/' path to the filesystem
    let mut mount = Mount::new();
    mount
        .mount("/", chain)
        .mount("/static/", Static::new("static/"));

    // Fire & Forget
    println!("\nServer running at \x1b[33mhttp://{}\x1b[0m\n", addr);
    Iron::new(mount).http(addr).unwrap();
}

/// Root page handler
fn index(_: &mut Request) -> IronResult<Response> {
    read_docs("Home")
}

/// Wiki page handler
fn page(req: &mut Request) -> IronResult<Response> {
    use router::Router;

    // Parse URL
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap_or("Home");
    read_docs(name)
}

/// `name`을 인자로 받아, `docs/<name>.md` 파일을 렌더링하여 `IronResult<Response>`로 반환합니다.
fn read_docs(name: &str) -> IronResult<Response> {
    use std::fs::File;
    use std::io::Read;
    use cmark::Parser;
    use cmark::html::push_html;

    // Read file
    let path = format!("docs/{}.md", name);
    let mut file = itry!(File::open(&path));
    let mut md = String::new();
    itry!(file.read_to_string(&mut md));

    // Parse markdown
    let parser = Parser::new(&md);
    let mut html = String::new();
    push_html(&mut html, parser);

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}
<commit_msg>"모든 문서 보기" 페이지 구현<commit_after>#[macro_use] extern crate iron;
#[macro_use] extern crate router;
extern crate mount;
extern crate staticfile;
extern crate handlebars_iron as hbs;
extern crate pulldown_cmark as cmark;

use std::collections::BTreeMap;
use iron::prelude::*;
use iron::status;
use mount::Mount;
use staticfile::Static;
use hbs::{Template, HandlebarsEngine, DirectorySource};

//
// Configs
//
/// 서버가 소켓을 열 주소
const ADDR: &'static str = "localhost:8000";
/// 마크다운 문서가 담긴 주소
const DOCS_DIR: &'static str = "docs";

/// Entry point
fn main() {
    let mut chain = Chain::new(router! {
        get "/" => index,
        get "/pages/:name" => page,
        get "/pages/_pages" => all_docs,
    });

    // Compile templates
    let mut hbse = HandlebarsEngine::new();
    hbse.add(Box::new(DirectorySource::new("templates", ".hbs")));
    // load templates from all registered sources
    if let Err(r) = hbse.reload() {
        use std::error::Error;
        panic!("{}", r.description());
    }
    // Register handlebar middleware
    chain.link_after(hbse);

    // Mount '/static/' path to the filesystem
    let mut mount = Mount::new();
    mount
        .mount("/", chain)
        .mount("/static/", Static::new("static/"));

    // Fire & Forget
    println!("\nServer running at \x1b[33mhttp://{}\x1b[0m\n", ADDR);
    Iron::new(mount).http(ADDR).unwrap();
}

/// Root page handler
fn index(_: &mut Request) -> IronResult<Response> {
    read_docs("Home")
}

/// Wiki page handler
fn page(req: &mut Request) -> IronResult<Response> {
    use router::Router;

    // Parse URL
    let name = req.extensions.get::<Router>().unwrap().find("name").unwrap_or("Home");
    read_docs(name)
}

/// "All documents" page handler
fn all_docs(_: &mut Request) -> IronResult<Response> {
    use std::fs::read_dir;

    let paths: Vec<_> = itry!(read_dir(DOCS_DIR))
        .filter_map(|f| f.ok())
        .map(|f| f.path())
        .filter(|p| p.is_file())
        .filter(|p| p.as_os_str().to_str()
            .map(|s| s.ends_with(".md"))
            .unwrap_or(false))
        .collect();
    let pages = paths.iter()
        .filter_map(|p| p.file_stem())
        .filter_map(|stem| stem.to_str());

    // TODO: 러스트로 이짓하지 말고 Handlebar로 대체
    let mut html = "
".to_string();
    for page in pages {
        use std::fmt::Write;
        write!(&mut html, r#"
{0}
"#, page).unwrap();
    }
    html.push_str("
");

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}

/// `name`을 인자로 받아, `docs/<name>.md` 파일을 렌더링하여 `IronResult<Response>`로 반환합니다.
fn read_docs(name: &str) -> IronResult<Response> {
    use std::fs::File;
    use std::io::Read;
    use cmark::Parser;
    use cmark::html::push_html;

    // Read file
    let path = format!("{}/{}.md", DOCS_DIR, name);
    let mut file = itry!(File::open(&path));
    let mut md = String::new();
    itry!(file.read_to_string(&mut md));

    // Parse markdown
    let parser = Parser::new(&md);
    let mut html = String::new();
    push_html(&mut html, parser);

    // Fill in to the template
    let mut data = BTreeMap::new();
    data.insert("content", html);
    Ok(Response::with((status::Ok, Template::new("default", data))))
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle the backing store of a pool.

use std::path::Path;

use devicemapper::{CacheDev, DmDevice, LinearDev, Sectors};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, DevUuid, PoolUuid};

use super::super::dm::get_dm;
use super::super::dmnames::{format_backstore_ids, CacheRole};

use super::blockdev::StratBlockDev;
use super::blockdevmgr::{coalesce_blkdevsegs, map_to_dm, BlkDevSegment, BlockDevMgr, Segment};

/// Handles the lowest level, base layer of this tier.
/// The dm_device organizes all block devs into a single linear allocation
/// pool. This structure can allocate additional space to the upper layer,
/// but it cannot accept returned space. When it is extended to be able to
/// accept returned space the allocation algorithm will have to be revised.
/// All available sectors on blockdevs in the manager are allocated to
/// the DM device.
#[derive(Debug)]
pub struct DataTier {
    /// Manages the individual block devices
    /// it is always the case block_mgr.avail_space() == 0.
    pub block_mgr: BlockDevMgr,
    /// The list of segments granted by block_mgr and used by dm_device
    /// It is always the case that block_mgr.avail_space() == 0, i.e., all
    /// available space in block_mgr is allocated to the DM device.
    pub segments: Vec<BlkDevSegment>,
}

impl DataTier {
    /// Setup a previously existing data layer from the block_mgr and
    /// previously allocated segments.
    ///
    /// Returns the DataTier and the linear DM device that was created during
    /// setup.
    pub fn setup(
        pool_uuid: PoolUuid,
        block_mgr: BlockDevMgr,
        segments: &[(DevUuid, Sectors, Sectors)],
    ) -> StratisResult<(DataTier, LinearDev)> {
        if block_mgr.avail_space() != Sectors(0) {
            let err_msg = format!(
                "{} unallocated to device; probable metadata corruption",
                block_mgr.avail_space()
            );
            return Err(StratisError::Engine(ErrorEnum::Error, err_msg));
        }

        let uuid_to_devno = block_mgr.uuid_to_devno();
        let mapper = |triple: &(DevUuid, Sectors, Sectors)| -> StratisResult<BlkDevSegment> {
            let device = uuid_to_devno(triple.0).ok_or_else(|| {
                StratisError::Engine(
                    ErrorEnum::NotFound,
                    format!("missing device for UUUD {:?}", &triple.0),
                )
            })?;
            Ok(BlkDevSegment::new(
                triple.0,
                Segment::new(device, triple.1, triple.2),
            ))
        };
        let segments = segments
            .iter()
            .map(&mapper)
            .collect::<StratisResult<Vec<_>>>()?;

        let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::OriginSub);
        let ld = LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;

        Ok((
            DataTier {
                block_mgr,
                segments,
            },
            ld,
        ))
    }

    /// Setup a new DataTier struct from the block_mgr.
    ///
    /// Returns the DataTier and the linear device that was created.
    ///
    /// WARNING: metadata changing event
    pub fn new(
        pool_uuid: PoolUuid,
        mut block_mgr: BlockDevMgr,
    ) -> StratisResult<(DataTier, LinearDev)> {
        let avail_space = block_mgr.avail_space();
        let segments = block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::OriginSub);
        let ld = LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;
        Ok((
            DataTier {
                block_mgr,
                segments,
            },
            ld,
        ))
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(
        &mut self,
        pool_uuid: PoolUuid,
        cache: Option<&mut CacheDev>,
        linear: Option<&mut LinearDev>,
        paths: &[&Path],
        force: bool,
    ) -> StratisResult<Vec<DevUuid>> {
        // These are here so that if invariant is false, the method fails
        // before allocating the segments from the block_mgr.
        // These two statements combined are equivalent to
        // cache.is_some() XOR linear.is_some(), but they may be clearer and
        // Rust does not seem to have a boolean XOR operator, anyway.
        assert!(!(cache.is_some() && linear.is_some()));
        assert!(!(cache.is_none() && linear.is_none()));

        let uuids = self.block_mgr.add(pool_uuid, paths, force)?;

        let avail_space = self.block_mgr.avail_space();
        let segments = self.block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let coalesced = coalesce_blkdevsegs(&self.segments, &segments);
        let table = map_to_dm(&coalesced);

        match (cache, linear) {
            (Some(cache), None) => {
                cache.set_origin_table(get_dm(), table)?;
                cache.resume(get_dm())
            }
            (None, Some(linear)) => {
                linear.set_table(get_dm(), table)?;
                linear.resume(get_dm())
            }
            _ => panic!("see assertions at top of method"),
        }?;

        self.segments = coalesced;

        Ok(uuids)
    }

    /// All the sectors available to this device
    pub fn capacity(&self) -> Sectors {
        self.segments
            .iter()
            .map(|x| x.segment.length)
            .sum::<Sectors>()
    }

    /// The total size of all the blockdevs combined
    pub fn current_capacity(&self) -> Sectors {
        let size = self.block_mgr.current_capacity();
        assert_eq!(size - self.metadata_size(), self.capacity());
        size
    }

    /// The number of sectors used for metadata by all the blockdevs
    pub fn metadata_size(&self) -> Sectors {
        self.block_mgr.metadata_size()
    }

    /// Destroy the store. Wipe its blockdevs.
    pub fn destroy(self) -> StratisResult<()> {
        self.block_mgr.destroy_all()
    }

    /// Save the given state to the devices. This action bypasses the DM
    /// device entirely.
    pub fn save_state(&mut self, metadata: &[u8]) -> StratisResult<()> {
        self.block_mgr.save_state(metadata)
    }

    /// Lookup an immutable blockdev by its Stratis UUID.
    pub fn get_blockdev_by_uuid(&self, uuid: DevUuid) -> Option<(BlockDevTier, &StratBlockDev)> {
        self.block_mgr
            .get_blockdev_by_uuid(uuid)
            .and_then(|bd| Some((BlockDevTier::Data, bd)))
    }

    /// Lookup a mutable blockdev by its Stratis UUID.
    pub fn get_mut_blockdev_by_uuid(
        &mut self,
        uuid: DevUuid,
    ) -> Option<(BlockDevTier, &mut StratBlockDev)> {
        self.block_mgr
            .get_mut_blockdev_by_uuid(uuid)
            .and_then(|bd| Some((BlockDevTier::Data, bd)))
    }

    /// Get the blockdevs belonging to this tier
    pub fn blockdevs(&self) -> Vec<(DevUuid, &StratBlockDev)> {
        self.block_mgr.blockdevs()
    }
}
<commit_msg>Get rid of an assert<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle the backing store of a pool.

use std::path::Path;

use devicemapper::{CacheDev, DmDevice, LinearDev, Sectors};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, DevUuid, PoolUuid};

use super::super::dm::get_dm;
use super::super::dmnames::{format_backstore_ids, CacheRole};

use super::blockdev::StratBlockDev;
use super::blockdevmgr::{coalesce_blkdevsegs, map_to_dm, BlkDevSegment, BlockDevMgr, Segment};

/// Handles the lowest level, base layer of this tier.
/// The dm_device organizes all block devs into a single linear allocation
/// pool. This structure can allocate additional space to the upper layer,
/// but it cannot accept returned space. When it is extended to be able to
/// accept returned space the allocation algorithm will have to be revised.
/// All available sectors on blockdevs in the manager are allocated to
/// the DM device.
#[derive(Debug)]
pub struct DataTier {
    /// Manages the individual block devices
    /// it is always the case block_mgr.avail_space() == 0.
    pub block_mgr: BlockDevMgr,
    /// The list of segments granted by block_mgr and used by dm_device
    /// It is always the case that block_mgr.avail_space() == 0, i.e., all
    /// available space in block_mgr is allocated to the DM device.
    pub segments: Vec<BlkDevSegment>,
}

impl DataTier {
    /// Setup a previously existing data layer from the block_mgr and
    /// previously allocated segments.
    ///
    /// Returns the DataTier and the linear DM device that was created during
    /// setup.
    pub fn setup(
        pool_uuid: PoolUuid,
        block_mgr: BlockDevMgr,
        segments: &[(DevUuid, Sectors, Sectors)],
    ) -> StratisResult<(DataTier, LinearDev)> {
        if block_mgr.avail_space() != Sectors(0) {
            let err_msg = format!(
                "{} unallocated to device; probable metadata corruption",
                block_mgr.avail_space()
            );
            return Err(StratisError::Engine(ErrorEnum::Error, err_msg));
        }

        let uuid_to_devno = block_mgr.uuid_to_devno();
        let mapper = |triple: &(DevUuid, Sectors, Sectors)| -> StratisResult<BlkDevSegment> {
            let device = uuid_to_devno(triple.0).ok_or_else(|| {
                StratisError::Engine(
                    ErrorEnum::NotFound,
                    format!("missing device for UUUD {:?}", &triple.0),
                )
            })?;
            Ok(BlkDevSegment::new(
                triple.0,
                Segment::new(device, triple.1, triple.2),
            ))
        };
        let segments = segments
            .iter()
            .map(&mapper)
            .collect::<StratisResult<Vec<_>>>()?;

        let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::OriginSub);
        let ld = LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;

        Ok((
            DataTier {
                block_mgr,
                segments,
            },
            ld,
        ))
    }

    /// Setup a new DataTier struct from the block_mgr.
    ///
    /// Returns the DataTier and the linear device that was created.
    ///
    /// WARNING: metadata changing event
    pub fn new(
        pool_uuid: PoolUuid,
        mut block_mgr: BlockDevMgr,
    ) -> StratisResult<(DataTier, LinearDev)> {
        let avail_space = block_mgr.avail_space();
        let segments = block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let (dm_name, dm_uuid) = format_backstore_ids(pool_uuid, CacheRole::OriginSub);
        let ld = LinearDev::setup(get_dm(), &dm_name, Some(&dm_uuid), map_to_dm(&segments))?;
        Ok((
            DataTier {
                block_mgr,
                segments,
            },
            ld,
        ))
    }

    /// Add the given paths to self. Return UUIDs of the new blockdevs
    /// corresponding to the specified paths.
    /// WARNING: metadata changing event
    pub fn add(
        &mut self,
        pool_uuid: PoolUuid,
        cache: Option<&mut CacheDev>,
        linear: Option<&mut LinearDev>,
        paths: &[&Path],
        force: bool,
    ) -> StratisResult<Vec<DevUuid>> {
        // These are here so that if invariant is false, the method fails
        // before allocating the segments from the block_mgr.
        // These two statements combined are equivalent to
        // cache.is_some() XOR linear.is_some(), but they may be clearer and
        // Rust does not seem to have a boolean XOR operator, anyway.
        assert!(!(cache.is_some() && linear.is_some()));
        assert!(!(cache.is_none() && linear.is_none()));

        let uuids = self.block_mgr.add(pool_uuid, paths, force)?;

        let avail_space = self.block_mgr.avail_space();
        let segments = self.block_mgr
            .alloc_space(&[avail_space])
            .expect("asked for exactly the space available, must get")
            .iter()
            .flat_map(|s| s.iter())
            .cloned()
            .collect::<Vec<_>>();
        let coalesced = coalesce_blkdevsegs(&self.segments, &segments);
        let table = map_to_dm(&coalesced);

        match (cache, linear) {
            (Some(cache), None) => {
                cache.set_origin_table(get_dm(), table)?;
                cache.resume(get_dm())
            }
            (None, Some(linear)) => {
                linear.set_table(get_dm(), table)?;
                linear.resume(get_dm())
            }
            _ => panic!("see assertions at top of method"),
        }?;

        self.segments = coalesced;

        Ok(uuids)
    }

    /// All the sectors available to this device
    pub fn capacity(&self) -> Sectors {
        self.segments
            .iter()
            .map(|x| x.segment.length)
            .sum::<Sectors>()
    }

    /// The total size of all the blockdevs combined
    pub fn current_capacity(&self) -> Sectors {
        self.block_mgr.current_capacity()
    }

    /// The number of sectors used for metadata by all the blockdevs
    pub fn metadata_size(&self) -> Sectors {
        self.block_mgr.metadata_size()
    }

    /// Destroy the store. Wipe its blockdevs.
    pub fn destroy(self) -> StratisResult<()> {
        self.block_mgr.destroy_all()
    }

    /// Save the given state to the devices. This action bypasses the DM
    /// device entirely.
    pub fn save_state(&mut self, metadata: &[u8]) -> StratisResult<()> {
        self.block_mgr.save_state(metadata)
    }

    /// Lookup an immutable blockdev by its Stratis UUID.
    pub fn get_blockdev_by_uuid(&self, uuid: DevUuid) -> Option<(BlockDevTier, &StratBlockDev)> {
        self.block_mgr
            .get_blockdev_by_uuid(uuid)
            .and_then(|bd| Some((BlockDevTier::Data, bd)))
    }

    /// Lookup a mutable blockdev by its Stratis UUID.
    pub fn get_mut_blockdev_by_uuid(
        &mut self,
        uuid: DevUuid,
    ) -> Option<(BlockDevTier, &mut StratBlockDev)> {
        self.block_mgr
            .get_mut_blockdev_by_uuid(uuid)
            .and_then(|bd| Some((BlockDevTier::Data, bd)))
    }

    /// Get the blockdevs belonging to this tier
    pub fn blockdevs(&self) -> Vec<(DevUuid, &StratBlockDev)> {
        self.block_mgr.blockdevs()
    }

    /// Assert things that should always hold true of a DataTier
    #[allow(dead_code)]
    fn invariant(&self) -> () {
        assert_eq!(
            self.block_mgr.current_capacity() - self.metadata_size(),
            self.capacity()
        )
    }
}
<|endoftext|>


<commit_before>/// A genetic algorithm in Rust
/// Copyright (C) 2015  Andrew Schwartzmeyer

#[macro_use]
extern crate clap;
extern crate rand;
extern crate time;

use clap::App;
use individual::Individual;
use rand::Rng;
use std::thread;
use time::precise_time_s;

mod individual;
mod problem;

arg_enum!{
    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
    pub enum Problem {
        Ackley,
        Schwefel
    }
}

/// Tournament selection from 4 random individuals
fn select<R: Rng>(population: &[Individual], rng: &mut R) -> Individual {
    if let Some(selected) = (0..4).map(|_| rng.choose(population)).min() {
        selected.unwrap().clone()
    } else {
        unimplemented!();
    }
}

/// Setup and run algorithm to search for solution
fn main() {
    let matches = App::new("rust-genetic-algorithm")
        .version(&crate_version!()[..])
        .author("Andrew Schwartzmeyer <andrew@schwartzmeyer.com")
        .about("A genetic algorithm in Rust for Schwefel's function.")
        .args_from_usage(
            "[<problem>] 'The problem to solve'
             [-d --dimension <30>] 'Sets the dimension of the hypercube'
             [-p --population <256>] 'Sets the size of the population'
             [-i --iterations <5000>] 'Sets maximum number of generations'
             --verbose 'Print fitness every 10th generation'")
        .get_matches();
    let problem = value_t!(matches.value_of("problem"), Problem)
        .unwrap_or(Problem::Schwefel);
    let dimension = value_t!(matches.value_of("d"), usize).unwrap_or(30);
    let population_size = value_t!(matches.value_of("p"), usize).unwrap_or(256);
    let iterations = value_t!(matches.value_of("i"), usize).unwrap_or(5000);
    let verbose = matches.is_present("verbose");

    let mut rng = rand::thread_rng();

    // initialize population individuals
    let mut population: Vec<_> = (0..population_size).map(|_| {
        Individual::new(problem, dimension, &mut rng)
    }).collect();

    let start_time = precise_time_s();
    // search with generations
    for i in 0..iterations {
        // select, mutate, and recombine individuals for next generation
        let mut offspring: Vec<Individual> = Vec::with_capacity(population.len());
        for _ in 0..population.len()/2 {
            let (mut x, mut y) = (select(&population, &mut rng),
                                  select(&population, &mut rng));
            x.mutate(&mut rng);
            y.mutate(&mut rng);
            Individual::combine(&mut x, &mut y, &mut rng);
            offspring.push(x);
            offspring.push(y);
        }
        assert!(offspring.len() == population.len());

        // replace 2 random individuals with elite of prior generation
        for _ in 0..2 {
            if let Some(x) = population.iter().min() {
                offspring[rng.gen_range(0, population.len())] = x.clone();
            }
        }

        // replace population with next generation
        population = offspring;

        // examine best individual for convergence
        if let Some(x) = population.iter().min() {
            if verbose && i % 10 == 0 {
                let fitness = x.fitness;
                thread::spawn(move || {
                    println!("{}th fitness {}", i, fitness)
                });
            }
            if x.fitness < 0.05_f64 {
                let duration = precise_time_s() - start_time;
                println!("{}th solution converged at {} in {} seconds",
                         i, x.fitness, duration);
                if verbose {
                    println!{"{:?}", x.solution};
                }
                return;
            }
        } else { unimplemented!() }
    }
    println!("Failed to converge.");
}
<commit_msg>Implement verbosity levels<commit_after>/// A genetic algorithm in Rust
/// Copyright (C) 2015  Andrew Schwartzmeyer

#[macro_use]
extern crate clap;
extern crate rand;
extern crate time;

use clap::App;
use individual::Individual;
use rand::Rng;
use std::thread;
use time::precise_time_s;

mod individual;
mod problem;

arg_enum!{
    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
    pub enum Problem {
        Ackley,
        Schwefel
    }
}

/// Tournament selection from 4 random individuals
fn select<R: Rng>(population: &[Individual], rng: &mut R) -> Individual {
    if let Some(selected) = (0..4).map(|_| rng.choose(population)).min() {
        selected.unwrap().clone()
    } else {
        unimplemented!();
    }
}

/// Setup and run algorithm to search for solution
fn main() {
    let matches = App::new("rust-genetic-algorithm")
        .version(&crate_version!()[..])
        .author("Andrew Schwartzmeyer <andrew@schwartzmeyer.com")
        .about("A genetic algorithm in Rust for Schwefel's function.")
        .args_from_usage(
            "[<problem>] 'The problem to solve'
             [-d --dimension <30>] 'Sets the dimension of the hypercube'
             [-p --population <256>] 'Sets the size of the population'
             [-i --iterations <5000>] 'Sets maximum number of generations'
             [verbose]... -v 'Print fitness (1) and solution (2) every 10th generation'")
        .get_matches();
    let problem = value_t!(matches.value_of("problem"), Problem)
        .unwrap_or(Problem::Schwefel);
    let dimension = value_t!(matches.value_of("d"), usize).unwrap_or(30);
    let population_size = value_t!(matches.value_of("p"), usize).unwrap_or(256);
    let iterations = value_t!(matches.value_of("i"), usize).unwrap_or(5000);
    let verbosity = matches.occurrences_of("verbose");

    let mut rng = rand::thread_rng();

    // initialize population individuals
    let mut population: Vec<_> = (0..population_size).map(|_| {
        Individual::new(problem, dimension, &mut rng)
    }).collect();

    let start_time = precise_time_s();
    // search with generations
    for i in 0..iterations {
        // select, mutate, and recombine individuals for next generation
        let mut offspring: Vec<Individual> = Vec::with_capacity(population.len());
        for _ in 0..population.len()/2 {
            let (mut x, mut y) = (select(&population, &mut rng),
                                  select(&population, &mut rng));
            x.mutate(&mut rng);
            y.mutate(&mut rng);
            Individual::combine(&mut x, &mut y, &mut rng);
            offspring.push(x);
            offspring.push(y);
        }
        assert!(offspring.len() == population.len());

        // replace 2 random individuals with elite of prior generation
        for _ in 0..2 {
            if let Some(x) = population.iter().min() {
                offspring[rng.gen_range(0, population.len())] = x.clone();
            }
        }

        // replace population with next generation
        population = offspring;

        // examine best individual for convergence
        if let Some(x) = population.iter().min() {
            if verbosity > 0 && i % 10 == 0 {
                let fitness = x.fitness;
                let solution = x.solution.clone();
                thread::spawn(move || {
                    if verbosity >= 1 {
                        println!("{}th fitness {}", i, fitness);
                    }
                    if verbosity >= 2 {
                        println!{"{:?}", solution};
                    }
                });
            }
            if x.fitness < 0.05_f64 {
                let duration = precise_time_s() - start_time;
                println!("{}th solution converged at {} in {} seconds",
                         i, x.fitness, duration);
                println!{"{:?}", x.solution};
                return;
            }
        } else { unimplemented!() }
    }
    println!("Failed to converge.");
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
#[macro_use]
extern crate log;
extern crate rpassword;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_process;
extern crate tokio_signal;
extern crate url;
extern crate sha1;
extern crate hex;

use sha1::{Sha1, Digest};
use env_logger::LogBuilder;
use futures::sync::mpsc::UnboundedReceiver;
use futures::{Async, Future, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::mem;
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Core, Handle};
use tokio_io::IoStream;
use url::Url;

use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache;
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig};
use librespot::core::session::Session;
use librespot::core::version;

use librespot::connect::discovery::{discovery, DiscoveryStream};
use librespot::connect::spirc::{Spirc, SpircTask};
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
use librespot::playback::config::{Bitrate, PlayerConfig};
use librespot::playback::mixer::{self, Mixer};
use librespot::playback::player::{Player, PlayerEvent};

mod player_event_handler;
use player_event_handler::run_program_on_events;

fn device_id(name: &str) -> String {
    hex::encode(Sha1::digest(name.as_bytes()))
}

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=info,librespot=info");
            }
            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>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    credentials: Option<Credentials>,
    enable_discovery: bool,
    zeroconf_port: u16,
    player_event_program: Option<String>,
}

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",
    ).optflag("", "disable-audio-cache", "Disable caching of the audio data.")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE")
        .optopt(
            "b",
            "bitrate",
            "Bitrate (96, 160 or 320). Defaults to 160",
            "BITRATE",
        )
        .optopt(
            "",
            "onevent",
            "Run PROGRAM when playback is about to begin.",
            "PROGRAM",
        )
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optopt("", "proxy", "HTTP proxy to use when connecting", "PROXY")
        .optopt("", "ap-port", "Connect to AP with specified port. If no AP with that port are present fallback AP will be used. Available ports are usually 80, 443 and 4070", "AP_PORT")
        .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 if using portaudio",
            "DEVICE",
        )
        .optopt("", "mixer", "Mixer to use", "MIXER")
        .optopt(
            "",
            "initial-volume",
            "Initial volume in %, once connected (must be from 0 to 100)",
            "VOLUME",
        )
        .optopt(
            "",
            "zeroconf-port",
            "The port the internal server advertised over zeroconf uses.",
            "ZEROCONF_PORT",
        )
        .optflag(
            "",
            "enable-volume-normalisation",
            "Play all tracks at the same volume",
        )
        .optopt(
            "",
            "normalisation-pregain",
            "Pregain (dB) applied by volume normalisation",
            "PREGAIN",
        )
        .optflag(
            "",
            "linear-volume",
            "increase volume linear instead of logarithmic.",
        );

    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 {}. Build ID: {}",
        version::short_sha(),
        version::commit_date(),
        version::short_now(),
        version::build_id()
    );

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

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

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

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

    let use_audio_cache = !matches.opt_present("disable-audio-cache");

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

    let initial_volume = matches
        .opt_str("initial-volume")
        .map(|volume| {
            let volume = volume.parse::<u16>().unwrap();
            if volume > 100 {
                panic!("Initial volume must be in the range 0-100");
            }
            (volume as i32 * 0xFFFF / 100) as u16
        })
        .or_else(|| cache.as_ref().and_then(Cache::volume))
        .unwrap_or(0x8000);

    let zeroconf_port = matches
        .opt_str("zeroconf-port")
        .map(|port| port.parse::<u16>().unwrap())
        .unwrap_or(0);

    let name = matches.opt_str("name").unwrap();

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

        let password = |username: &String| -> String {
            write!(stderr(), "Password for {}: ", username).unwrap();
            stderr().flush().unwrap();
            rpassword::read_password().unwrap()
        };

        get_credentials(
            matches.opt_str("username"),
            matches.opt_str("password"),
            cached_credentials,
            password,
        )
    };

    let session_config = {
        let device_id = device_id(&name);

        SessionConfig {
            user_agent: version::version_string(),
            device_id: device_id,
            proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map(
                |s| {
                    match Url::parse(&s) {
                        Ok(url) => {
                            if url.host().is_none() || url.port().is_none() {
                                panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed");
                            }

                            if url.scheme() != "http" {
                                panic!("Only unsecure http:// proxies are supported");
                            }
                            url
                        },
                    Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err)
                    }
                },
            ),
            ap_port: matches
                .opt_str("ap-port")
                .map(|port| port.parse::<u16>().expect("Invalid port")),
        }
    };

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

        PlayerConfig {
            bitrate: bitrate,
            normalisation: matches.opt_present("enable-volume-normalisation"),
            normalisation_pregain: matches
                .opt_str("normalisation-pregain")
                .map(|pregain| pregain.parse::<f32>().expect("Invalid pregain float value"))
                .unwrap_or(PlayerConfig::default().normalisation_pregain),
        }
    };

    let connect_config = {
        let device_type = matches
            .opt_str("device-type")
            .as_ref()
            .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type"))
            .unwrap_or(DeviceType::default());

        ConnectConfig {
            name: name,
            device_type: device_type,
            volume: initial_volume,
            linear_volume: matches.opt_present("linear-volume"),
        }
    };

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

    Setup {
        backend: backend,
        cache: cache,
        session_config: session_config,
        player_config: player_config,
        connect_config: connect_config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        zeroconf_port: zeroconf_port,
        mixer: mixer,
        player_event_program: matches.opt_str("onevent"),
    }
}

struct Main {
    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    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>>,

    shutdown: bool,

    player_event_channel: Option<UnboundedReceiver<PlayerEvent>>,
    player_event_program: Option<String>,
}

impl Main {
    fn new(handle: Handle, setup: Setup) -> Main {
        let mut task = Main {
            handle: handle.clone(),
            cache: setup.cache,
            session_config: setup.session_config,
            player_config: setup.player_config,
            connect_config: setup.connect_config,
            backend: setup.backend,
            device: setup.device,
            mixer: setup.mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,
            shutdown: false,
            signal: Box::new(tokio_signal::ctrl_c(&handle).flatten_stream()),

            player_event_channel: None,
            player_event_program: setup.player_event_program,
        };

        if setup.enable_discovery {
            let config = task.connect_config.clone();
            let device_id = task.session_config.device_id.clone();

            task.discovery = Some(discovery(&handle, config, device_id, setup.zeroconf_port).unwrap());
        }

        if let Some(credentials) = setup.credentials {
            task.credentials(credentials);
        }

        task
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.session_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 player_config = self.player_config.clone();
                let connect_config = self.connect_config.clone();

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

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

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                trace!("Ctrl-C received");
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    } else {
                        return Ok(Async::Ready(()));
                    }
                    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_event_channel) = self.player_event_channel {
                if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() {
                    if let Some(ref program) = self.player_event_program {
                        let child = run_program_on_events(event, program)
                            .expect("program failed to start")
                            .map(|status| if !status.success() {
                                error!("child exited with status {:?}", status.code());
                            })
                            .map_err(|e| error!("failed to wait on child process: {}", e));

                        self.handle.spawn(child);

                    }
                }
            }

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

fn main() {
    if env::var("RUST_BACKTRACE").is_err() {
        env::set_var("RUST_BACKTRACE", "full")
    }
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();

    core.run(Main::new(handle, setup(&args))).unwrap()
}
<commit_msg>QDH: Instantiate audio backend immediately when using "--device ?".<commit_after>extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
#[macro_use]
extern crate log;
extern crate rpassword;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_process;
extern crate tokio_signal;
extern crate url;
extern crate sha1;
extern crate hex;

use sha1::{Sha1, Digest};
use env_logger::LogBuilder;
use futures::sync::mpsc::UnboundedReceiver;
use futures::{Async, Future, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::mem;
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Core, Handle};
use tokio_io::IoStream;
use url::Url;

use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache;
use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig};
use librespot::core::session::Session;
use librespot::core::version;

use librespot::connect::discovery::{discovery, DiscoveryStream};
use librespot::connect::spirc::{Spirc, SpircTask};
use librespot::playback::audio_backend::{self, Sink, BACKENDS};
use librespot::playback::config::{Bitrate, PlayerConfig};
use librespot::playback::mixer::{self, Mixer};
use librespot::playback::player::{Player, PlayerEvent};

mod player_event_handler;
use player_event_handler::run_program_on_events;

fn device_id(name: &str) -> String {
    hex::encode(Sha1::digest(name.as_bytes()))
}

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=info,librespot=info");
            }
            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>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    credentials: Option<Credentials>,
    enable_discovery: bool,
    zeroconf_port: u16,
    player_event_program: Option<String>,
}

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",
    ).optflag("", "disable-audio-cache", "Disable caching of the audio data.")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE")
        .optopt(
            "b",
            "bitrate",
            "Bitrate (96, 160 or 320). Defaults to 160",
            "BITRATE",
        )
        .optopt(
            "",
            "onevent",
            "Run PROGRAM when playback is about to begin.",
            "PROGRAM",
        )
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optopt("", "proxy", "HTTP proxy to use when connecting", "PROXY")
        .optopt("", "ap-port", "Connect to AP with specified port. If no AP with that port are present fallback AP will be used. Available ports are usually 80, 443 and 4070", "AP_PORT")
        .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 if using portaudio",
            "DEVICE",
        )
        .optopt("", "mixer", "Mixer to use", "MIXER")
        .optopt(
            "",
            "initial-volume",
            "Initial volume in %, once connected (must be from 0 to 100)",
            "VOLUME",
        )
        .optopt(
            "",
            "zeroconf-port",
            "The port the internal server advertised over zeroconf uses.",
            "ZEROCONF_PORT",
        )
        .optflag(
            "",
            "enable-volume-normalisation",
            "Play all tracks at the same volume",
        )
        .optopt(
            "",
            "normalisation-pregain",
            "Pregain (dB) applied by volume normalisation",
            "PREGAIN",
        )
        .optflag(
            "",
            "linear-volume",
            "increase volume linear instead of logarithmic.",
        );

    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 {}. Build ID: {}",
        version::short_sha(),
        version::commit_date(),
        version::short_now(),
        version::build_id()
    );

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

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

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

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

    let use_audio_cache = !matches.opt_present("disable-audio-cache");

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

    let initial_volume = matches
        .opt_str("initial-volume")
        .map(|volume| {
            let volume = volume.parse::<u16>().unwrap();
            if volume > 100 {
                panic!("Initial volume must be in the range 0-100");
            }
            (volume as i32 * 0xFFFF / 100) as u16
        })
        .or_else(|| cache.as_ref().and_then(Cache::volume))
        .unwrap_or(0x8000);

    let zeroconf_port = matches
        .opt_str("zeroconf-port")
        .map(|port| port.parse::<u16>().unwrap())
        .unwrap_or(0);

    let name = matches.opt_str("name").unwrap();

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

        let password = |username: &String| -> String {
            write!(stderr(), "Password for {}: ", username).unwrap();
            stderr().flush().unwrap();
            rpassword::read_password().unwrap()
        };

        get_credentials(
            matches.opt_str("username"),
            matches.opt_str("password"),
            cached_credentials,
            password,
        )
    };

    let session_config = {
        let device_id = device_id(&name);

        SessionConfig {
            user_agent: version::version_string(),
            device_id: device_id,
            proxy: matches.opt_str("proxy").or(std::env::var("http_proxy").ok()).map(
                |s| {
                    match Url::parse(&s) {
                        Ok(url) => {
                            if url.host().is_none() || url.port().is_none() {
                                panic!("Invalid proxy url, only urls on the format \"http://host:port\" are allowed");
                            }

                            if url.scheme() != "http" {
                                panic!("Only unsecure http:// proxies are supported");
                            }
                            url
                        },
                    Err(err) => panic!("Invalid proxy url: {}, only urls on the format \"http://host:port\" are allowed", err)
                    }
                },
            ),
            ap_port: matches
                .opt_str("ap-port")
                .map(|port| port.parse::<u16>().expect("Invalid port")),
        }
    };

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

        PlayerConfig {
            bitrate: bitrate,
            normalisation: matches.opt_present("enable-volume-normalisation"),
            normalisation_pregain: matches
                .opt_str("normalisation-pregain")
                .map(|pregain| pregain.parse::<f32>().expect("Invalid pregain float value"))
                .unwrap_or(PlayerConfig::default().normalisation_pregain),
        }
    };

    let connect_config = {
        let device_type = matches
            .opt_str("device-type")
            .as_ref()
            .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type"))
            .unwrap_or(DeviceType::default());

        ConnectConfig {
            name: name,
            device_type: device_type,
            volume: initial_volume,
            linear_volume: matches.opt_present("linear-volume"),
        }
    };

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

    Setup {
        backend: backend,
        cache: cache,
        session_config: session_config,
        player_config: player_config,
        connect_config: connect_config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        zeroconf_port: zeroconf_port,
        mixer: mixer,
        player_event_program: matches.opt_str("onevent"),
    }
}

struct Main {
    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    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>>,

    shutdown: bool,

    player_event_channel: Option<UnboundedReceiver<PlayerEvent>>,
    player_event_program: Option<String>,
}

impl Main {
    fn new(handle: Handle, setup: Setup) -> Main {
        let mut task = Main {
            handle: handle.clone(),
            cache: setup.cache,
            session_config: setup.session_config,
            player_config: setup.player_config,
            connect_config: setup.connect_config,
            backend: setup.backend,
            device: setup.device,
            mixer: setup.mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,
            shutdown: false,
            signal: Box::new(tokio_signal::ctrl_c(&handle).flatten_stream()),

            player_event_channel: None,
            player_event_program: setup.player_event_program,
        };

        if setup.enable_discovery {
            let config = task.connect_config.clone();
            let device_id = task.session_config.device_id.clone();

            task.discovery = Some(discovery(&handle, config, device_id, setup.zeroconf_port).unwrap());
        }

        if let Some(credentials) = setup.credentials {
            task.credentials(credentials);
        }

        task
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.session_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 player_config = self.player_config.clone();
                let connect_config = self.connect_config.clone();

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

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

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                trace!("Ctrl-C received");
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    } else {
                        return Ok(Async::Ready(()));
                    }
                    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_event_channel) = self.player_event_channel {
                if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() {
                    if let Some(ref program) = self.player_event_program {
                        let child = run_program_on_events(event, program)
                            .expect("program failed to start")
                            .map(|status| if !status.success() {
                                error!("child exited with status {:?}", status.code());
                            })
                            .map_err(|e| error!("failed to wait on child process: {}", e));

                        self.handle.spawn(child);

                    }
                }
            }

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

fn main() {
    if env::var("RUST_BACKTRACE").is_err() {
        env::set_var("RUST_BACKTRACE", "full")
    }
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();

    core.run(Main::new(handle, setup(&args))).unwrap()
}
<|endoftext|>