<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::FileHeaderParser;
use storage::file_id::*;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn from_parser_result(id: FileID, header: FileHeaderData, data: String) -> File {
        File {
            header: header,
            data: data,
            id: id,
        }
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_data(d: String) -> File {
        File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header.clone(), self.data.clone())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

<commit_msg>Implement Debug for File<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::FileHeaderParser;
use storage::file_id::*;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn from_parser_result(id: FileID, header: FileHeaderData, data: String) -> File {
        File {
            header: header,
            data: data,
            id: id,
        }
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_data(d: String) -> File {
        File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header.clone(), self.data.clone())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

impl Debug for File {

    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "File[{:?}] header: '{:?}', data: '{:?}')",
            self.id, self.header, self.data)
    }
}

<|endoftext|>


<commit_before>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type MoveType = usize;  // from 0 to 3
pub type CastlingRights = [(bool, bool); 2];  // (King-side, Queen-side)

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const QUEEN: PieceType = 0;
pub const ROOK: PieceType = 1;
pub const BISHOP: PieceType = 2;
pub const KNIGHT: PieceType = 3;
pub const KING: PieceType = 4;
pub const PAWN: PieceType = 5;

// Move types
pub const MOVE_NORMAL: MoveType = 0;
pub const MOVE_ENPASSANT: MoveType = 1;
pub const MOVE_PROMOTION: MoveType = 2;
pub const MOVE_CASTLING: MoveType = 3;

// Squares
pub const A1: Square = 0 + 0*8;
pub const B1: Square = 1 + 0*8;
pub const C1: Square = 2 + 0*8;
pub const D1: Square = 3 + 0*8;
pub const E1: Square = 4 + 0*8;
pub const F1: Square = 5 + 0*8;
pub const G1: Square = 6 + 0*8;
pub const H1: Square = 7 + 0*8;

pub const A2: Square = 0 + 1*8;
pub const B2: Square = 1 + 1*8;
pub const C2: Square = 2 + 1*8;
pub const D2: Square = 3 + 1*8;
pub const E2: Square = 4 + 1*8;
pub const F2: Square = 5 + 1*8;
pub const G2: Square = 6 + 1*8;
pub const H2: Square = 7 + 1*8;

pub const A3: Square = 0 + 2*8;
pub const B3: Square = 1 + 2*8;
pub const C3: Square = 2 + 2*8;
pub const D3: Square = 3 + 2*8;
pub const E3: Square = 4 + 2*8;
pub const F3: Square = 5 + 2*8;
pub const G3: Square = 6 + 2*8;
pub const H3: Square = 7 + 2*8;

pub const A4: Square = 0 + 3*8;
pub const B4: Square = 1 + 3*8;
pub const C4: Square = 2 + 3*8;
pub const D4: Square = 3 + 3*8;
pub const E4: Square = 4 + 3*8;
pub const F4: Square = 5 + 3*8;
pub const G4: Square = 6 + 3*8;
pub const H4: Square = 7 + 3*8;

pub const A5: Square = 0 + 4*8;
pub const B5: Square = 1 + 4*8;
pub const C5: Square = 2 + 4*8;
pub const D5: Square = 3 + 4*8;
pub const E5: Square = 4 + 4*8;
pub const F5: Square = 5 + 4*8;
pub const G5: Square = 6 + 4*8;
pub const H5: Square = 7 + 4*8;

pub const A6: Square = 0 + 5*8;
pub const B6: Square = 1 + 5*8;
pub const C6: Square = 2 + 5*8;
pub const D6: Square = 3 + 5*8;
pub const E6: Square = 4 + 5*8;
pub const F6: Square = 5 + 5*8;
pub const G6: Square = 6 + 5*8;
pub const H6: Square = 7 + 5*8;

pub const A7: Square = 0 + 6*8;
pub const B7: Square = 1 + 6*8;
pub const C7: Square = 2 + 6*8;
pub const D7: Square = 3 + 6*8;
pub const E7: Square = 4 + 6*8;
pub const F7: Square = 5 + 6*8;
pub const G7: Square = 6 + 6*8;
pub const H7: Square = 7 + 6*8;

pub const A8: Square = 0 + 7*8;
pub const B8: Square = 1 + 7*8;
pub const C8: Square = 2 + 7*8;
pub const D8: Square = 3 + 7*8;
pub const E8: Square = 4 + 7*8;
pub const F8: Square = 5 + 7*8;
pub const G8: Square = 6 + 7*8;
pub const H8: Square = 7 + 7*8;

pub struct Move(u16);

impl Move {
    #[inline]
    pub fn new(m_type: MoveType, orig: Square, dest: Square, pp_type: PieceType) -> Move {
        assert!(m_type <= 3);
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_type <= 3);
        Move( ((m_type << 14) | (pp_type << 12) | (orig << 6) | dest) as u16 )
    }

    #[inline]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & (0b11 << 14)) >> 14) as MoveType
    }

    #[inline]
    pub fn orig_square(&self) -> Square {
        (self.0 & (0b111111 << 6) >> 6) as Square
    }

    #[inline]
    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    #[inline]
    pub fn promotion_piece_type(&self) -> PieceType {
        (self.0 & (0b11 << 12) >> 12) as PieceType
    }
}

#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}

#[inline]
pub fn rank(square: Square) -> usize {
    square / 8
}

#[inline]
pub fn file(square: Square) -> usize {
    square % 8
}

<commit_msg>Added rank and file constants.<commit_after>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type MoveType = usize;  // from 0 to 3
pub type CastlingRights = [(bool, bool); 2];  // (King-side, Queen-side)

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const QUEEN: PieceType = 0;
pub const ROOK: PieceType = 1;
pub const BISHOP: PieceType = 2;
pub const KNIGHT: PieceType = 3;
pub const KING: PieceType = 4;
pub const PAWN: PieceType = 5;

// Move types
pub const MOVE_NORMAL: MoveType = 0;
pub const MOVE_ENPASSANT: MoveType = 1;
pub const MOVE_PROMOTION: MoveType = 2;
pub const MOVE_CASTLING: MoveType = 3;

// Ranks
pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

// Files
pub const FILE_A: Rank = 0;
pub const FILE_B: Rank = 1;
pub const FILE_C: Rank = 2;
pub const FILE_D: Rank = 3;
pub const FILE_E: Rank = 4;
pub const FILE_F: Rank = 5;
pub const FILE_G: Rank = 6;
pub const FILE_H: Rank = 7;

// Squares
pub const A1: Square = 0 + 0*8;
pub const B1: Square = 1 + 0*8;
pub const C1: Square = 2 + 0*8;
pub const D1: Square = 3 + 0*8;
pub const E1: Square = 4 + 0*8;
pub const F1: Square = 5 + 0*8;
pub const G1: Square = 6 + 0*8;
pub const H1: Square = 7 + 0*8;

pub const A2: Square = 0 + 1*8;
pub const B2: Square = 1 + 1*8;
pub const C2: Square = 2 + 1*8;
pub const D2: Square = 3 + 1*8;
pub const E2: Square = 4 + 1*8;
pub const F2: Square = 5 + 1*8;
pub const G2: Square = 6 + 1*8;
pub const H2: Square = 7 + 1*8;

pub const A3: Square = 0 + 2*8;
pub const B3: Square = 1 + 2*8;
pub const C3: Square = 2 + 2*8;
pub const D3: Square = 3 + 2*8;
pub const E3: Square = 4 + 2*8;
pub const F3: Square = 5 + 2*8;
pub const G3: Square = 6 + 2*8;
pub const H3: Square = 7 + 2*8;

pub const A4: Square = 0 + 3*8;
pub const B4: Square = 1 + 3*8;
pub const C4: Square = 2 + 3*8;
pub const D4: Square = 3 + 3*8;
pub const E4: Square = 4 + 3*8;
pub const F4: Square = 5 + 3*8;
pub const G4: Square = 6 + 3*8;
pub const H4: Square = 7 + 3*8;

pub const A5: Square = 0 + 4*8;
pub const B5: Square = 1 + 4*8;
pub const C5: Square = 2 + 4*8;
pub const D5: Square = 3 + 4*8;
pub const E5: Square = 4 + 4*8;
pub const F5: Square = 5 + 4*8;
pub const G5: Square = 6 + 4*8;
pub const H5: Square = 7 + 4*8;

pub const A6: Square = 0 + 5*8;
pub const B6: Square = 1 + 5*8;
pub const C6: Square = 2 + 5*8;
pub const D6: Square = 3 + 5*8;
pub const E6: Square = 4 + 5*8;
pub const F6: Square = 5 + 5*8;
pub const G6: Square = 6 + 5*8;
pub const H6: Square = 7 + 5*8;

pub const A7: Square = 0 + 6*8;
pub const B7: Square = 1 + 6*8;
pub const C7: Square = 2 + 6*8;
pub const D7: Square = 3 + 6*8;
pub const E7: Square = 4 + 6*8;
pub const F7: Square = 5 + 6*8;
pub const G7: Square = 6 + 6*8;
pub const H7: Square = 7 + 6*8;

pub const A8: Square = 0 + 7*8;
pub const B8: Square = 1 + 7*8;
pub const C8: Square = 2 + 7*8;
pub const D8: Square = 3 + 7*8;
pub const E8: Square = 4 + 7*8;
pub const F8: Square = 5 + 7*8;
pub const G8: Square = 6 + 7*8;
pub const H8: Square = 7 + 7*8;

pub struct Move(u16);

impl Move {
    #[inline]
    pub fn new(m_type: MoveType, orig: Square, dest: Square, pp_type: PieceType) -> Move {
        assert!(m_type <= 3);
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_type <= 3);
        Move( ((m_type << 14) | (pp_type << 12) | (orig << 6) | dest) as u16 )
    }

    #[inline]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & (0b11 << 14)) >> 14) as MoveType
    }

    #[inline]
    pub fn orig_square(&self) -> Square {
        (self.0 & (0b111111 << 6) >> 6) as Square
    }

    #[inline]
    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    #[inline]
    pub fn promotion_piece_type(&self) -> PieceType {
        (self.0 & (0b11 << 12) >> 12) as PieceType
    }
}

#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}

#[inline]
pub fn rank(square: Square) -> usize {
    square / 8
}

#[inline]
pub fn file(square: Square) -> usize {
    square % 8
}

<|endoftext|>


<commit_before>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<Job>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("mp4"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            self.jobs.push(Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
            });
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn run(&mut self) {
        println!("Showing current BatchJob");
        for rule in self.rules.iter() {
            println!("{:?}", rule);
        }
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }
        Ok(())
    }

    fn convert_video(&self, source_filepath: &Path, output_dir: &str) {
        let mut out_file = PathBuf::new();
        out_file.push(output_dir);
        out_file.push(source_filepath.file_stem().unwrap());
        out_file.set_extension("mp4");

        let mut output = Command::new("ffmpeg")
            .arg("-loglevel")
            .arg("warning")
            .arg("-i")
            .arg(source_filepath)
            .arg("-y")
            .arg("-c:v")
            .arg("libx264")
            .arg("-preset")
            .arg("ultrafast")
            .arg("-framerate")
            .arg("30")
            .arg("-vsync")
            .arg("1")
            .arg("-crf")
            .arg("20")
            .arg(out_file.as_path())
            .spawn()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        output.wait().unwrap();
    }
}
<commit_msg>Pre processing validation<commit_after>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

#[derive(Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
    Pending,
    Done,
    Error,
}

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,

    status: JobStatus,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<Job>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("mp4"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            self.jobs.push(Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
                status: JobStatus::Pending,
            });
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn run(&mut self) {
        let pending_jobs = self.jobs
            .iter_mut()
            .filter(|j| j.status == JobStatus::Pending)
            .collect::<Vec<&mut Job>>();

        println!("{} pending jobs", pending_jobs.len());

        for job in pending_jobs {
            let path = Path::new(job.source_path.as_str());
            println!("Processing: {}", job.source_path);

            if !path.exists() {
                job.status = JobStatus::Error;
                println!("   Path does not exist");
                continue;
            } else if !path.is_file() {
                job.status = JobStatus::Error;
                println!("   Path is not a file");
                continue;
            }

            let extension = match path.extension() {
                Some(e) => match e.to_str() {
                    Some(es) => es,
                    None => {
                        job.status = JobStatus::Error;
                        println!("   Error converting to string");
                        continue;
                    }
                },
                None => {
                    job.status = JobStatus::Done;
                    println!("   No extension");
                    continue;
                }
            };

            let rule = match self.rules.get(extension) {
                Some(r) => r,
                None => {
                    job.status = JobStatus::Done;
                    println!("   No rule defined for extension '{}'", extension);
                    continue;
                }
            };

            let args: Vec<&str> = rule.split_whitespace().collect();
            println!("   {:?}", args);
        }
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }
        Ok(())
    }

    fn convert_video(&self, source_filepath: &Path, output_dir: &str) {
        let mut out_file = PathBuf::new();
        out_file.push(output_dir);
        out_file.push(source_filepath.file_stem().unwrap());
        out_file.set_extension("mp4");

        let mut output = Command::new("ffmpeg")
            .arg("-loglevel")
            .arg("warning")
            .arg("-i")
            .arg(source_filepath)
            .arg("-y")
            .arg("-c:v")
            .arg("libx264")
            .arg("-preset")
            .arg("ultrafast")
            .arg("-framerate")
            .arg("30")
            .arg("-vsync")
            .arg("1")
            .arg("-crf")
            .arg("20")
            .arg(out_file.as_path())
            .spawn()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        output.wait().unwrap();
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Symbol range
//!
//! It's quite common to want to match ranges of symbols (most particularly, 'all' symbols but also things like all upper-case
//! characters). It would be inefficient to store all of the transitions represented by one of these transitions on a per-symbol
//! basis, and impossible for some symbol sets (consider a state machine working on u32s). Instead, transitions are stored as
//! symbol ranges.
//!

///
/// Trait implemented by symbol types that are countable - ie, for types where there's always a next symbol
///
pub trait Countable where Self: Sized {
    ///
    /// Returns the next symbol in order (None if this is the last symbol)
    ///
    fn next(&self) -> Option<Self>;

    ///
    /// Returns the next symbol in order (None if this is the last symbol)
    ///
    fn prev(&self) -> Option<Self>;
}

///
/// Represents a range of symbols
///
/// Symbols must be ordered in order to use them with a range-based state machine.
///
#[derive(Clone, Eq, PartialEq)]
pub struct SymbolRange<Symbol: PartialOrd+Clone> {
    ///
    /// Lowest symbol in the range
    ///
    pub lowest: Symbol,

    ///
    /// Highest symbol in the range
    ///
    /// This is inclusive, so the highest symbol is always included in the range (this makes it differ from Rust's
    /// built-in Range struct, and is important for supporting uncountable symbols)
    ///
    pub highest: Symbol
}

impl<Symbol: PartialOrd+Clone> SymbolRange<Symbol> {
    ///
    /// Creates a new range covering everything between the specified two symbols
    ///
    #[inline]
    pub fn new(lowest: Symbol, highest: Symbol) -> SymbolRange<Symbol> {
        if lowest > highest {
            SymbolRange { lowest: highest, highest: lowest }
        } else {
            SymbolRange { lowest: lowest, highest: highest }
        }
    }

    ///
    /// Joins this range with another
    ///
    /// This creates a new range that covers all the symbols of both. If `overlaps()` is false for these two ranges, then
    /// the new range may cover additional symbols that are not in either range.
    ///
    pub fn join(&self, with: &SymbolRange<Symbol>) -> SymbolRange<Symbol> {
        SymbolRange {
            lowest:  if with.lowest<self.lowest   { with.lowest.clone()  } else { self.lowest.clone()  },
            highest: if with.highest<self.highest { self.highest.clone() } else { with.highest.clone() }
        }
    }

    ///
    /// True if this range overlaps another
    ///
    #[inline]
    pub fn overlaps(&self, with: &SymbolRange<Symbol>) -> bool {
        if self.highest < with.lowest {
            false
        } else if self.lowest > with.highest {
            false
        } else {
            true
        }
    }
}

impl Countable for u8 {
    fn next(&self) -> Option<u8> {
        if *self == Self::max_value() {
            None
        } else {
            Some(self+1)
        }
    }

    fn prev(&self) -> Option<u8> {
        if *self == Self::min_value() {
            None
        } else {
            Some(self-1)
        }
    }
}

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

    #[test]
    fn can_create_range() {
        let range = SymbolRange::new(1, 2);

        assert!(range.lowest == 1);
        assert!(range.highest == 2);
    }

    #[test]
    fn can_create_range_reversed() {
        let range = SymbolRange::new(5, 1);

        assert!(range.lowest == 1);
        assert!(range.highest == 5);
    }

    #[test]
    fn overlaps_when_within() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(2, 3)));
    }

    #[test]
    fn overlaps_when_without() {
        assert!(SymbolRange::new(2, 3).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn overlaps_when_lower() {
        assert!(SymbolRange::new(1, 3).overlaps(&SymbolRange::new(2, 4)));
    }

    #[test]
    fn overlaps_when_higher() {
        assert!(SymbolRange::new(2, 4).overlaps(&SymbolRange::new(1, 3)));
    }

    #[test]
    fn overlaps_when_same() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn does_not_overlap_lower() {
        assert!(!SymbolRange::new(1, 2).overlaps(&SymbolRange::new(4, 5)));
    }

    #[test]
    fn does_not_overlap_higher() {
        assert!(!SymbolRange::new(4, 5).overlaps(&SymbolRange::new(1, 2)));
    }

    #[test]
    fn join_left() {
        let joined = SymbolRange::new(1, 3).join(&SymbolRange::new(3, 4));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_right() {
        let joined = SymbolRange::new(3, 4).join(&SymbolRange::new(1, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_overlap() {
        let joined = SymbolRange::new(1, 4).join(&SymbolRange::new(2, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }
}
<commit_msg>Add a test for overlapping on an uncountable value<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Symbol range
//!
//! It's quite common to want to match ranges of symbols (most particularly, 'all' symbols but also things like all upper-case
//! characters). It would be inefficient to store all of the transitions represented by one of these transitions on a per-symbol
//! basis, and impossible for some symbol sets (consider a state machine working on u32s). Instead, transitions are stored as
//! symbol ranges.
//!

///
/// Trait implemented by symbol types that are countable - ie, for types where there's always a next symbol
///
pub trait Countable where Self: Sized {
    ///
    /// Returns the next symbol in order (None if this is the last symbol)
    ///
    fn next(&self) -> Option<Self>;

    ///
    /// Returns the next symbol in order (None if this is the last symbol)
    ///
    fn prev(&self) -> Option<Self>;
}

///
/// Represents a range of symbols
///
/// Symbols must be ordered in order to use them with a range-based state machine.
///
#[derive(Clone, Eq, PartialEq)]
pub struct SymbolRange<Symbol: PartialOrd+Clone> {
    ///
    /// Lowest symbol in the range
    ///
    pub lowest: Symbol,

    ///
    /// Highest symbol in the range
    ///
    /// This is inclusive, so the highest symbol is always included in the range (this makes it differ from Rust's
    /// built-in Range struct, and is important for supporting uncountable symbols)
    ///
    pub highest: Symbol
}

impl<Symbol: PartialOrd+Clone> SymbolRange<Symbol> {
    ///
    /// Creates a new range covering everything between the specified two symbols
    ///
    #[inline]
    pub fn new(lowest: Symbol, highest: Symbol) -> SymbolRange<Symbol> {
        if lowest > highest {
            SymbolRange { lowest: highest, highest: lowest }
        } else {
            SymbolRange { lowest: lowest, highest: highest }
        }
    }

    ///
    /// Joins this range with another
    ///
    /// This creates a new range that covers all the symbols of both. If `overlaps()` is false for these two ranges, then
    /// the new range may cover additional symbols that are not in either range.
    ///
    pub fn join(&self, with: &SymbolRange<Symbol>) -> SymbolRange<Symbol> {
        SymbolRange {
            lowest:  if with.lowest<self.lowest   { with.lowest.clone()  } else { self.lowest.clone()  },
            highest: if with.highest<self.highest { self.highest.clone() } else { with.highest.clone() }
        }
    }

    ///
    /// True if this range overlaps another
    ///
    #[inline]
    pub fn overlaps(&self, with: &SymbolRange<Symbol>) -> bool {
        if self.highest < with.lowest {
            false
        } else if self.lowest > with.highest {
            false
        } else {
            true
        }
    }
}

impl Countable for u8 {
    fn next(&self) -> Option<u8> {
        if *self == Self::max_value() {
            None
        } else {
            Some(self+1)
        }
    }

    fn prev(&self) -> Option<u8> {
        if *self == Self::min_value() {
            None
        } else {
            Some(self-1)
        }
    }
}

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

    #[test]
    fn can_create_range() {
        let range = SymbolRange::new(1, 2);

        assert!(range.lowest == 1);
        assert!(range.highest == 2);
    }

    #[test]
    fn can_create_range_reversed() {
        let range = SymbolRange::new(5, 1);

        assert!(range.lowest == 1);
        assert!(range.highest == 5);
    }

    #[test]
    fn overlaps_when_within() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(2, 3)));
    }

    #[test]
    fn overlaps_when_within_float() {
        assert!(SymbolRange::new(1.0, 4.0).overlaps(&SymbolRange::new(2.0, 3.0)));
    }

    #[test]
    fn overlaps_when_without() {
        assert!(SymbolRange::new(2, 3).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn overlaps_when_lower() {
        assert!(SymbolRange::new(1, 3).overlaps(&SymbolRange::new(2, 4)));
    }

    #[test]
    fn overlaps_when_higher() {
        assert!(SymbolRange::new(2, 4).overlaps(&SymbolRange::new(1, 3)));
    }

    #[test]
    fn overlaps_when_same() {
        assert!(SymbolRange::new(1, 4).overlaps(&SymbolRange::new(1, 4)));
    }

    #[test]
    fn does_not_overlap_lower() {
        assert!(!SymbolRange::new(1, 2).overlaps(&SymbolRange::new(4, 5)));
    }

    #[test]
    fn does_not_overlap_higher() {
        assert!(!SymbolRange::new(4, 5).overlaps(&SymbolRange::new(1, 2)));
    }

    #[test]
    fn join_left() {
        let joined = SymbolRange::new(1, 3).join(&SymbolRange::new(3, 4));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_right() {
        let joined = SymbolRange::new(3, 4).join(&SymbolRange::new(1, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }

    #[test]
    fn join_overlap() {
        let joined = SymbolRange::new(1, 4).join(&SymbolRange::new(2, 3));

        assert!(joined.lowest == 1);
        assert!(joined.highest == 4);
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
extern crate js;
extern crate collections;
use js::lexer::Lexer;
use js::parser::Parser;
use js::exec::{Executor, Interpreter};
use js::ast::{Token, TComment};
use js::stdlib::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
use std::os;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<StrBuf, StrBuf> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = current.slice_chars(2, space_ind);
					let value = current.slice_from(space_ind + 1);
					map.insert(key.into_strbuf(), value.into_strbuf());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	if args.len() < 2 {
		return Err(to_value("'assert' function expects assertion and description arguments"));
	}
	let val : bool = from_value(*args.get(0)).unwrap();
	let desc : Value = *args.get(1);
	if val {
		Ok(desc)
	} else {
		Err(desc)
	}
}
fn main() {
	let args = os::args();
	let verbose = args.contains(&"-v".into_strbuf()) || args.contains(&"--verbose".into_strbuf());
	let mut path = Path::new("tests");
	if !path.is_dir() {
		path = Path::new("../tests");
	}
	if !path.is_dir() {
		fail!("Could not find tests directory");
	}
	for file in walk_dir(&path).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			if verbose {
				println!("{}", lexer.tokens.clone().iter().map(|tk| tk.to_str()).collect::<Vec<StrBuf>>().connect("\n"));
			}
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_strbuf()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_strbuf(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("{}: All tests passed for {}", file_str, description),
				Err(v) => fail!("{}: Test failed for {} in {}", file_str, v.borrow(), description)
			}
		}
	}
}<commit_msg>Add a few more verbose outputs to tests<commit_after>#![crate_type = "bin"]
extern crate js;
extern crate collections;
use js::lexer::Lexer;
use js::parser::Parser;
use js::exec::{Executor, Interpreter};
use js::ast::{Token, TComment};
use js::stdlib::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
use std::os;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<StrBuf, StrBuf> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = current.slice_chars(2, space_ind);
					let value = current.slice_from(space_ind + 1);
					map.insert(key.into_strbuf(), value.into_strbuf());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	if args.len() < 2 {
		return Err(to_value("'assert' function expects assertion and description arguments"));
	}
	let val : bool = from_value(*args.get(0)).unwrap();
	let desc : Value = *args.get(1);
	if val {
		Ok(desc)
	} else {
		Err(desc)
	}
}
fn main() {
	let args = os::args();
	let verbose = args.contains(&"-v".into_strbuf()) || args.contains(&"--verbose".into_strbuf());
	let mut path = Path::new("tests");
	if !path.is_dir() {
		path = Path::new("../tests");
	}
	if !path.is_dir() {
		fail!("Could not find tests directory");
	}
	for file in walk_dir(&path).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			if verbose {
				println!("{}: Lexing", file_str);
			}
			lexer.lex().unwrap();
			if verbose {
				println!("{}", lexer.tokens.clone().iter().map(|tk| tk.to_str()).collect::<Vec<StrBuf>>().connect("\n"));
			}
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_strbuf()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			if verbose {
				println!("{}: Parsing", file_str);
			}
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_strbuf(), to_value(assert));
			if verbose {
				println!("{}: Executing", file_str);
			}
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("{}: All tests passed for {}", file_str, description),
				Err(v) => fail!("{}: Test failed for {} in {}", file_str, v.borrow(), description)
			}
		}
	}
}<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

#[test]
fn parse_quarks() {
  let source = "null true false 1.3 0.3 2 3 name table";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_quark(&mut it), Ok(Node::Null));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(true)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(false)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(1.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(0.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(2)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Name(String::from("name"))));
  assert_eq!(parse_quark(&mut it), Ok(Node::Table));
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedEOF));
}
<commit_msg>tests.parser: Add test_simple()<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

#[test]
fn test_quark() {
  let source = "null true false 1.3 0.3 2 3 name table";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_quark(&mut it), Ok(Node::Null));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(true)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Bool(false)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(1.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Float(0.3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(2)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Int(3)));
  assert_eq!(parse_quark(&mut it), Ok(Node::Name(String::from("name"))));
  assert_eq!(parse_quark(&mut it), Ok(Node::Table));
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_quark(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_atom() {
  let source = "null (null)";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Ok(Node::Null));
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_atom(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_simple() {
  let source = "foo foo.bar foo[bar] foo() foo:bar() foo.bar() foo.bar[baz]:qux()";
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(parse_simple(&mut it), Ok(Node::Name(String::from("foo"))));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Str(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Index {
    lhs: Box::new(Node::Name(String::from("foo"))),
    rhs: Box::new(Node::Name(String::from("bar"))),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Name(String::from("foo"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Name(String::from("foo"))),
    method: Box::new(Node::Str(String::from("bar"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Func {
    func: Box::new(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Ok(Node::Method {
    owner: Box::new(Node::Index {
      lhs: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      rhs: Box::new(Node::Name(String::from("baz"))),
    }),
    method: Box::new(Node::Str(String::from("qux"))),
    args: Vec::new(),
  }));
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();
  assert_eq!(parse_simple(&mut it), Err(UnexpectedEOF));
}
<|endoftext|>


<commit_before>/// Character level parsers

use internal::{IResult,Needed};
use util::ErrorKind;

/// matches one of the provided characters
#[macro_export]
macro_rules! one_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        one_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! one_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          //$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::OneOf, $i))
          $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i))
        }
      }
    }
  );
);

/// matches anything but the provided characters
#[macro_export]
macro_rules! none_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        none_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! none_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if !found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::NoneOf, $i))
        }
      }
    }
  );
);

/// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char>
#[macro_export]
macro_rules! char (
  ($i:expr, $c: expr) => (
    {
      if $i.is_empty() {
        let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1));
        res
      } else {
        if $i[0] == $c as u8 {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::Char, $i))
        }
      }
    }
  );
);

named!(pub newline<char>, char!('\n'));

pub fn crlf(input:&[u8]) -> IResult<&[u8], char> {
  if input.len() < 2 {
    IResult::Incomplete(Needed::Size(2))
  } else {
    if &input[0..2] == &b"\r\n"[..] {
      IResult::Done(&input[2..], '\n')
    } else {
      IResult::Error(error_position!(ErrorKind::CrLf, input))
    }
  }
}

named!(pub eol<char>, alt!(newline | crlf));
named!(pub tab<char>, char!('\t'));

pub fn anychar(input:&[u8]) -> IResult<&[u8], char> {
  if input.is_empty() {
    IResult::Incomplete(Needed::Size(1))
  } else {
    IResult::Done(&input[1..], input[0] as char)
  }
}

#[cfg(test)]
mod tests {
  use internal::IResult::*;
  use util::ErrorKind;

  #[test]
  fn one_of() {
    named!(f<char>, one_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Done(&b"bcd"[..], 'a'));

    let b = &b"cde"[..];
    assert_eq!(f(b), Error(error_position!(ErrorKind::OneOf, b)));
  }

  #[test]
  fn none_of() {
    named!(f<char>, none_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::NoneOf, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

  #[test]
  fn char() {
    named!(f<char>, char!('c'));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::Char, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }
}
<commit_msg>fix crlf<commit_after>/// Character level parsers

use internal::{IResult,Needed};
use util::ErrorKind;
use std::ops::{Range,RangeFrom,RangeTo};
use traits::{AsChar,Compare,CompareResult,IterIndices,Slice};

/// matches one of the provided characters
#[macro_export]
macro_rules! one_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        one_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! one_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          //$crate::IResult::Error($crate::Err::Position($crate::ErrorKind::OneOf, $i))
          $crate::IResult::Error(error_position!($crate::ErrorKind::OneOf, $i))
        }
      }
    }
  );
);

/// matches anything but the provided characters
#[macro_export]
macro_rules! none_of (
  ($i:expr, $inp: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        #[inline(always)]
        fn as_bytes<T: $crate::AsBytes>(b: &T) -> &[u8] {
          b.as_bytes()
        }

        let expected = $inp;
        let bytes = as_bytes(&expected);
        none_of_bytes!($i, bytes)
      }
    }
  );
);

#[doc(hidden)]
#[macro_export]
macro_rules! none_of_bytes (
  ($i:expr, $bytes: expr) => (
    {
      if $i.is_empty() {
        $crate::IResult::Incomplete::<_, _>($crate::Needed::Size(1))
      } else {
        let mut found = false;

        for &i in $bytes {
          if i == $i[0] {
            found = true;
            break;
          }
        }

        if !found {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::NoneOf, $i))
        }
      }
    }
  );
);

/// matches one character: `char!(char) => &[u8] -> IResult<&[u8], char>
#[macro_export]
macro_rules! char (
  ($i:expr, $c: expr) => (
    {
      if $i.is_empty() {
        let res: $crate::IResult<&[u8], char> = $crate::IResult::Incomplete($crate::Needed::Size(1));
        res
      } else {
        if $i[0] == $c as u8 {
          $crate::IResult::Done(&$i[1..], $i[0] as char)
        } else {
          $crate::IResult::Error(error_position!($crate::ErrorKind::Char, $i))
        }
      }
    }
  );
);

named!(pub newline<char>, char!('\n'));

pub fn crlf<'a, T: ?Sized>(input:&'a T) -> IResult<&'a T, char> where
  &'a T:Slice<Range<usize>>+Slice<RangeFrom<usize>>+Slice<RangeTo<usize>>,
  &'a T: IterIndices,
  &'a T: Compare<&'static str> {
    match input.compare("\n") {
      CompareResult::Ok         => {
        let c = input.slice(0..1).iter_elements().next().unwrap().as_char();
        IResult::Done(input.slice(1..), c)
      },
      CompareResult::Incomplete => IResult::Incomplete(Needed::Size(1)),
      CompareResult::Error      => match input.compare("\r\n") {
        //FIXME: is this the right index?
        CompareResult::Ok         => {
          let c = input.slice(0..2).iter_elements().next().unwrap().as_char();
          IResult::Done(input.slice(2..), c)
        },
        CompareResult::Incomplete => IResult::Incomplete(Needed::Size(2)),
        CompareResult::Error      => IResult::Error(error_position!(ErrorKind::CrLf, input))
      }
    }
}

named!(pub eol<char>, alt!(newline | crlf));
named!(pub tab<char>, char!('\t'));

pub fn anychar(input:&[u8]) -> IResult<&[u8], char> {
  if input.is_empty() {
    IResult::Incomplete(Needed::Size(1))
  } else {
    IResult::Done(&input[1..], input[0] as char)
  }
}

#[cfg(test)]
mod tests {
  use internal::IResult::*;
  use util::ErrorKind;

  #[test]
  fn one_of() {
    named!(f<char>, one_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Done(&b"bcd"[..], 'a'));

    let b = &b"cde"[..];
    assert_eq!(f(b), Error(error_position!(ErrorKind::OneOf, b)));
  }

  #[test]
  fn none_of() {
    named!(f<char>, none_of!("ab"));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::NoneOf, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }

  #[test]
  fn char() {
    named!(f<char>, char!('c'));

    let a = &b"abcd"[..];
    assert_eq!(f(a), Error(error_position!(ErrorKind::Char, a)));

    let b = &b"cde"[..];
    assert_eq!(f(b), Done(&b"de"[..], 'c'));
  }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone, Debug)]
pub struct Condition(Rc<RefCell<bool>>);

impl Condition {
    pub fn is_active(&self) -> bool {
        *self.0.borrow()
    }

    pub fn activate(&mut self) {
        *self.0.borrow_mut() = true;
    }

    pub fn deactivate(&mut self) {
        *self.0.borrow_mut() = false;
    }
}
<commit_msg>Condition: add public new() method<commit_after>use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone, Debug)]
pub struct Condition(Rc<RefCell<bool>>);

impl Condition {
    pub fn new(state: bool) -> Condition {
        Condition(Rc::new(RefCell::new(state)))
    }

    pub fn is_active(&self) -> bool {
        *self.0.borrow()
    }

    pub fn activate(&mut self) {
        *self.0.borrow_mut() = true;
    }

    pub fn deactivate(&mut self) {
        *self.0.borrow_mut() = false;
    }
}
<|endoftext|>


<commit_before>use getopts::{Options,Matches};
use std::net::{TcpStream,SocketAddr};

pub fn connect(matches: &Matches) {
    let host = matches.free.get(0).unwrap();
    let port = match matches.free.get(1).unwrap().parse::<u16>() {
        Ok(n) => { n }
        Err(_) => {
            panic!("not in possible range".to_string());
        }
    };
    // let connect_addr = SocketAddr::new(host, port);
    match TcpStream::connect(&(host.as_slice(), port)) {
        Ok(stream) => {
            println!("ok");
        },
        Err(f) => {
            // just exit
        }
    }
}
<commit_msg>client side working better now doesn't drop connection if server dies, for some reason, and reading from stdin is probably not the best (work for files? work for strange input?)<commit_after>use getopts::{Options,Matches};
use std::net::{TcpStream,SocketAddr};
use std::io::{BufStream,Write};
use std::old_io;

pub fn connect(matches: &Matches) {
    let host = matches.free.get(0).unwrap();
    let port = match matches.free.get(1).unwrap().parse::<u16>() {
        Ok(n) => { n }
        Err(_) => {
            panic!("not in possible range".to_string());
        }
    };
    match TcpStream::connect(&(host.as_slice(), port)) {
        Ok(stream) => {
            write_to_stream(&stream);
            println!("ok");
        },
        Err(f) => {
            // just exit
        }
    }
}

fn write_to_stream(stream: &TcpStream) {
    let mut buf_stream = BufStream::new(stream);
    let mut stdin = old_io::stdin();
    for line in stdin.lock().lines() {
        buf_stream.write_all(line.unwrap().as_bytes()).unwrap();
        buf_stream.flush();
    }
}
<|endoftext|>


<commit_before>extern crate mio;
use getopts::{Options,Matches};
use std::net::{SocketAddr,lookup_host,IpAddr};
use std::io::{BufStream,Write};
use std::old_io;

use self::mio::*;
use self::mio::net::tcp::*;
use self::mio::buf::{ByteBuf};
use self::mio::net::*;

use std::thread;

use super::util::parse_addr;

const CLIENT: Token = Token(1);

struct ClientHandler {
    sock: NonBlock<TcpStream>
}

impl Handler for ClientHandler {
    type Timeout = usize;
    type Message = String;

    fn readable(&mut self, event_loop: &mut EventLoop<ClientHandler>, token: Token, _: ReadHint) {
        match token {
            CLIENT => {
                let mut read_buf = ByteBuf::mut_with_capacity(2048);
                match self.sock.read(&mut read_buf) {
                    Ok(None) => {
                        panic!("Read operation would block, bailing cuz this shouldn't happen.");
                    }
                    Ok(Some(r)) => {
                        // `_` would be the number of bytes read.
                        // `flip` will return a `ByteBuf` on which we can call
                        // `read_slice` to get the data available to be read.
                        // See http://carllerche.github.io/bytes/bytes/struct.ByteBuf.html
                        let mut buf = read_buf.flip();
                        let mut sl = [0; 2048];
                        buf.read_slice(&mut sl);
                        // Assuming what was written was encoded as UTF8, print what
                        // was read to STDOUT.
                        print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                    }
                    Err(e) => {
                        // Probably because connection could not be established.
                        event_loop.shutdown();
                        panic!(e.to_string());
                    }
                }
            },
            _ => {
                panic!("unepxected token!".to_string());
            }
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<ClientHandler>, msg: String) {
        self.sock.write_slice(msg.as_bytes()).unwrap();
    }
}

pub fn nc_connect(matches: &Matches) {
    let addr = parse_addr(matches);
    let sock = match addr.ip() {
        IpAddr::V4(..) => v4(),
        IpAddr::V6(..) => v6()
    }.unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    match sock.connect(&addr) {
        Ok((stream, _)) => {
            let mut client = ClientHandler { sock: stream };
            event_loop.register(&client.sock, CLIENT).unwrap();
            let sender = event_loop.channel();
            thread::spawn(move || {
                readwrite_chan(&sender);
            });
            let _ = event_loop.run(&mut client);
        },
        Err(f) => {
            println!("exiting");
            // just exit
        }
    }
}

fn readwrite_chan(channel: &EventLoopSender<String>) {
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0; 4096];
    println!("readwritechan");
    loop {
        // Have to block here, so we can't immediately terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                println!("read");
                let read = read_buf.slice_to(n);
                let byte_vec: Vec<u8> = read.to_vec();
                let message = String::from_utf8(byte_vec).unwrap();
                channel.send(message).unwrap();
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<commit_msg>removing some debugging println!s<commit_after>extern crate mio;
use getopts::{Options,Matches};
use std::net::{SocketAddr,lookup_host,IpAddr};
use std::io::{BufStream,Write};
use std::old_io;

use self::mio::*;
use self::mio::net::tcp::*;
use self::mio::buf::{ByteBuf};
use self::mio::net::*;

use std::thread;

use super::util::parse_addr;

const CLIENT: Token = Token(1);

struct ClientHandler {
    sock: NonBlock<TcpStream>
}

impl Handler for ClientHandler {
    type Timeout = usize;
    type Message = String;

    fn readable(&mut self, event_loop: &mut EventLoop<ClientHandler>, token: Token, _: ReadHint) {
        match token {
            CLIENT => {
                let mut read_buf = ByteBuf::mut_with_capacity(2048);
                match self.sock.read(&mut read_buf) {
                    Ok(None) => {
                        panic!("Read operation would block, bailing cuz this shouldn't happen.");
                    }
                    Ok(Some(r)) => {
                        // `_` would be the number of bytes read.
                        // `flip` will return a `ByteBuf` on which we can call
                        // `read_slice` to get the data available to be read.
                        // See http://carllerche.github.io/bytes/bytes/struct.ByteBuf.html
                        let mut buf = read_buf.flip();
                        let mut sl = [0; 2048];
                        buf.read_slice(&mut sl);
                        // Assuming what was written was encoded as UTF8, print what
                        // was read to STDOUT.
                        print!("{}", String::from_utf8(sl.to_vec()).unwrap());
                    }
                    Err(e) => {
                        // Probably because connection could not be established.
                        event_loop.shutdown();
                        panic!(e.to_string());
                    }
                }
            },
            _ => {
                panic!("unepxected token!".to_string());
            }
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<ClientHandler>, msg: String) {
        self.sock.write_slice(msg.as_bytes()).unwrap();
    }
}

pub fn nc_connect(matches: &Matches) {
    let addr = parse_addr(matches);
    let sock = match addr.ip() {
        IpAddr::V4(..) => v4(),
        IpAddr::V6(..) => v6()
    }.unwrap();

    let mut event_loop = EventLoop::new().unwrap();

    match sock.connect(&addr) {
        Ok((stream, _)) => {
            let mut client = ClientHandler { sock: stream };
            event_loop.register(&client.sock, CLIENT).unwrap();
            let sender = event_loop.channel();
            thread::spawn(move || {
                readwrite_chan(&sender);
            });
            let _ = event_loop.run(&mut client);
        },
        Err(f) => {
            println!("exiting");
            // just exit
        }
    }
}

fn readwrite_chan(channel: &EventLoopSender<String>) {
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0; 4096];
    loop {
        // Have to block here, so we can't immediately terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                let read = read_buf.slice_to(n);
                let byte_vec: Vec<u8> = read.to_vec();
                let message = String::from_utf8(byte_vec).unwrap();
                channel.send(message).unwrap();
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Clone,Debug)]
pub enum HttpMethods {
    Get,
    Post,
}

impl fmt::Display for HttpMethods {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s: String = format!("{:?}", self);
        write!(f, "{}", s.to_uppercase())
    }
}

#[derive(Clone,Debug)]
pub enum ResponseCode {
    // Testing
    Undefined = 0,
    // Informational
    Continue = 100,
    SwitchingProtocols = 101,
    Processing = 102,
    // Success
    Ok = 200,
    Created = 201,
    Accepted = 202,
    NonAuthoritativeInformation = 203,
    NoContent = 204,
    ResetContent = 205,
    PartialContent = 206,
    MultiStatus = 207,
    AlreadyReported = 208,
    ImUsed = 226,
    // Redirection
    MultipleChoices = 300,
    MovedPermanently = 301,
    Found = 302,
    SeeOther = 303,
    NotModified = 304,
    UseProxy = 305,
    SwitchProxy = 306,
    TemporaryRedirect = 307,
    PermanentRedirect = 308,
    // Client Error
    BadRequest = 400,
    Unauthorized = 401,
    PaymentRequired = 402,
    Forbidden = 403,
    NotFound = 404,
    MethodNotAllowed = 405,
    NotAcceptable = 406,
    ProxyAuthenticationRequired = 407,
    RequestTimeout = 408,
    Conflict = 409,
    Gone = 410,
    LengthRequired = 411,
    PreconditionFailed = 412,
    PayloadTooLarge = 413,
    UriTooLong = 414,
    UnsupportedMediaType = 415,
    RangeNotSatisified = 416,
    ExpectationFailed = 417,
    ImATeapot = 418,
    MisdirectedRequest = 421,
    UnprocessableEntitiy = 422,
    Locked = 423,
    FailedDependency = 424,
    UpgradeRequired = 426,
    PreconditionRequired = 428,
    TooManyRequests = 429,
    RequestHeaderFieldsTooLarge = 431,
    UnavailableForLegalReasons = 451,
    // Server Error
    InternalServerError = 500,
    NotImplemented = 501,
    BadGateway = 502,
    ServiceUnavailable = 503,
    GatewayTimeout = 504,
    HttpVersionNotSupported = 505,
    VariantAlsoNegotiates = 506,
    InsufficientStorage = 507,
    LoopDetected = 508 ,
    NotExtended = 510,
    NetworkAuthenticationRequired = 511,
}

impl fmt::Display for ResponseCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s: String = format!("{:?}", self).to_owned();
        write!(f, "{}", &s.to_uppercase())
    }
}

impl ResponseCode {
    pub fn from_int(i: u32) -> ResponseCode {
        match i {
            // Testing
            0 => ResponseCode::Undefined,
            // Informational
            100 => ResponseCode::Continue,
            101 => ResponseCode::SwitchingProtocols,
            102 => ResponseCode::Processing,
            // Success
            200 => ResponseCode::Ok,
            201 => ResponseCode::Created,
            202 => ResponseCode::Accepted,
            203 => ResponseCode::NonAuthoritativeInformation,
            204 => ResponseCode::NoContent,
            205 => ResponseCode::ResetContent,
            206 => ResponseCode::PartialContent,
            207 => ResponseCode::MultiStatus,
            208 => ResponseCode::AlreadyReported,
            226 => ResponseCode::ImUsed,
            // Redirection
            300 => ResponseCode::MultipleChoices,
            301 => ResponseCode::MovedPermanently,
            302 => ResponseCode::Found,
            303 => ResponseCode::SeeOther,
            304 => ResponseCode::NotModified,
            305 => ResponseCode::UseProxy,
            306 => ResponseCode::SwitchProxy,
            307 => ResponseCode::TemporaryRedirect,
            308 => ResponseCode::PermanentRedirect,
            // Client Error
            400 => ResponseCode::BadRequest,
            401 => ResponseCode::Unauthorized,
            402 => ResponseCode::PaymentRequired,
            403 => ResponseCode::Forbidden,
            404 => ResponseCode::NotFound,
            405 => ResponseCode::MethodNotAllowed,
            406 => ResponseCode::NotAcceptable,
            407 => ResponseCode::ProxyAuthenticationRequired,
            408 => ResponseCode::RequestTimeout,
            409 => ResponseCode::Conflict,
            410 => ResponseCode::Gone,
            411 => ResponseCode::LengthRequired,
            412 => ResponseCode::PreconditionFailed,
            413 => ResponseCode::PayloadTooLarge,
            414 => ResponseCode::UriTooLong,
            415 => ResponseCode::UnsupportedMediaType,
            416 => ResponseCode::RangeNotSatisified,
            417 => ResponseCode::ExpectationFailed,
            418 => ResponseCode::ImATeapot,
            421 => ResponseCode::MisdirectedRequest,
            422 => ResponseCode::UnprocessableEntitiy,
            423 => ResponseCode::Locked,
            424 => ResponseCode::FailedDependency,
            426 => ResponseCode::UpgradeRequired,
            428 => ResponseCode::PreconditionRequired,
            429 => ResponseCode::TooManyRequests,
            431 => ResponseCode::RequestHeaderFieldsTooLarge,
            451 => ResponseCode::UnavailableForLegalReasons,
            // Server Error
            500 => ResponseCode::InternalServerError,
            501 => ResponseCode::NotImplemented,
            502 => ResponseCode::BadGateway,
            503 => ResponseCode::ServiceUnavailable,
            504 => ResponseCode::GatewayTimeout,
            505 => ResponseCode::HttpVersionNotSupported,
            506 => ResponseCode::VariantAlsoNegotiates,
            507 => ResponseCode::InsufficientStorage,
            508 => ResponseCode::LoopDetected,
            510 => ResponseCode::NotExtended,
            511 => ResponseCode::NetworkAuthenticationRequired,
            _ => ResponseCode::Undefined,
        }
    }

}

#[test]
pub fn methods_post() {
    let s = HttpMethods::Post.to_string();
    assert_eq!(s, "POST".to_owned());
}

#[test]
pub fn methods_get() {
    let s = HttpMethods::Get.to_string();
    assert_eq!(s, "GET".to_owned());
}

#[test]
pub fn response_code_success() {
    let s = ResponseCode::Continue.to_string();
    assert_eq!(s, "CONTINUE");
}<commit_msg>partialeq on constants<commit_after>use std::fmt;

#[derive(Clone,Debug)]
pub enum HttpMethods {
    Get,
    Post,
}

impl fmt::Display for HttpMethods {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s: String = format!("{:?}", self);
        write!(f, "{}", s.to_uppercase())
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum ResponseCode {
    // Testing
    Undefined = 0,
    // Informational
    Continue = 100,
    SwitchingProtocols = 101,
    Processing = 102,
    // Success
    Ok = 200,
    Created = 201,
    Accepted = 202,
    NonAuthoritativeInformation = 203,
    NoContent = 204,
    ResetContent = 205,
    PartialContent = 206,
    MultiStatus = 207,
    AlreadyReported = 208,
    ImUsed = 226,
    // Redirection
    MultipleChoices = 300,
    MovedPermanently = 301,
    Found = 302,
    SeeOther = 303,
    NotModified = 304,
    UseProxy = 305,
    SwitchProxy = 306,
    TemporaryRedirect = 307,
    PermanentRedirect = 308,
    // Client Error
    BadRequest = 400,
    Unauthorized = 401,
    PaymentRequired = 402,
    Forbidden = 403,
    NotFound = 404,
    MethodNotAllowed = 405,
    NotAcceptable = 406,
    ProxyAuthenticationRequired = 407,
    RequestTimeout = 408,
    Conflict = 409,
    Gone = 410,
    LengthRequired = 411,
    PreconditionFailed = 412,
    PayloadTooLarge = 413,
    UriTooLong = 414,
    UnsupportedMediaType = 415,
    RangeNotSatisified = 416,
    ExpectationFailed = 417,
    ImATeapot = 418,
    MisdirectedRequest = 421,
    UnprocessableEntitiy = 422,
    Locked = 423,
    FailedDependency = 424,
    UpgradeRequired = 426,
    PreconditionRequired = 428,
    TooManyRequests = 429,
    RequestHeaderFieldsTooLarge = 431,
    UnavailableForLegalReasons = 451,
    // Server Error
    InternalServerError = 500,
    NotImplemented = 501,
    BadGateway = 502,
    ServiceUnavailable = 503,
    GatewayTimeout = 504,
    HttpVersionNotSupported = 505,
    VariantAlsoNegotiates = 506,
    InsufficientStorage = 507,
    LoopDetected = 508 ,
    NotExtended = 510,
    NetworkAuthenticationRequired = 511,
}

impl fmt::Display for ResponseCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let s: String = format!("{:?}", self).to_owned();
        write!(f, "{}", &s.to_uppercase())
    }
}

impl ResponseCode {
    pub fn from_int(i: u32) -> ResponseCode {
        match i {
            // Testing
            0 => ResponseCode::Undefined,
            // Informational
            100 => ResponseCode::Continue,
            101 => ResponseCode::SwitchingProtocols,
            102 => ResponseCode::Processing,
            // Success
            200 => ResponseCode::Ok,
            201 => ResponseCode::Created,
            202 => ResponseCode::Accepted,
            203 => ResponseCode::NonAuthoritativeInformation,
            204 => ResponseCode::NoContent,
            205 => ResponseCode::ResetContent,
            206 => ResponseCode::PartialContent,
            207 => ResponseCode::MultiStatus,
            208 => ResponseCode::AlreadyReported,
            226 => ResponseCode::ImUsed,
            // Redirection
            300 => ResponseCode::MultipleChoices,
            301 => ResponseCode::MovedPermanently,
            302 => ResponseCode::Found,
            303 => ResponseCode::SeeOther,
            304 => ResponseCode::NotModified,
            305 => ResponseCode::UseProxy,
            306 => ResponseCode::SwitchProxy,
            307 => ResponseCode::TemporaryRedirect,
            308 => ResponseCode::PermanentRedirect,
            // Client Error
            400 => ResponseCode::BadRequest,
            401 => ResponseCode::Unauthorized,
            402 => ResponseCode::PaymentRequired,
            403 => ResponseCode::Forbidden,
            404 => ResponseCode::NotFound,
            405 => ResponseCode::MethodNotAllowed,
            406 => ResponseCode::NotAcceptable,
            407 => ResponseCode::ProxyAuthenticationRequired,
            408 => ResponseCode::RequestTimeout,
            409 => ResponseCode::Conflict,
            410 => ResponseCode::Gone,
            411 => ResponseCode::LengthRequired,
            412 => ResponseCode::PreconditionFailed,
            413 => ResponseCode::PayloadTooLarge,
            414 => ResponseCode::UriTooLong,
            415 => ResponseCode::UnsupportedMediaType,
            416 => ResponseCode::RangeNotSatisified,
            417 => ResponseCode::ExpectationFailed,
            418 => ResponseCode::ImATeapot,
            421 => ResponseCode::MisdirectedRequest,
            422 => ResponseCode::UnprocessableEntitiy,
            423 => ResponseCode::Locked,
            424 => ResponseCode::FailedDependency,
            426 => ResponseCode::UpgradeRequired,
            428 => ResponseCode::PreconditionRequired,
            429 => ResponseCode::TooManyRequests,
            431 => ResponseCode::RequestHeaderFieldsTooLarge,
            451 => ResponseCode::UnavailableForLegalReasons,
            // Server Error
            500 => ResponseCode::InternalServerError,
            501 => ResponseCode::NotImplemented,
            502 => ResponseCode::BadGateway,
            503 => ResponseCode::ServiceUnavailable,
            504 => ResponseCode::GatewayTimeout,
            505 => ResponseCode::HttpVersionNotSupported,
            506 => ResponseCode::VariantAlsoNegotiates,
            507 => ResponseCode::InsufficientStorage,
            508 => ResponseCode::LoopDetected,
            510 => ResponseCode::NotExtended,
            511 => ResponseCode::NetworkAuthenticationRequired,
            _ => ResponseCode::Undefined,
        }
    }

}

#[test]
pub fn methods_post() {
    let s = HttpMethods::Post.to_string();
    assert_eq!(s, "POST".to_owned());
}

#[test]
pub fn methods_get() {
    let s = HttpMethods::Get.to_string();
    assert_eq!(s, "GET".to_owned());
}

#[test]
pub fn response_code_success() {
    let s = ResponseCode::Continue.to_string();
    assert_eq!(s, "CONTINUE");
}
<|endoftext|>