<commit_before>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        if Stream::is_numeric(&token_str) {
            return Some(Token::ImmConst(token_str.parse::<u16>().unwrap()));
        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    fn is_numeric(input: &str) -> bool {
        if input.len() < 1 {
            return false;
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return false;
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return false
                }
                return true
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return false
                }
                return true
            }
        }
        false
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<commit_msg>Update the Stream::is_numeric method to indicate base of the input<commit_after>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        let (numeric, radix) = Stream::is_numeric(&token_str);
        if numeric {
            return match radix {
                // base 10
                0 => Some(Token::ImmConst(token_str.parse::<u16>().unwrap())),
                // base 16
                1 => Some(Token::ImmConst(u16::from_str_radix(&token_str, 16).unwrap())),
                _ => None,
            }

        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    // Returns a tuple of boolean and integer
    // The input is numeric if the boolean component of the result is true
    // Integer component of result:
    //   0 => base 10
    //   1 => base 16
    fn is_numeric(input: &str) -> (bool, u8) {
        if input.len() < 1 {
            return (false, std::u8::MAX);
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return (false, std::u8::MAX);
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return (false, std::u8::MAX);
                }
                return (true, 1);
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return (false, std::u8::MAX);
                }
                return (true, 0);
            }
        }
        return (false, std::u8::MAX);
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<|endoftext|>


<commit_before>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,  // TODO: this should be optional
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<commit_msg>Add type to FeatureCollection json<commit_after>// TODO
// impl ToGeojson for ....
// generic number instead of f64 for position?
// rename Position to Pos or Positions

extern crate serialize;

use std::collections::TreeMap;
use serialize::json::ToJson;
use serialize::json;

/// Position
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
pub struct Position(pub Vec<f64>);

impl ToJson for Position {
    fn to_json(&self) -> json::Json {
        let &Position(ref nums) = self;
        nums.to_json()
    }
}

impl Clone for Position {
    fn clone(&self) -> Position {
        let &Position(ref nums) = self;
        Position(nums.clone())
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
pub struct Point {
    pub coordinates: Position,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Point".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
pub struct MultiPoint {
    pub points: Vec<Point>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Position> =
            self.points.iter().map(|p| p.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPoint".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
pub struct LineString {
    pub coordinates: Vec<Position>,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "LineString".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates.to_json());
        d.to_json()
    }
}

/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
pub struct MultiLineString {
    pub line_strings: Vec<LineString>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Position>> =
            self.line_strings.iter().map(|l| l.coordinates.clone()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiLineString".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
pub struct Polygon {
    pub exterior: Vec<Position>,
    pub holes: Vec<Vec<Position>>,  // TODO: this should be optional
}

impl Polygon {
    fn coordinates(&self) -> Vec<Vec<Position>> {
        let mut coordinates = self.holes.clone();
        coordinates.insert(0, self.exterior.clone());
        coordinates
    }
}

impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Polygon".to_string().to_json());
        d.insert("coordinates".to_string(), self.coordinates().to_json());
        d.to_json()
    }
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
pub struct MultiPolygon {
    pub polygons: Vec<Polygon>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let coordinates: Vec<Vec<Vec<Position>>> =
            self.polygons.iter().map(|p| p.coordinates()).collect();
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "MultiPolygon".to_string().to_json());
        d.insert("coordinates".to_string(), coordinates.to_json());
        d.to_json()
    }
}

/// Geometry
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            // TODO: is there a better way of doing this?
            Point(ref geom) => geom.to_json(),
            MultiPoint(ref geom) => geom.to_json(),
            LineString(ref geom) => geom.to_json(),
            MultiLineString(ref geom) => geom.to_json(),
            Polygon(ref geom) => geom.to_json(),
            MultiPolygon(ref geom) => geom.to_json(),
            GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}

/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "GeometryCollection".to_string().to_json());
        d.insert("geometries".to_string(), self.geometries.to_json());
        d.to_json()
    }
}

/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "Feature".to_string().to_json());
        d.insert("geometry".to_string(), self.geometry.to_json());
        d.insert("properties".to_string(), self.properties.to_json());
        d.to_json()
    }
}

/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = TreeMap::new();
        d.insert("type".to_string(), "FeatureCollection".to_string().to_json());
        d.insert("features".to_string(), self.features.to_json());
        d.to_json()
    }
}

fn main() {
    let point = Point {
        coordinates: Position(vec![1., 2., 3.]),
    };

    let j: json::Json = point.to_json();
    let s: String = j.to_pretty_str();

    println!("{}", s);
}
<|endoftext|>


<commit_before>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let http_proxy = cargo_update::ops::find_proxy(&crates_file);
    let configuration = cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml"))?;
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);
    let installed_git_packages = if opts.update_git || (opts.update && opts.install) {
        cargo_update::ops::installed_git_repo_packages(&crates_file)
    } else {
        vec![]
    };

    if !opts.filter.is_empty() {
        packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
    }
    match (opts.all, opts.to_update.is_empty()) {
        (true, true) => {}
        (true, false) => {
            for pkg in cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install, &installed_git_packages).into_iter() {
                if packages.iter().find(|p| p.name == pkg.name).is_none() {
                    packages.push(pkg);
                }
            }
        }
        (false, true) => {
            panic!("No packages to update and -a not specified, this should've been caught by option parser \
                    (please report to http://github.com/nabijaczleweli/cargo-update)")
        }
        (false, false) => packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install, &installed_git_packages),
    }

    let registry_url = cargo_update::ops::get_index_url(&crates_file);
    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1, Some(&registry_url)).map_err(|e| {
            println!("Couldn't get package repository: {}.", e);
            2
        })?;
    let mut registry_repo = Repository::open(&registry).map_err(|_| {
            println!("Failed to open registry repository at {}.", registry.display());
            2
        })?;
    cargo_update::ops::update_index(&mut registry_repo, &registry_url, http_proxy.as_ref().map(String::as_str), &mut stdout()).map_err(|e| {
            println!("Failed to update index repository: {}.", e);
            2
        })?;
    let latest_registry = registry_repo.revparse_single("origin/master")
        .map_err(|_| {
            println!("Failed to read master branch of registry repository at {}.", registry.display());
            2
        })?;

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version, package_install_prereleases) in
            packages.iter()
                .map(|p| {
                    let cfg = configuration.get(&p.name);
                    (p, cfg.as_ref().and_then(|c| c.target_version.as_ref()), cfg.as_ref().and_then(|c| c.install_prereleases))
                })
                .sorted_by(|&(ref lhs, lhstv, lhsip), &(ref rhs, rhstv, rhsip)| {
                    (!lhs.needs_update(lhstv, lhsip), &lhs.name).cmp(&(!rhs.needs_update(rhstv, rhsip), &rhs.name))
                }) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version, package_install_prereleases) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out).unwrap();
        out.flush().unwrap();
    }

    let mut success_n_global = 0usize;
    let mut errored_global = vec![];
    let mut result_global = None;

    if opts.update {
        if !opts.force {
            packages.retain(|p| {
                let cfg = configuration.get(&p.name);
                p.needs_update(cfg.as_ref().and_then(|c| c.target_version.as_ref()),
                               cfg.as_ref().and_then(|c| c.install_prereleases))
            });
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!();
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            success_n_global += success_n;

            println!();
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                print!("Failed to update ");
                for (i, e) in errored.iter().enumerate() {
                    if i != 0 {
                        print!(", ");
                    }
                    print!("{}", e);
                }
                println!(".");
                println!();

                if opts.update_git {
                    errored_global = errored;
                    result_global = result;
                } else {
                    return Err(result.unwrap());
                }
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = installed_git_packages;

        if !opts.filter.is_empty() {
            packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
        }
        if !opts.all {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        let git_db_dir = crates_file.with_file_name("git").join("db");
        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1, &git_db_dir, http_proxy.as_ref().map(String::as_str));
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out).unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!();
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                success_n_global += success_n;

                println!();
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    print!("Failed to update ");
                    for (i, e) in errored.iter().enumerate() {
                        if i != 0 {
                            print!(", ");
                        }
                        print!("{}", e);
                    }
                    println!(".");
                    println!();

                    errored_global.extend(errored);

                    if result_global.is_none() {
                        return Err(result.unwrap());
                    }
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    if opts.update {
        println!("Overall updated {} package{}.", success_n_global, if success_n_global == 1 { "" } else { "s" });

        if !errored_global.is_empty() && result_global.is_some() {
            print!("Overall failed to update ");
            for (i, e) in errored_global.iter().enumerate() {
                if i != 0 {
                    print!(", ");
                }
                print!("{}", e);
            }
            println!(".");

            return Err(result_global.unwrap());
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    save_cargo_update_exec_impl(format!("exe-v{}", version));
}

#[cfg(target_os="windows")]
fn save_cargo_update_exec_impl(extension: String) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(extension)).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    restore_cargo_update_exec_impl(format!("exe-v{}", version))
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec_impl(extension: String) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(extension), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<commit_msg>Specifying features with install-update-config is broken on nightly<commit_after>extern crate cargo_update;
extern crate tabwriter;
extern crate lazysort;
extern crate regex;
extern crate git2;

use std::process::{Command, exit};
use std::io::{Write, stdout};
use tabwriter::TabWriter;
use lazysort::SortedBy;
use std::fmt::Display;
use git2::Repository;
#[cfg(target_os="windows")]
use std::fs::File;
use regex::Regex;
use std::env;
use std::fs;

fn main() {
    let result = actual_main().err().unwrap_or(0);
    exit(result);
}

fn actual_main() -> Result<(), i32> {
    let opts = cargo_update::Options::parse();

    if cfg!(target_os = "windows") {
        let old_version_r = Regex::new(r"cargo-install-update\.exe-v.+").unwrap();
        for old_version in fs::read_dir(env::current_exe().unwrap().parent().unwrap().canonicalize().unwrap())
            .unwrap()
            .map(Result::unwrap)
            .filter(|f| old_version_r.is_match(&f.file_name().into_string().unwrap())) {
            fs::remove_file(old_version.path()).unwrap();
        }
    }

    let crates_file = cargo_update::ops::resolve_crates_file(opts.crates_file.1.clone());
    let http_proxy = cargo_update::ops::find_proxy(&crates_file);
    let configuration = cargo_update::ops::PackageConfig::read(&crates_file.with_file_name(".install_config.toml"))?;
    let mut packages = cargo_update::ops::installed_main_repo_packages(&crates_file);
    let installed_git_packages = if opts.update_git || (opts.update && opts.install) {
        cargo_update::ops::installed_git_repo_packages(&crates_file)
    } else {
        vec![]
    };

    if !opts.filter.is_empty() {
        packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
    }
    match (opts.all, opts.to_update.is_empty()) {
        (true, true) => {}
        (true, false) => {
            for pkg in cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install, &installed_git_packages).into_iter() {
                if packages.iter().find(|p| p.name == pkg.name).is_none() {
                    packages.push(pkg);
                }
            }
        }
        (false, true) => {
            panic!("No packages to update and -a not specified, this should've been caught by option parser \
                    (please report to http://github.com/nabijaczleweli/cargo-update)")
        }
        (false, false) => packages = cargo_update::ops::intersect_packages(&packages, &opts.to_update, opts.install, &installed_git_packages),
    }

    let registry_url = cargo_update::ops::get_index_url(&crates_file);
    let registry = cargo_update::ops::get_index_path(&opts.cargo_dir.1, Some(&registry_url)).map_err(|e| {
            println!("Couldn't get package repository: {}.", e);
            2
        })?;
    let mut registry_repo = Repository::open(&registry).map_err(|_| {
            println!("Failed to open registry repository at {}.", registry.display());
            2
        })?;
    cargo_update::ops::update_index(&mut registry_repo, &registry_url, http_proxy.as_ref().map(String::as_str), &mut stdout()).map_err(|e| {
            println!("Failed to update index repository: {}.", e);
            2
        })?;
    let latest_registry = registry_repo.revparse_single("origin/master")
        .map_err(|_| {
            println!("Failed to read master branch of registry repository at {}.", registry.display());
            2
        })?;

    for package in &mut packages {
        package.pull_version(&latest_registry.as_commit().unwrap().tree().unwrap(), &registry_repo);
    }

    {
        let mut out = TabWriter::new(stdout());
        writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
        for (package, package_target_version, package_install_prereleases) in
            packages.iter()
                .map(|p| {
                    let cfg = configuration.get(&p.name);
                    (p, cfg.as_ref().and_then(|c| c.target_version.as_ref()), cfg.as_ref().and_then(|c| c.install_prereleases))
                })
                .sorted_by(|&(ref lhs, lhstv, lhsip), &(ref rhs, rhstv, rhsip)| {
                    (!lhs.needs_update(lhstv, lhsip), &lhs.name).cmp(&(!rhs.needs_update(rhstv, rhsip), &rhs.name))
                }) {
            write!(out, "{}\t", package.name).unwrap();
            if let Some(ref v) = package.version {
                write!(out, "v{}", v).unwrap();
            }
            if let Some(tv) = package_target_version {
                write!(out, "\t{}", tv).unwrap();
            } else if let Some(upd_v) = package.update_to_version() {
                write!(out, "\tv{}", upd_v).unwrap();
            } else {
                write!(out, "\tN/A").unwrap();
            }
            writeln!(out,
                     "\t{}",
                     if package.needs_update(package_target_version, package_install_prereleases) {
                         "Yes"
                     } else {
                         "No"
                     })
                .unwrap();
        }
        writeln!(out).unwrap();
        out.flush().unwrap();
    }

    let mut success_n_global = 0usize;
    let mut errored_global = vec![];
    let mut result_global = None;

    if opts.update {
        if !opts.force {
            packages.retain(|p| {
                let cfg = configuration.get(&p.name);
                p.needs_update(cfg.as_ref().and_then(|c| c.target_version.as_ref()),
                               cfg.as_ref().and_then(|c| c.install_prereleases))
            });
        }

        packages.retain(|pkg| pkg.update_to_version().is_some());

        if !packages.is_empty() {
            let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                .map(|package| -> Result<(), (i32, String)> {
                    println!("{} {}",
                             if package.version.is_some() {
                                 "Updating"
                             } else {
                                 "Installing"
                             },
                             package.name);

                    if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                        save_cargo_update_exec(package.version.as_ref().unwrap());
                    }

                    let install_res = if let Some(cfg) = configuration.get(&package.name) {
                            Command::new("cargo")
                                .args(&cfg.cargo_args()[..])
                                .arg("--vers")
                                .arg(if let Some(tv) = cfg.target_version.as_ref() {
                                    tv.to_string()
                                } else {
                                    package.update_to_version().unwrap().to_string()
                                })
                                .arg(&package.name)
                                .status()
                        } else {
                            Command::new("cargo")
                                .arg("install")
                                .arg("-f")
                                .arg(&package.name)
                                .arg("--vers")
                                .arg(package.update_to_version().unwrap().to_string())
                                .status()
                        }
                        .unwrap();

                    println!();
                    if !install_res.success() {
                        if cfg!(target_os = "windows") && package.version.is_some() && package.name == "cargo-update" {
                            restore_cargo_update_exec(package.version.as_ref().unwrap());
                        }

                        Err((install_res.code().unwrap_or(-1), package.name))
                    } else {
                        Ok(())
                    }
                })
                .fold((0, vec![], None), |(s, mut e, r), p| match p {
                    Ok(()) => (s + 1, e, r),
                    Err((pr, pn)) => {
                        e.push(pn);
                        (s, e, r.or_else(|| Some(pr)))
                    }
                });

            success_n_global += success_n;

            println!();
            println!("Updated {} package{}.", success_n, if success_n == 1 { "" } else { "s" });
            if !errored.is_empty() && result.is_some() {
                print!("Failed to update ");
                for (i, e) in errored.iter().enumerate() {
                    if i != 0 {
                        print!(", ");
                    }
                    print!("{}", e);
                }
                println!(".");
                println!();

                if opts.update_git {
                    errored_global = errored;
                    result_global = result;
                } else {
                    return Err(result.unwrap());
                }
            }
        } else {
            println!("No packages need updating.");
        }
    }

    if opts.update_git {
        let mut packages = installed_git_packages;

        if !opts.filter.is_empty() {
            packages.retain(|p| configuration.get(&p.name).map(|p_cfg| opts.filter.iter().all(|f| f.matches(p_cfg))).unwrap_or(false));
        }
        if !opts.all {
            packages.retain(|p| opts.to_update.iter().any(|u| p.name == u.0));
        }

        let git_db_dir = crates_file.with_file_name("git").join("db");
        for package in &mut packages {
            package.pull_version(&opts.temp_dir.1, &git_db_dir, http_proxy.as_ref().map(String::as_str));
        }

        {
            let mut out = TabWriter::new(stdout());
            writeln!(out, "Package\tInstalled\tLatest\tNeeds update").unwrap();
            for package in packages.iter()
                .sorted_by(|lhs, rhs| (!lhs.needs_update(), &lhs.name).cmp(&(!rhs.needs_update(), &rhs.name))) {
                writeln!(out,
                         "{}\t{}\t{}\t{}",
                         package.name,
                         package.id,
                         package.newest_id.as_ref().unwrap(),
                         if package.needs_update() { "Yes" } else { "No" })
                    .unwrap();
            }
            writeln!(out).unwrap();
            out.flush().unwrap();
        }

        if opts.update {
            if !opts.force {
                packages.retain(cargo_update::ops::GitRepoPackage::needs_update);
            }

            if !packages.is_empty() {
                let (success_n, errored, result): (usize, Vec<String>, Option<i32>) = packages.into_iter()
                    .map(|package| -> Result<(), (i32, String)> {
                        println!("Updating {} from {}", package.name, package.url);

                        if cfg!(target_os = "windows") && package.name == "cargo-update" {
                            save_cargo_update_exec(&package.id.to_string());
                        }

                        let install_res = if let Some(cfg) = configuration.get(&package.name) {
                                let mut cmd = Command::new("cargo");
                                cmd.args(&cfg.cargo_args()[..])
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            } else {
                                let mut cmd = Command::new("cargo");
                                cmd.arg("install")
                                    .arg("-f")
                                    .arg("--git")
                                    .arg(&package.url)
                                    .arg(&package.name);
                                if let Some(ref b) = package.branch.as_ref() {
                                    cmd.arg("--branch").arg(b);
                                }
                                cmd.status()
                            }
                            .unwrap();

                        println!();
                        if !install_res.success() {
                            if cfg!(target_os = "windows") && package.name == "cargo-update" {
                                restore_cargo_update_exec(&package.id.to_string());
                            }

                            Err((install_res.code().unwrap_or(-1), package.name))
                        } else {
                            Ok(())
                        }
                    })
                    .fold((0, vec![], None), |(s, mut e, r), p| match p {
                        Ok(()) => (s + 1, e, r),
                        Err((pr, pn)) => {
                            e.push(pn);
                            (s, e, r.or_else(|| Some(pr)))
                        }
                    });

                success_n_global += success_n;

                println!();
                println!("Updated {} git package{}.", success_n, if success_n == 1 { "" } else { "s" });
                if !errored.is_empty() && result.is_some() {
                    print!("Failed to update ");
                    for (i, e) in errored.iter().enumerate() {
                        if i != 0 {
                            print!(", ");
                        }
                        print!("{}", e);
                    }
                    println!(".");
                    println!();

                    errored_global.extend(errored);

                    if result_global.is_none() {
                        return Err(result.unwrap());
                    }
                }
            } else {
                println!("No git packages need updating.");
            }
        }
    }

    if opts.update {
        println!("Overall updated {} package{}.", success_n_global, if success_n_global == 1 { "" } else { "s" });

        if !errored_global.is_empty() && result_global.is_some() {
            print!("Overall failed to update ");
            for (i, e) in errored_global.iter().enumerate() {
                if i != 0 {
                    print!(", ");
                }
                print!("{}", e);
            }
            println!(".");

            return Err(result_global.unwrap());
        }
    }

    Ok(())
}

/// This way the past-current exec will be "replaced" and we'll get no dupes in .cargo.toml
#[cfg(target_os="windows")]
fn save_cargo_update_exec<D: Display>(version: &D) {
    save_cargo_update_exec_impl(format!("exe-v{}", version));
}

#[cfg(target_os="windows")]
fn save_cargo_update_exec_impl(extension: String) {
    let cur_exe = env::current_exe().unwrap();
    fs::rename(&cur_exe, cur_exe.with_extension(extension)).unwrap();
    File::create(cur_exe).unwrap();
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec<D: Display>(version: &D) {
    restore_cargo_update_exec_impl(format!("exe-v{}", version))
}

#[cfg(target_os="windows")]
fn restore_cargo_update_exec_impl(extension: String) {
    let cur_exe = env::current_exe().unwrap();
    fs::remove_file(&cur_exe).unwrap();
    fs::rename(cur_exe.with_extension(extension), cur_exe).unwrap();
}

#[cfg(not(target_os="windows"))]
fn save_cargo_update_exec<D: Display>(_: &D) {}

#[cfg(not(target_os="windows"))]
fn restore_cargo_update_exec<D: Display>(_: &D) {}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::io;
use std::io::prelude::*;
use std::thread;
use std::str;
use irc::IrcReader;
use irc::IrcWriter;
use irc::IrcMessage;

extern crate openssl;
use openssl::ssl::*;

mod irc;

fn main() {
	let connection_result = TcpStream::connect("127.0.0.1:6697");
	if connection_result.is_err() {
		return;
	}

	let connection = connection_result.unwrap();
	let ssl_context = SslContext::new(SslMethod::Sslv23);
	let ssl_stream = SslStream::new(&ssl_context.unwrap(), connection).unwrap();
	let reader_connection = ssl_stream.try_clone().unwrap();
	let reader = IrcReader::new(reader_connection);
	let writer_connection = ssl_stream.try_clone().unwrap();
	let mut writer = IrcWriter::new(writer_connection);

	thread::spawn(move || {
		let stdin = io::stdin();
		let stdin_lock = stdin.lock();
		for in_line in stdin_lock.lines() {
			let _ = in_line.and_then(|x| {

                match str::from_utf8(x.as_bytes()).unwrap() {
                    "user" => {
                        writer.write(IrcMessage::test_user().message());
                        writer.write(b"\r\n");
                        writer.write(IrcMessage::test_nick().message());
                        writer.write(b"\r\n");
                    },
                    _ => {
                        writer.write(x.as_bytes());
                        writer.write(b"\r\n");
                    }
                }
				Ok(x)
			});
		}
	});

	for irc_msg in reader {
		parse_command(&irc_msg.message());
	}
}

fn parse_command(command: &[u8]) {
	let command_str = str::from_utf8(command);
	if command_str.is_err() {
		return;
	}
	println!("{}", command_str.unwrap());
}
<commit_msg>Fix whitespace<commit_after>use std::net::TcpStream;
use std::io;
use std::io::prelude::*;
use std::thread;
use std::str;
use irc::IrcReader;
use irc::IrcWriter;
use irc::IrcMessage;

extern crate openssl;
use openssl::ssl::*;

mod irc;

fn main() {
    let connection_result = TcpStream::connect("127.0.0.1:6697");
    if connection_result.is_err() {
        return;
    }

    let connection = connection_result.unwrap();
    let ssl_context = SslContext::new(SslMethod::Sslv23);
    let ssl_stream = SslStream::new(&ssl_context.unwrap(), connection).unwrap();
    let reader_connection = ssl_stream.try_clone().unwrap();
    let reader = IrcReader::new(reader_connection);
    let writer_connection = ssl_stream.try_clone().unwrap();
    let mut writer = IrcWriter::new(writer_connection);

    thread::spawn(move || {
        let stdin = io::stdin();
        let stdin_lock = stdin.lock();
        for in_line in stdin_lock.lines() {
            let _ = in_line.and_then(|x| {

                match str::from_utf8(x.as_bytes()).unwrap() {
                    "user" => {
                        writer.write(IrcMessage::test_user().message());
                        writer.write(b"\r\n");
                        writer.write(IrcMessage::test_nick().message());
                        writer.write(b"\r\n");
                    },
                    _ => {
                        writer.write(x.as_bytes());
                        writer.write(b"\r\n");
                    }
                }
                Ok(x)
            });
        }
    });

    for irc_msg in reader {
        parse_command(&irc_msg.message());
    }
}

fn parse_command(command: &[u8]) {
    let command_str = str::from_utf8(command);
    if command_str.is_err() {
        return;
    }
    println!("{}", command_str.unwrap());
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate num;

use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let memory = Memory::new();
    let mut cpu = Cpu::new(memory);

    loop {
        let clock_cycle = cpu.tick();
    }
}

<commit_msg>Removed whitespace from main.rs<commit_after>#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate num;

use memory::Memory;
use cpu::Cpu;

mod memory;
mod ops;
mod extensions;
mod cpu;

fn main() {
    let memory = Memory::new();
    let mut cpu = Cpu::new(memory);

    loop {
        let clock_cycle = cpu.tick();
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::fs::File;
use std::env;

extern crate chrono;
use chrono::*;

extern crate aggregated_stats;

#[macro_use]
extern crate clap;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate prometheus;
extern crate hyper;

mod analyzer;
mod args;
mod filter;
mod log_parser;
use log_parser::log_events::*;
mod render;
mod request_response_matcher;
mod http_handler;
mod result;

fn main() {
    env_logger::init().expect("Failed to initialize logging.");

    let args = args::parse_args(env::args()).expect("Failed to parse arguments.");

    let result = run(&args);

    let mut stream;
    let mut renderers: Vec<Box<render::Renderer>>;
    renderers = vec![];

    renderers.push(Box::new(render::TerminalRenderer::new()));

    if args.graphite_server.is_some() {
        stream = TcpStream::connect((args.graphite_server.as_ref().unwrap().as_str(),
                                     args.graphite_port.unwrap()))
            .expect("Could not connect to the Graphite server");

        renderers.push(Box::new(render::graphite::GraphiteRenderer::new(UTC::now(),
                                                                        args.graphite_prefix
                                                                            .clone(),
                                                                        &mut stream)));
    }

    if args.influxdb_write_url.is_some() {
        renderers.push(Box::new(render::influxdb::InfluxDbRenderer::new(args.influxdb_write_url
                                                                            .clone()
                                                                            .unwrap(),
                                                                        args.influxdb_tags
                                                                            .clone())));
    }

    for mut renderer in renderers {
        renderer.render(result.clone());
    }

    if args.prometheus_listen.is_some() {
        let binding_address = args.prometheus_listen.clone().unwrap();
        http_handler::listen_http(args, &binding_address);
    }
}

fn run(args: &args::RequestLogAnalyzerArgs) -> result::RequestLogAnalyzerResult {
    let input: Box<io::Read> = match args.filename.as_ref() {
        "-" => Box::new(io::stdin()),
        _ => Box::new(File::open(&args.filename).expect("Failed to open file.")),
    };

    let reader = io::BufReader::new(input);

    let mut events_iterator = reader.lines()
        .map(log_parser::parse_line)
        .filter(|event| event.is_ok())
        .map(|event| event.unwrap());

    let pairs_iterator =
        request_response_matcher::RequestResponsePairIterator::new(&mut events_iterator)
            .filter(|pair| filter::matches_filter(pair, &args.conditions));

    analyzer::analyze_iterator(pairs_iterator)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run() {
        let args = args::RequestLogAnalyzerArgs {
            filename: String::from("src/test/simple-1.log"),
            conditions: filter::FilterConditions {
                include_terms: None,
                exclude_terms: None,
                latest_time: None,
            },
            graphite_server: None,
            graphite_port: Some(2003),
            graphite_prefix: None,
            prometheus_listen: None,
            influxdb_write_url: None,
            influxdb_tags: None,
        };

        let result = run(&args);
        assert_eq!(result.count, 2);

        let timing = result.timing.unwrap();
        assert_eq!(timing.min, 7);
        assert_eq!(timing.max, 10);

        assert!(result.error.is_some());
    }

    #[test]
    fn test_run_ignore_broken_lines() {
        let args = args::RequestLogAnalyzerArgs {
            filename: String::from("src/test/broken.log"),
            conditions: filter::FilterConditions {
                include_terms: None,
                exclude_terms: None,
                latest_time: None,
            },
            graphite_server: None,
            graphite_port: Some(2003),
            graphite_prefix: None,
            prometheus_listen: None,
            influxdb_write_url: None,
            influxdb_tags: None,
        };

        let result = run(&args);
        assert_eq!(result.count, 1);
    }
}
<commit_msg>Clean up imports<commit_after>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::fs::File;
use std::env;

extern crate chrono;
use chrono::*;

extern crate aggregated_stats;

#[macro_use]
extern crate clap;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate prometheus;
extern crate hyper;

mod analyzer;
mod args;
mod filter;
mod log_parser;
mod render;
mod request_response_matcher;
mod http_handler;
mod result;

fn main() {
    env_logger::init().expect("Failed to initialize logging.");

    let args = args::parse_args(env::args()).expect("Failed to parse arguments.");

    let result = run(&args);

    let mut stream;
    let mut renderers: Vec<Box<render::Renderer>>;
    renderers = vec![];

    renderers.push(Box::new(render::TerminalRenderer::new()));

    if args.graphite_server.is_some() {
        stream = TcpStream::connect((args.graphite_server.as_ref().unwrap().as_str(),
                                     args.graphite_port.unwrap()))
            .expect("Could not connect to the Graphite server");

        renderers.push(Box::new(render::graphite::GraphiteRenderer::new(UTC::now(),
                                                                        args.graphite_prefix
                                                                            .clone(),
                                                                        &mut stream)));
    }

    if args.influxdb_write_url.is_some() {
        renderers.push(Box::new(render::influxdb::InfluxDbRenderer::new(args.influxdb_write_url
                                                                            .clone()
                                                                            .unwrap(),
                                                                        args.influxdb_tags
                                                                            .clone())));
    }

    for mut renderer in renderers {
        renderer.render(result.clone());
    }

    if args.prometheus_listen.is_some() {
        let binding_address = args.prometheus_listen.clone().unwrap();
        http_handler::listen_http(args, &binding_address);
    }
}

fn run(args: &args::RequestLogAnalyzerArgs) -> result::RequestLogAnalyzerResult {
    let input: Box<io::Read> = match args.filename.as_ref() {
        "-" => Box::new(io::stdin()),
        _ => Box::new(File::open(&args.filename).expect("Failed to open file.")),
    };

    let reader = io::BufReader::new(input);

    let mut events_iterator = reader.lines()
        .map(log_parser::parse_line)
        .filter(|event| event.is_ok())
        .map(|event| event.unwrap());

    let pairs_iterator =
        request_response_matcher::RequestResponsePairIterator::new(&mut events_iterator)
            .filter(|pair| filter::matches_filter(pair, &args.conditions));

    analyzer::analyze_iterator(pairs_iterator)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run() {
        let args = args::RequestLogAnalyzerArgs {
            filename: String::from("src/test/simple-1.log"),
            conditions: filter::FilterConditions {
                include_terms: None,
                exclude_terms: None,
                latest_time: None,
            },
            graphite_server: None,
            graphite_port: Some(2003),
            graphite_prefix: None,
            prometheus_listen: None,
            influxdb_write_url: None,
            influxdb_tags: None,
        };

        let result = run(&args);
        assert_eq!(result.count, 2);

        let timing = result.timing.unwrap();
        assert_eq!(timing.min, 7);
        assert_eq!(timing.max, 10);

        assert!(result.error.is_some());
    }

    #[test]
    fn test_run_ignore_broken_lines() {
        let args = args::RequestLogAnalyzerArgs {
            filename: String::from("src/test/broken.log"),
            conditions: filter::FilterConditions {
                include_terms: None,
                exclude_terms: None,
                latest_time: None,
            },
            graphite_server: None,
            graphite_port: Some(2003),
            graphite_prefix: None,
            prometheus_listen: None,
            influxdb_write_url: None,
            influxdb_tags: None,
        };

        let result = run(&args);
        assert_eq!(result.count, 1);
    }
}
<|endoftext|>


<commit_before>use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:12043").unwrap();

    let mut buf = [0; 10];
    let (amt, src) = socket.recv_from(&mut buf).unwrap();

    let buf = &mut buf[..amt];
    socket.send_to(buf, &src).unwrap();

    drop(socket);
}
<commit_msg>Implement reading and writing dns header message<commit_after>use std::net::UdpSocket;

struct Message {
    id: u16, // 2 bytes
    query_response: u16, // 1 bit
    operation_code: u16, // 4 bits
    authoritative_answer: u16, // 1 bit
    truncation_flag: u16, // 1 bit
    recursion_desired: u16, // 1 bit
    recursion_available: u16, // 1 bit
    unused: u16, // 3 bits
    error_code: u16, // 4 bits
    question_count: u16, // 2 bytes
    answer_count: u16, // 2 bytes
    ns_count: u16, // 2 bytes
    ar_count: u16, // 2 bytes
}

fn unpack(buffer: &[u8]) -> Message {
    let id: u16 = (buffer[0] as u16) << 8 | buffer[1] as u16;
    let body: u16 = (buffer[2] as u16) << 8 | buffer[3] as u16;
    let question_count: u16 = (buffer[4] as u16) << 8 | buffer[5] as u16;
    let answer_count: u16 = (buffer[6] as u16) << 8 | buffer[7] as u16;
    let ns_count: u16 = (buffer[8] as u16) << 8 | buffer[9] as u16;
    let ar_count: u16 = (buffer[10] as u16) << 8 | buffer[11] as u16;

    Message {
        id: id,
        query_response: (body & (1 << 15)) >> 15,
        operation_code: (body & (15 << 11)) >> 11,
        authoritative_answer: (body & (1 >> 10)) >> 10,
        truncation_flag: (body & (1 >> 9)) >> 9,
        recursion_desired: (body & (1 >> 8)) >> 8,
        recursion_available: (body & (1 >> 7)) >> 7,
        unused: (body & (7 << 4)) >> 4,
        error_code: (body & (15 << 0)) >> 0,
        question_count: question_count,
        answer_count: answer_count,
        ns_count: ns_count,
        ar_count: ar_count,
    }
}

fn pack(message: &Message) -> Vec<u8> {
    let mut buffer: Vec<u8> = Vec::new();

    buffer.push((message.id >> 8) as u8);
    buffer.push(message.id as u8);

    let mut body: u16 = 0;

    body = body | message.query_response << 15;
    body = body | message.operation_code << 11;
    body = body | message.authoritative_answer << 10;
    body = body | message.truncation_flag << 9;
    body = body | message.recursion_desired << 8;
    body = body | message.recursion_available << 7;
    body = body | message.unused << 4;
    body = body | message.error_code;

    buffer.push((body >> 8) as u8);
    buffer.push(body as u8);

    buffer.push((message.question_count >> 8) as u8);
    buffer.push(message.question_count as u8);

    buffer.push((message.answer_count >> 8) as u8);
    buffer.push(message.answer_count as u8);

    buffer.push((message.ns_count >> 8) as u8);
    buffer.push(message.ns_count as u8);

    buffer.push((message.ar_count >> 8) as u8);
    buffer.push(message.ar_count as u8);

    buffer
}

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:12043").unwrap();

    let mut buffer: [u8; 512] = [0; 512];
    let (size, source) = socket.recv_from(&mut buffer).unwrap();

    let query_message = unpack(&buffer[..size]);

    let answer_message = Message { query_response: 1, ..query_message };

    let result = pack(&answer_message);

    socket.send_to(&result, &source).unwrap();

    drop(socket);
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate rustc_serialize;

#[macro_use]
extern crate rouille;

mod alsa_input;
mod async_input;
mod base;
mod control;
mod file_input;
mod filters;
mod input_device;
mod input;
mod light;
mod output;
mod pipe_input;
mod resampler;
mod state_script;
mod ui;
mod web_ui;

use base::*;
use input::Input;
use getopts::Options;
use std::env;
use std::time::{Instant, Duration};
use filters::*;

impl From<getopts::Fail> for Error {
    fn from(e: getopts::Fail) -> Error {
        Error::new(&e.to_string())
    }
}

struct InputMixer {
    input: Box<Input>,
    current_frame: Option<Frame>,
    current_frame_pos: usize,
    volume: ui::Gain,
    gain: ui::Gain,
    multiplier: f32,
}

impl InputMixer {
    fn new(input: Box<Input>) -> InputMixer {
        let mut r = InputMixer {
            input: input,
            current_frame: None,
            current_frame_pos: 0,
            volume: ui::Gain { db: -20.0 },
            gain: ui::Gain { db: 0.0 },
            multiplier: 1.0,
        };
        r.update_multiplier();
        r
    }

    fn set_input_gain(&mut self, input_gain: ui::Gain) {
        self.gain = input_gain;
        self.update_multiplier();
    }

    fn set_master_volume(&mut self, volume: ui::Gain) {
        self.volume = volume;
        self.update_multiplier();
    }

    fn update_multiplier(&mut self) {
        self.multiplier = 10f32.powf((self.volume.db + self.gain.db) / 20.0);
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame) -> Result<bool> {
        for i in 0..mixed_frame.len() {
            if self.current_frame.is_none() {
                self.current_frame = try!(self.input.read());
                self.current_frame_pos = 0;
            }

            let reset: bool;
            match self.current_frame {
                None => return Ok(i > 0),
                Some(ref frame) => {
                    mixed_frame.left[i] += self.multiplier * frame.left[self.current_frame_pos];
                    mixed_frame.right[i] += self.multiplier * frame.right[self.current_frame_pos];
                    self.current_frame_pos += 1;
                    reset = self.current_frame_pos >= frame.len();
                }
            }
            if reset {
                self.current_frame = None;
            }
        }

        if self.input.is_synchronized() {
            while try!(self.input.samples_buffered()) > MAX_QUEUED_FRAMES * mixed_frame.len() {
                let len = try!(self.input.read()).unwrap().len();
                println!("DROPPED {}, left {}",
                         len,
                         try!(self.input.samples_buffered()));
            }
        }

        Ok(true)
    }
}

const OUTPUT_SHUTDOWN_SECONDS: u64 = 5;
const STANDBY_SECONDS: u64 = 3600;

fn run_loop(mut inputs: Vec<Box<Input>>,
            mut outputs: Vec<Box<output::Output>>,
            sample_rate: usize,
            shared_state: ui::SharedState,
            mut drc_filter: Option<StereoFilter<FirFilter>>)
            -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = inputs
        .drain(..)
        .map(|i| Box::new(InputMixer::new(i)))
        .collect();

    let mut state = ui::StreamState::Active;
    let mut last_data_time = Instant::now();
    let mut selected_output = 0;

    let mut loudness_filter =
        StereoFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut voice_boost_filter: Option<StereoFilter<VoiceBoostFilter>> = None;
    let mut crossfeed_filter = CrossfeedFilter::new();

    let mut exclusive_mux_mode = true;
    let mut enable_drc = true;

    loop {
        let mut frame = Frame::new(sample_rate, outputs[selected_output].period_size());

        let mut have_data = false;
        for m in mixers.iter_mut() {
            have_data |= try!(m.mix_into(&mut frame));
            if have_data && exclusive_mux_mode {
                break;
            }
        }

        let now = Instant::now();
        if have_data {
            last_data_time = now;
        }

        let new_state = match (have_data, (now - last_data_time).as_secs()) {
            (true, _) => ui::StreamState::Active,
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            frame = loudness_filter.apply(&frame);
            match voice_boost_filter.as_mut() {
                Some(ref mut f) => {
                    frame = f.apply(&frame);
                }
                None => (),
            }
            frame = crossfeed_filter.apply(frame);

            match (enable_drc, drc_filter.as_mut()) {
                (true, Some(ref mut f)) => {
                    frame = f.apply(&frame);
                }
                _ => (),
            }

            try!(outputs[selected_output].write(&frame));
        } else {
            std::thread::sleep(Duration::from_millis(500));
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    for i in mixers.iter_mut() {
                        i.set_master_volume(volume)
                    }
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_input_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable } => {
                    enable_drc = enable
                }
                ui::UiMessage::SetVoiceBoost { boost } => {
                    if boost.db > 0.0 {
                        let p = SimpleFilterParams::new(sample_rate, boost.db);
                        if voice_boost_filter.is_some() {
                            voice_boost_filter.as_mut().unwrap().set_params(p);
                        } else {
                            voice_boost_filter = Some(StereoFilter::<VoiceBoostFilter>::new(
                            SimpleFilterParams::new(sample_rate, boost.db)))
                        }
                    } else {
                        voice_boost_filter = None
                    }
                }
                ui::UiMessage::SetCrossfeed { level, delay_ms } => {
                    crossfeed_filter.set_params(level, delay_ms);
                }
                ui::UiMessage::SetMuxMode { mux_mode: ui::MuxMode::Exclusive } => {
                    exclusive_mux_mode = true;
                }
                ui::UiMessage::SetMuxMode { mux_mode: ui::MuxMode::Mixer } => {
                    exclusive_mux_mode = false;
                }
            }
        }
    }
}

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

fn run() -> Result<()> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optmulti("i", "input", "Audio input device name", "INPUT");
    opts.optmulti("f", "input-file", "Input file name", "FILE");
    opts.optmulti("p", "input-pipe", "Input pipe name", "PIPE");
    opts.optmulti("o", "output", "Output device name", "OUTPUT");
    opts.optopt("r", "sample-rate", "Output sample rate", "RATE");
    opts.optopt("w", "web-address", "Address:port for web UI", "ADDRESS");
    opts.optopt("s",
                "state-script",
                "Script to run on state change",
                "SCRIPT");
    opts.optmulti("c", "control-device", "Control input device", "INPUT_DEV");
    opts.optmulti("l", "light-device", "Light device", "LIGHT_DEV");
    opts.optmulti("F", "filter", "FIR filter file", "FIR_FILTER");
    opts.optflag("g", "loudness-graph", "Print out loudness graph");
    opts.optflag("h", "help", "Print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return Ok(());
    }

    let mut inputs = Vec::<Box<Input>>::new();
    let mut input_states = Vec::<ui::InputState>::new();

    let output_rate = match matches.opt_str("r").map(|x| x.parse::<usize>()) {
        None => 88200,
        Some(Ok(rate)) => rate,
        Some(Err(_)) => return Err(Error::new("Cannot parse sample-rate parameter.")),
    };

    if matches.opt_present("g") {
        filters::draw_filter_graph::<VoiceBoostFilter>(SimpleFilterParams::new(88100, 10.0));
        return Ok(());
    }

    for f in matches.opt_strs("f") {
        inputs.push(Box::new(try!(file_input::FileInput::open(&f))));
        input_states.push(ui::InputState::new(&f));
    }

    for p in matches.opt_strs("p") {
        inputs.push(Box::new(pipe_input::PipeInput::open(&p)));
        input_states.push(ui::InputState::new(&p));
    }

    for i in matches.opt_strs("i") {
        inputs.push(Box::new(alsa_input::ResilientAlsaInput::new(&i)));
        input_states.push(ui::InputState::new(&i));
    }

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return Ok(());
    }

    if inputs.is_empty() {
        return Err(Error::new("No inputs specified."));
    }

    let mut outputs = Vec::<Box<output::Output>>::new();
    let mut output_states = Vec::<ui::OutputState>::new();

    for o in matches.opt_strs("o") {
        outputs.push(Box::new(output::ResilientAlsaOutput::new(&o, output_rate)));
        output_states.push(ui::OutputState::new(&o));
    }

    let shared_state = ui::SharedState::new(input_states, output_states);

    let web_addr = match matches.opt_str("w") {
        Some(addr) => addr,
        None => String::from("127.0.0.1:8000"),
    };
    web_ui::start_web(&web_addr, shared_state.clone());

    for c in matches.opt_strs("c") {
        control::start_input_handler(&c, shared_state.clone());
    }

    for l in matches.opt_strs("l") {
        light::start_light_controller(&l, shared_state.clone());
    }

    for s in matches.opt_strs("s") {
        state_script::start_state_script_contoller(&s, shared_state.clone());
    }

    let mut fir_filters = Vec::new();
    for filename in matches.opt_strs("F") {
        let params = try!(FirFilterParams::new(&filename));
        fir_filters.push(params.reduce(1000));
    }

    let drc_filter = if fir_filters.len() == 0 {
        None
    } else if fir_filters.len() == 2 {
        Some(StereoFilter::<FirFilter>::new_pair(fir_filters[0].clone(), fir_filters[1].clone()))
    } else {
        return Err(Error::new("Expected 0 or 2 FIR filters"))
    };

    let wrapped_inputs = inputs
        .drain(..)
        .map(|input| {
              Box::<async_input::AsyncInput>::new(async_input::AsyncInput::new(
                Box::new(input::InputResampler::new(input, output_rate))))
              as Box<Input>
          })
        .collect();

    run_loop(wrapped_inputs, outputs, output_rate, shared_state, drc_filter)
}

fn main() {
    match run() {
        Err(e) => {
            println!("{}", e);
            std::process::exit(-1);
        }
        Ok(_) => (),
    }
}
<commit_msg>Added filter lenght option<commit_after>extern crate getopts;
extern crate rustc_serialize;

#[macro_use]
extern crate rouille;

mod alsa_input;
mod async_input;
mod base;
mod control;
mod file_input;
mod filters;
mod input_device;
mod input;
mod light;
mod output;
mod pipe_input;
mod resampler;
mod state_script;
mod ui;
mod web_ui;

use base::*;
use input::Input;
use getopts::Options;
use std::env;
use std::time::{Instant, Duration};
use filters::*;

impl From<getopts::Fail> for Error {
    fn from(e: getopts::Fail) -> Error {
        Error::new(&e.to_string())
    }
}

struct InputMixer {
    input: Box<Input>,
    current_frame: Option<Frame>,
    current_frame_pos: usize,
    volume: ui::Gain,
    gain: ui::Gain,
    multiplier: f32,
}

impl InputMixer {
    fn new(input: Box<Input>) -> InputMixer {
        let mut r = InputMixer {
            input: input,
            current_frame: None,
            current_frame_pos: 0,
            volume: ui::Gain { db: -20.0 },
            gain: ui::Gain { db: 0.0 },
            multiplier: 1.0,
        };
        r.update_multiplier();
        r
    }

    fn set_input_gain(&mut self, input_gain: ui::Gain) {
        self.gain = input_gain;
        self.update_multiplier();
    }

    fn set_master_volume(&mut self, volume: ui::Gain) {
        self.volume = volume;
        self.update_multiplier();
    }

    fn update_multiplier(&mut self) {
        self.multiplier = 10f32.powf((self.volume.db + self.gain.db) / 20.0);
    }

    fn mix_into(&mut self, mixed_frame: &mut Frame) -> Result<bool> {
        for i in 0..mixed_frame.len() {
            if self.current_frame.is_none() {
                self.current_frame = try!(self.input.read());
                self.current_frame_pos = 0;
            }

            let reset: bool;
            match self.current_frame {
                None => return Ok(i > 0),
                Some(ref frame) => {
                    mixed_frame.left[i] += self.multiplier * frame.left[self.current_frame_pos];
                    mixed_frame.right[i] += self.multiplier * frame.right[self.current_frame_pos];
                    self.current_frame_pos += 1;
                    reset = self.current_frame_pos >= frame.len();
                }
            }
            if reset {
                self.current_frame = None;
            }
        }

        if self.input.is_synchronized() {
            while try!(self.input.samples_buffered()) > MAX_QUEUED_FRAMES * mixed_frame.len() {
                let len = try!(self.input.read()).unwrap().len();
                println!("DROPPED {}, left {}",
                         len,
                         try!(self.input.samples_buffered()));
            }
        }

        Ok(true)
    }
}

const OUTPUT_SHUTDOWN_SECONDS: u64 = 5;
const STANDBY_SECONDS: u64 = 3600;

fn run_loop(mut inputs: Vec<Box<Input>>,
            mut outputs: Vec<Box<output::Output>>,
            sample_rate: usize,
            shared_state: ui::SharedState,
            mut drc_filter: Option<StereoFilter<FirFilter>>)
            -> Result<()> {
    let ui_channel = shared_state.lock().add_observer();

    let mut mixers: Vec<Box<InputMixer>> = inputs
        .drain(..)
        .map(|i| Box::new(InputMixer::new(i)))
        .collect();

    let mut state = ui::StreamState::Active;
    let mut last_data_time = Instant::now();
    let mut selected_output = 0;

    let mut loudness_filter =
        StereoFilter::<LoudnessFilter>::new(SimpleFilterParams::new(sample_rate, 10.0));
    let mut voice_boost_filter: Option<StereoFilter<VoiceBoostFilter>> = None;
    let mut crossfeed_filter = CrossfeedFilter::new();

    let mut exclusive_mux_mode = true;
    let mut enable_drc = true;

    loop {
        let mut frame = Frame::new(sample_rate, outputs[selected_output].period_size());

        let mut have_data = false;
        for m in mixers.iter_mut() {
            have_data |= try!(m.mix_into(&mut frame));
            if have_data && exclusive_mux_mode {
                break;
            }
        }

        let now = Instant::now();
        if have_data {
            last_data_time = now;
        }

        let new_state = match (have_data, (now - last_data_time).as_secs()) {
            (true, _) => ui::StreamState::Active,
            (false, t) if t < OUTPUT_SHUTDOWN_SECONDS => ui::StreamState::Active,
            (false, t) if t < STANDBY_SECONDS => ui::StreamState::Inactive,
            (false, _) => ui::StreamState::Standby,
        };

        if state != new_state {
            state = new_state;
            println!("INFO: state: {}", state.as_str());
            shared_state.lock().on_stream_state(state);
            if state != ui::StreamState::Active {
                for ref mut out in &mut outputs {
                    out.deactivate();
                }
            }
        }

        if state == ui::StreamState::Active {
            frame = loudness_filter.apply(&frame);
            match voice_boost_filter.as_mut() {
                Some(ref mut f) => {
                    frame = f.apply(&frame);
                }
                None => (),
            }
            frame = crossfeed_filter.apply(frame);

            match (enable_drc, drc_filter.as_mut()) {
                (true, Some(ref mut f)) => {
                    frame = f.apply(&frame);
                }
                _ => (),
            }

            try!(outputs[selected_output].write(&frame));
        } else {
            std::thread::sleep(Duration::from_millis(500));
        }

        for msg in ui_channel.try_iter() {
            match msg {
                ui::UiMessage::SelectOutput { output } => {
                    outputs[output].deactivate();
                    selected_output = output;
                }
                ui::UiMessage::SetMasterVolume { volume, loudness } => {
                    for i in mixers.iter_mut() {
                        i.set_master_volume(volume)
                    }
                    loudness_filter.set_params(SimpleFilterParams::new(sample_rate, loudness.db));
                }
                ui::UiMessage::SetInputGain { device, gain } => {
                    mixers[device as usize].set_input_gain(gain);
                }
                ui::UiMessage::SetEnableDrc { enable } => {
                    enable_drc = enable
                }
                ui::UiMessage::SetVoiceBoost { boost } => {
                    if boost.db > 0.0 {
                        let p = SimpleFilterParams::new(sample_rate, boost.db);
                        if voice_boost_filter.is_some() {
                            voice_boost_filter.as_mut().unwrap().set_params(p);
                        } else {
                            voice_boost_filter = Some(StereoFilter::<VoiceBoostFilter>::new(
                            SimpleFilterParams::new(sample_rate, boost.db)))
                        }
                    } else {
                        voice_boost_filter = None
                    }
                }
                ui::UiMessage::SetCrossfeed { level, delay_ms } => {
                    crossfeed_filter.set_params(level, delay_ms);
                }
                ui::UiMessage::SetMuxMode { mux_mode: ui::MuxMode::Exclusive } => {
                    exclusive_mux_mode = true;
                }
                ui::UiMessage::SetMuxMode { mux_mode: ui::MuxMode::Mixer } => {
                    exclusive_mux_mode = false;
                }
            }
        }
    }
}

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

fn run() -> Result<()> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optmulti("i", "input", "Audio input device name", "INPUT");
    opts.optmulti("f", "input-file", "Input file name", "FILE");
    opts.optmulti("p", "input-pipe", "Input pipe name", "PIPE");
    opts.optmulti("o", "output", "Output device name", "OUTPUT");
    opts.optopt("r", "sample-rate", "Output sample rate", "RATE");
    opts.optopt("w", "web-address", "Address:port for web UI", "ADDRESS");
    opts.optopt("s",
                "state-script",
                "Script to run on state change",
                "SCRIPT");
    opts.optmulti("c", "control-device", "Control input device", "INPUT_DEV");
    opts.optmulti("l", "light-device", "Light device", "LIGHT_DEV");
    opts.optmulti("F", "filter", "FIR filter file", "FIR_FILTER");
    opts.optopt("L", "filter-length", "Length for FIR filter (1000 by default)", "FILTER_LENGTH");
    opts.optflag("g", "loudness-graph", "Print out loudness graph");
    opts.optflag("h", "help", "Print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return Ok(());
    }

    let mut inputs = Vec::<Box<Input>>::new();
    let mut input_states = Vec::<ui::InputState>::new();

    let output_rate = match matches.opt_str("r").map(|x| x.parse::<usize>()) {
        None => 88200,
        Some(Ok(rate)) => rate,
        Some(Err(_)) => return Err(Error::new("Cannot parse sample-rate parameter.")),
    };

    if matches.opt_present("g") {
        filters::draw_filter_graph::<VoiceBoostFilter>(SimpleFilterParams::new(88100, 10.0));
        return Ok(());
    }

    for f in matches.opt_strs("f") {
        inputs.push(Box::new(try!(file_input::FileInput::open(&f))));
        input_states.push(ui::InputState::new(&f));
    }

    for p in matches.opt_strs("p") {
        inputs.push(Box::new(pipe_input::PipeInput::open(&p)));
        input_states.push(ui::InputState::new(&p));
    }

    for i in matches.opt_strs("i") {
        inputs.push(Box::new(alsa_input::ResilientAlsaInput::new(&i)));
        input_states.push(ui::InputState::new(&i));
    }

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return Ok(());
    }

    if inputs.is_empty() {
        return Err(Error::new("No inputs specified."));
    }

    let mut outputs = Vec::<Box<output::Output>>::new();
    let mut output_states = Vec::<ui::OutputState>::new();

    for o in matches.opt_strs("o") {
        outputs.push(Box::new(output::ResilientAlsaOutput::new(&o, output_rate)));
        output_states.push(ui::OutputState::new(&o));
    }

    let shared_state = ui::SharedState::new(input_states, output_states);

    let web_addr = match matches.opt_str("w") {
        Some(addr) => addr,
        None => String::from("127.0.0.1:8000"),
    };
    web_ui::start_web(&web_addr, shared_state.clone());

    for c in matches.opt_strs("c") {
        control::start_input_handler(&c, shared_state.clone());
    }

    for l in matches.opt_strs("l") {
        light::start_light_controller(&l, shared_state.clone());
    }

    for s in matches.opt_strs("s") {
        state_script::start_state_script_contoller(&s, shared_state.clone());
    }

    let filter_length = match matches.opt_str("L").map(|x| x.parse::<usize>()) {
        None => 1000,
        Some(Ok(length)) => length,
        Some(Err(_)) => return Err(Error::new("Cannot parse filter length.")),
    };

    let mut fir_filters = Vec::new();
    for filename in matches.opt_strs("F") {
        let params = try!(FirFilterParams::new(&filename));
        fir_filters.push(params.reduce(filter_length));
    }

    let drc_filter = if fir_filters.len() == 0 {
        None
    } else if fir_filters.len() == 2 {
        Some(StereoFilter::<FirFilter>::new_pair(fir_filters[0].clone(), fir_filters[1].clone()))
    } else {
        return Err(Error::new("Expected 0 or 2 FIR filters"))
    };

    let wrapped_inputs = inputs
        .drain(..)
        .map(|input| {
              Box::<async_input::AsyncInput>::new(async_input::AsyncInput::new(
                Box::new(input::InputResampler::new(input, output_rate))))
              as Box<Input>
          })
        .collect();

    run_loop(wrapped_inputs, outputs, output_rate, shared_state, drc_filter)
}

fn main() {
    match run() {
        Err(e) => {
            println!("{}", e);
            std::process::exit(-1);
        }
        Ok(_) => (),
    }
}
<|endoftext|>