<commit_before>extern crate getopts;
extern crate regex;

use std::env;
use std::io::{self, Read};
use getopts::Options;
use regex::Regex;
use cache::{AccessType, CacheSystem};

mod cache;

const C1_DEFAULT: u64    = 12;
const B1_DEFAULT: u64    = 5;
const S1_DEFAULT: u64    = 3;
const V_DEFAULT:  u64    = 3;
const C2_DEFAULT: u64   = 15;
const B2_DEFAULT: u64   = 5;
const S2_DEFAULT: u64   = 4;

fn print_usage() {
    println!("cachesim [OPTIONS] < traces/file.trace");
    println!("L1 Parameters:");
    println!("  -c C1\t\tThe total size of the L1 cache is 2^C1 bytes");
    println!("  -b B1\t\tThe size of a block in the L1 cache is 2^B1 bytes");
    println!("  -s S1\t\tThe number of blocks per set in L1 is 2^S1");
    println!("Victim cache parameters:");
    println!("  -v V\t\tThe number of blocks in the Victim Cache");
    println!("L2 Parameters:");
    println!("  -C C2\t\tThe total size of the L2 cache is 2^C2 bytes");
    println!("  -B B2\t\tThe size of a block in the L2 cache is 2^B2 bytes");
    println!("  -S S2\t\tThe number of blocks per set in L2 is 2^S2");
}

fn main() {
    // 1.) Begin by handling parameters
    let args : Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    opts.optopt("c", "", "C parameter for L1 cache", "C1");
    opts.optopt("b", "", "B parameter for L1 cache", "B1");
    opts.optopt("s", "", "S parameter for L1 cache", "S1");
    opts.optopt("v", "", "v parameter for Victim cache", "V");
    opts.optopt("C", "", "C parameter for L2 cache", "C2");
    opts.optopt("B", "", "B parameter for L2 cache", "B2");
    opts.optopt("S", "", "S parameter for L2 cache", "S2");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) },
    };

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

    // parse: String -> Option<u64>
    let parse = |s: String| {
        let result = s.parse::<u64>();
        match result {
            Ok(num) => { Some(num) },
            Err(e) => { panic!(e.to_string()) },
        }
    };

    // The parsing. Maybe I can do some kind of map() instead?
    let c1 = matches.opt_str("c").and_then(|s| parse(s)).unwrap_or(C1_DEFAULT);
    let b1 = matches.opt_str("b").and_then(|s| parse(s)).unwrap_or(B1_DEFAULT);
    let s1 = matches.opt_str("s").and_then(|s| parse(s)).unwrap_or(S1_DEFAULT);
    let v =  matches.opt_str("v").and_then(|s| parse(s)).unwrap_or(V_DEFAULT);
    let c2 = matches.opt_str("C").and_then(|s| parse(s)).unwrap_or(C2_DEFAULT);
    let b2 = matches.opt_str("B").and_then(|s| parse(s)).unwrap_or(B2_DEFAULT);
    let s2 = matches.opt_str("S").and_then(|s| parse(s)).unwrap_or(S2_DEFAULT);

    println!("Cache Settings");
    println!("c: {}", c1);
    println!("b: {}", b1);
    println!("s: {}", s1);
    println!("v: {}", v);
    println!("C: {}", c2);
    println!("B: {}", b2);
    println!("S: {}", s2);

    // 2.) Read the trace file
    // The contents of the trace file should be in trace_buffer
    // if the file was piped in through stdin

    let mut trace_buffer = String::new();
    if let Err(e) = io::stdin().read_to_string(&mut trace_buffer) {
        panic!(e.to_string());
    }

    // 3.) Create cache system and begin processing
    let mut cache_system = CacheSystem::new(c1, b1, s1, v, c2, b2, s2);

    let access_list = trace_buffer.split('\n');

    let re = Regex::new(r"(r|w)(\s+)(0x[:xdigit:]+)").unwrap();
    for access in access_list {
        if let Some(cap) = re.captures(access) {
            let mode: AccessType = match cap.at(1).unwrap() {
                "r" => AccessType::Read,
                "w" => AccessType::Write,
                _ => { panic!("Malformed trace file!") },
            };

            let address = match u64::from_str_radix(&cap.at(3).unwrap()[2..], 16) {
                Ok(v) => { v },
                Err(f) => { panic!(f.to_string()) },
            };

            cache_system.cache_access(mode, address);
        }
    }

    // 4.) Finish processing, and print out statistics
    cache_system.complete_cache();

    cache_system.print_statistics();
}
<commit_msg>No more regex means faster run times<commit_after>extern crate getopts;
extern crate regex;

use std::env;
use std::io::{self, Read};
use getopts::Options;
use cache::{AccessType, CacheSystem};

mod cache;

const C1_DEFAULT: u64    = 12;
const B1_DEFAULT: u64    = 5;
const S1_DEFAULT: u64    = 3;
const V_DEFAULT:  u64    = 3;
const C2_DEFAULT: u64   = 15;
const B2_DEFAULT: u64   = 5;
const S2_DEFAULT: u64   = 4;

fn print_usage() {
    println!("cachesim [OPTIONS] < traces/file.trace");
    println!("L1 Parameters:");
    println!("  -c C1\t\tThe total size of the L1 cache is 2^C1 bytes");
    println!("  -b B1\t\tThe size of a block in the L1 cache is 2^B1 bytes");
    println!("  -s S1\t\tThe number of blocks per set in L1 is 2^S1");
    println!("Victim cache parameters:");
    println!("  -v V\t\tThe number of blocks in the Victim Cache");
    println!("L2 Parameters:");
    println!("  -C C2\t\tThe total size of the L2 cache is 2^C2 bytes");
    println!("  -B B2\t\tThe size of a block in the L2 cache is 2^B2 bytes");
    println!("  -S S2\t\tThe number of blocks per set in L2 is 2^S2");
}

fn main() {
    // 1.) Begin by handling parameters
    let args : Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    opts.optopt("c", "", "C parameter for L1 cache", "C1");
    opts.optopt("b", "", "B parameter for L1 cache", "B1");
    opts.optopt("s", "", "S parameter for L1 cache", "S1");
    opts.optopt("v", "", "v parameter for Victim cache", "V");
    opts.optopt("C", "", "C parameter for L2 cache", "C2");
    opts.optopt("B", "", "B parameter for L2 cache", "B2");
    opts.optopt("S", "", "S parameter for L2 cache", "S2");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) },
    };

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

    // parse: String -> Option<u64>
    let parse = |s: String| {
        let result = s.parse::<u64>();
        match result {
            Ok(num) => { Some(num) },
            Err(e) => { panic!(e.to_string()) },
        }
    };

    // The parsing. Maybe I can do some kind of map() instead?
    let c1 = matches.opt_str("c").and_then(|s| parse(s)).unwrap_or(C1_DEFAULT);
    let b1 = matches.opt_str("b").and_then(|s| parse(s)).unwrap_or(B1_DEFAULT);
    let s1 = matches.opt_str("s").and_then(|s| parse(s)).unwrap_or(S1_DEFAULT);
    let v =  matches.opt_str("v").and_then(|s| parse(s)).unwrap_or(V_DEFAULT);
    let c2 = matches.opt_str("C").and_then(|s| parse(s)).unwrap_or(C2_DEFAULT);
    let b2 = matches.opt_str("B").and_then(|s| parse(s)).unwrap_or(B2_DEFAULT);
    let s2 = matches.opt_str("S").and_then(|s| parse(s)).unwrap_or(S2_DEFAULT);

    println!("Cache Settings");
    println!("c: {}", c1);
    println!("b: {}", b1);
    println!("s: {}", s1);
    println!("v: {}", v);
    println!("C: {}", c2);
    println!("B: {}", b2);
    println!("S: {}", s2);

    // 2.) Read the trace file
    // The contents of the trace file should be in trace_buffer
    // if the file was piped in through stdin

    let mut trace_buffer = String::new();
    if let Err(e) = io::stdin().read_to_string(&mut trace_buffer) {
        panic!(e.to_string());
    }

    // 3.) Create cache system and begin processing
    let mut cache_system = CacheSystem::new(c1, b1, s1, v, c2, b2, s2);

    let access_list = trace_buffer.split('\n');

    for access in access_list {
        let tokens: Vec<&str> = access.split_whitespace().collect();
        if tokens.len() != 0 {
            let mode: AccessType = match tokens[0] {
                "r" => AccessType::Read,
                "w" => AccessType::Write,
                 _  => { panic!("Malformed trace file!") },
            };

            let address = match u64::from_str_radix(&tokens[1][2..], 32) {
                Ok(v)  => { v },
                Err(f) => { panic!(f.to_string()) },
            };

            cache_system.cache_access(mode, address);
        }
    }

    // 4.) Finish processing, and print out statistics
    cache_system.complete_cache();

    cache_system.print_statistics();
}
<|endoftext|>


<commit_before>#![crate_name="magog"]
#![feature(path_ext, old_path)]

extern crate image;
extern crate "calx_util" as util;

#[macro_use]
extern crate "calx_backend" as backend;

extern crate world;
extern crate time;

use backend::{Canvas};

use gamestate::GameState;
use titlestate::TitleState;

pub static SCREEN_W: u32 = 640;
pub static SCREEN_H: u32 = 360;

pub mod drawable;
pub mod tilecache;
pub mod viewutil;
pub mod worldview;
mod gamestate;
mod titlestate;
mod sprite;
mod msg_queue;
mod console;

pub trait State {
    fn process(&mut self, event: backend::Event) -> Option<Transition>;
}

pub enum Transition {
    Game(Option<u32>),
    Title,
    Exit,
}

pub fn version() -> String {
    let next_release = "0.1.0";
    let git_hash = include_str!("git_hash.inc");
    // Set is_release to true for one commit to make a release.
    let is_release = false;

    if is_release {
        format!("{}", next_release)
    } else {
        format!("{}-alpha+g{}", next_release, git_hash)
    }
}

pub fn compiler_version() -> String {
    include_str!("../rustc_version.txt").to_string()
}

pub fn screenshot(ctx: &mut Canvas) {
    use time;
    use std::path;
    use std::fs::PathExt;
    use image;

    let timestamp = time::precise_time_s() as u64;

    // Create screenshot filenames by concatenating the current timestamp in
    // seconds with a running number from 00 to 99. 100 shots per second
    // should be good enough.

    // Default if we fail to generate any of the 100 candidates for this
    // second, just overwrite with the "xx" prefix then.
    let mut filename = format!("magog-{}{}.png", timestamp, "xx");

    // Run through candidates for this second.
    for i in 0..100 {
        let test_filename = format!("magog-{}{:02}.png", timestamp, i);
        if !path::Path::new(&test_filename).exists() {
            filename = test_filename;
            break;
        }
    }

    let shot = ctx.screenshot();
    let _ = image::save_buffer(&Path::new(filename), shot.as_slice(), shot.width(), shot.height(), image::ColorType::RGB(8));
}

pub fn main() {
    println!("Magog v{}", version());
    println!("{}", compiler_version());
    let mut canvas = backend::CanvasBuilder::new()
        .set_size(SCREEN_W, SCREEN_H)
        .set_frame_interval(0.030f64);
    tilecache::init(&mut canvas);
    let mut state: Box<State> = Box::new(TitleState::new());

    for evt in canvas.run() {
        match state.process(evt) {
            Some(Transition::Title) => { state = Box::new(TitleState::new()); }
            Some(Transition::Game(seed)) => {
                state = Box::new(GameState::new(seed)); }
            Some(Transition::Exit) => { break; }
            _ => ()
        }
    }
}
<commit_msg>Multithreaded screenshotting<commit_after>#![crate_name="magog"]
#![feature(path_ext, old_path)]

extern crate image;
extern crate "calx_util" as util;

#[macro_use]
extern crate "calx_backend" as backend;

extern crate world;
extern crate time;

use backend::{Canvas};

use gamestate::GameState;
use titlestate::TitleState;

pub static SCREEN_W: u32 = 640;
pub static SCREEN_H: u32 = 360;

pub mod drawable;
pub mod tilecache;
pub mod viewutil;
pub mod worldview;
mod gamestate;
mod titlestate;
mod sprite;
mod msg_queue;
mod console;

pub trait State {
    fn process(&mut self, event: backend::Event) -> Option<Transition>;
}

pub enum Transition {
    Game(Option<u32>),
    Title,
    Exit,
}

pub fn version() -> String {
    let next_release = "0.1.0";
    let git_hash = include_str!("git_hash.inc");
    // Set is_release to true for one commit to make a release.
    let is_release = false;

    if is_release {
        format!("{}", next_release)
    } else {
        format!("{}-alpha+g{}", next_release, git_hash)
    }
}

pub fn compiler_version() -> String {
    include_str!("../rustc_version.txt").to_string()
}

pub fn screenshot(ctx: &mut Canvas) {
    use time;
    use std::path;
    use std::fs::{self, File, PathExt};
    use std::thread;
    use image;

    let shot = ctx.screenshot();

    // XXX: If the game is terminated right after taking a screenshot, the
    // screenshotting thread will be stopped and an incomplete image file will
    // result. Not sure if there's a better solution for this than some kind
    // of global worker thread pool where the screenshot thread should be
    // added.
    thread::spawn(move || {
        let timestamp = time::precise_time_s() as u64;
        // Create screenshot filenames by concatenating the current timestamp in
        // seconds with a running number from 00 to 99. 100 shots per second
        // should be good enough.

        // Default if we fail to generate any of the 100 candidates for this
        // second, just overwrite with the "xx" prefix then.
        let mut filename = format!("magog-{}{}.png", timestamp, "xx");

        // Run through candidates for this second.
        for i in 0..100 {
            let test_filename = format!("magog-{}{:02}.png", timestamp, i);
            if !path::Path::new(&test_filename).exists() {
                // Thread-safe claiming: create_dir will fail if the dir
                // already exists (it'll exist if another thread is gunning
                // for the same filename and managed to get past us here).
                // At least assuming that create_dir is atomic...
                let squat_dir = format!(".tmp-{}{:02}", timestamp, i);
                if std::fs::create_dir(&squat_dir).is_ok() {
                    File::create(&test_filename).unwrap();
                    filename = test_filename;
                    fs::remove_dir(&squat_dir).unwrap();
                    break;
                } else {
                    continue;
                }
            }
        }

        let _ = image::save_buffer(&Path::new(filename), shot.as_slice(), shot.width(), shot.height(), image::ColorType::RGB(8));
    });
}

pub fn main() {
    println!("Magog v{}", version());
    println!("{}", compiler_version());
    let mut canvas = backend::CanvasBuilder::new()
        .set_size(SCREEN_W, SCREEN_H)
        .set_frame_interval(0.030f64);
    tilecache::init(&mut canvas);
    let mut state: Box<State> = Box::new(TitleState::new());

    for evt in canvas.run() {
        match state.process(evt) {
            Some(Transition::Title) => { state = Box::new(TitleState::new()); }
            Some(Transition::Game(seed)) => {
                state = Box::new(GameState::new(seed)); }
            Some(Transition::Exit) => { break; }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
}
<commit_msg>working parser!<commit_after>#![feature(core)]
#![allow(dead_code)] // for debug

use std::ops::Add;
use std::num::FromPrimitive;
use std::iter::{Iterator, IteratorExt};
use std::str::FromStr;
use std::ascii::AsciiExt;
use std::fmt::{self, Display, Formatter};

#[derive(Debug)]
struct CrontabRecord {
    mins: Minutes,
    hrs: Hours,
    days: Days,
    mons: Months,
    dows: DaysOfWeek,
    user: Option<String>,
    cmd: String
}

#[derive(Debug)]
struct CrontabRecordParseError;

macro_rules! parse_cron_rec_field {
    ($iter:expr) => {
        try!($iter.next().ok_or(IntervalParseError).and_then(FromStr::from_str).map_err(|_| CrontabRecordParseError))
    }
}

impl FromStr for CrontabRecord {
    type Err = CrontabRecordParseError;

    fn from_str(s: &str) -> Result<CrontabRecord, CrontabRecordParseError> {
        let seps = [' ', '\t'];
        let mut splits = s.split(&seps[..]);
        Ok(CrontabRecord {
            mins: parse_cron_rec_field!(splits),
            hrs: parse_cron_rec_field!(splits),
            days: parse_cron_rec_field!(splits),
            mons: parse_cron_rec_field!(splits),
            dows: parse_cron_rec_field!(splits),
            user: None,
            cmd: splits.collect::<Vec<&str>>().connect(" ")
        })
    }
}

type Minutes = Vec<Interval<Minute>>;
type Hours = Vec<Interval<Hour>>;
type Days = Vec<Interval<Day>>;
type Months = Vec<Interval<Month>>;
type DaysOfWeek = Vec<Interval<DayOfWeek>>;

#[derive(Debug)]
enum Interval<T: Limited> {
    Value(T),
    Range(T, T, u8),
    Full(u8)
}

#[derive(Debug)]
struct IntervalParseError;

impl<T: Limited + Display> Display for Interval<T> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Interval::Value(val) => val.fmt(f),
            Interval::Range(from, to, step) => from.fmt(f)
                .and_then(|_| f.write_str("-"))
                .and_then(|_| to.fmt(f))
                .and_then(|_| if step > 1 {
                    f.write_str("/").and_then(|_| step.fmt(f))
                } else {
                    Ok(())
                }),
            Interval::Full(step) => f.write_str("*")
                .and_then(|_| if step > 1 {
                    f.write_str("/").and_then(|_| step.fmt(f))
                } else {
                    Ok(())
                })
        }
    }
}

impl<T: Limited + FromStr> FromStr for Interval<T> {
    type Err = IntervalParseError;
    fn from_str(s: &str) -> Result<Interval<T>, IntervalParseError> {
        let (range, step): (&str, u8) = if let Some(slash) = s.find('/') {
            (&s[..slash], try!(s[slash+1..].parse().map_err(|_| IntervalParseError))) // FIXME
        } else {
            (s, 1)
        };

        if step == 0 {
            return Err(IntervalParseError)
        }

        if range == "*" {
            return Ok(Interval::Full(step))
        }

        let (from, to): (T, T) = if let Some(hyphen) = range.find('-') {
            (try!(range[..hyphen].parse().map_err(|_| IntervalParseError)),
            try!(range[hyphen+1..].parse().map_err(|_| IntervalParseError)))
        } else {
            return range.parse().map_err(|_| IntervalParseError).map(Interval::Value);
        };

        if from > to {
            return Err(IntervalParseError)
        }

        Ok(Interval::Range(from, to, step))
    }
}

impl<T> Interval<T> where T: Limited {
    fn new(val: T) -> Interval<T> {
        Interval::Value(val)
    }

    fn full_step(step: u8) -> Interval<T> {
        Interval::Full(step)
    }

    fn full() -> Interval<T> {
        Interval::Full(1)
    }

    fn from_range(from: T, to: T) -> Interval<T> {
        Interval::Range(from, to, 1)
    }

    fn from_range_step(from: T, to: T, step: u8) -> Interval<T> {
        Interval::Range(from, to, step)
    }

    fn iter(&self) -> IntervalIter<T> {
        match *self {
            Interval::Value(v) => IntervalIter { cur: v, max: v, step: 1, stop: false },
            Interval::Range(f, t, s) => IntervalIter { cur: f, max: t, step: s, stop: false },
            Interval::Full(s) => IntervalIter { cur: T::min_value(), max: T::max_value(), step: s, stop: false }
        }
    }
}

#[derive(Debug)]
struct IntervalIter<T: Limited> {
    cur: T,
    max: T,
    step: u8,
    stop: bool
}

impl<T: Limited> Iterator for IntervalIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        if self.stop {
            return None;
        }

        if self.cur <= self.max {
            let result = self.cur;
            self.cur = self.cur + self.step;
            self.stop = result >= self.max;
            Some(result)
        } else {
            self.stop = true;
            None
        }
    }
}

trait Limited: Add<u8, Output=Self> + PartialOrd + Copy {
    fn min_value() -> Self;
    fn max_value() -> Self;
}

macro_rules! limited {
    ($name:ident, min=$min:expr, max=$max:expr) => {
        impl Limited for $name {
            fn min_value() -> $name { $name($min) }
            fn max_value() -> $name { $name($max) }
        }

        impl Add<u8> for $name {
            type Output = $name;
            fn add(self, rhs: u8) -> $name {
                //$name(((self.0 - $min) + rhs) % ($max - $min) + $min)
                let val = self.0 + rhs;
                $name(if val < $min { $min } else if val > $max { $max } else { val })
            }
        }

        impl Display for $name {
            #[inline]
            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
                self.0.fmt(f)
            }
        }

        impl FromStr for $name {
            type Err = <u8 as FromStr>::Err;
            #[inline]
            fn from_str(s: &str) -> Result<$name, <u8 as FromStr>::Err> {
                s.parse().map($name)
            }
        }
    }
}

#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct Minute(u8);
limited!(Minute, min=0, max=59);

#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct Hour(u8);
limited!(Hour, min=0, max=23);

#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct Day(u8);
limited!(Day, min=1, max=31);

#[derive(Debug, Copy, FromPrimitive, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
enum Month {
    January = 1,
    February = 2,
    March = 3,
    April = 4,
    May = 5,
    June = 6,
    July = 7,
    August = 8,
    September = 9,
    October = 10,
    November = 11,
    December = 12
}

#[derive(Debug)]
struct MonthParseError;

impl FromStr for Month {
    type Err = MonthParseError;
    fn from_str(s: &str) -> Result<Month, MonthParseError> {
        s.parse::<u8>()
            .map_err(|_| MonthParseError)
            .and_then(|v| Month::from_u8(v).ok_or(MonthParseError))
            .or_else(|_| match &*s[..3].to_ascii_lowercase() {
                "jan" => Ok(Month::January),
                "feb" => Ok(Month::February),
                "mar" => Ok(Month::March),
                "apr" => Ok(Month::April),
                "may" => Ok(Month::May),
                "jun" => Ok(Month::June),
                "jul" => Ok(Month::July),
                "aug" => Ok(Month::August),
                "sep" => Ok(Month::September),
                "oct" => Ok(Month::October),
                "nov" => Ok(Month::November),
                "dec" => Ok(Month::December),
                _ => Err(MonthParseError)
            })
    }
}

impl Display for Month {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(match *self {
            Month::January => "Jan",
            Month::February => "Feb",
            Month::March => "Mar",
            Month::April => "Apr",
            Month::May => "May",
            Month::June => "Jun",
            Month::July => "Jul",
            Month::August => "Aug",
            Month::September => "Sep",
            Month::October => "Oct",
            Month::November => "Nov",
            Month::December => "Dec"
        })
    }
}

impl Limited for Month {
    fn min_value() -> Month { Month::January }
    fn max_value() -> Month { Month::December }
}

impl Add<u8> for Month {
    type Output = Month;
    fn add(self, rhs: u8) -> Month {
        let val = self as u8 + rhs;
        if val < 1 { Month::January }
        else if val > 12 { Month::December }
        else { FromPrimitive::from_u8(val).unwrap() }
    }
}

#[derive(Debug, Copy, FromPrimitive, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
enum DayOfWeek {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}
impl Limited for DayOfWeek {
    fn min_value() -> DayOfWeek { DayOfWeek::Sunday }
    fn max_value() -> DayOfWeek { DayOfWeek::Saturday }
}

impl Display for DayOfWeek {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.write_str(match *self {
            DayOfWeek::Sunday => "Sun",
            DayOfWeek::Monday => "Mon",
            DayOfWeek::Tuesday => "Tue",
            DayOfWeek::Wednesday => "Wed",
            DayOfWeek::Thursday => "Thu",
            DayOfWeek::Friday => "Fri",
            DayOfWeek::Saturday => "Sat",
        })
    }
}

#[derive(Debug)]
struct DayOfWeekParseError;

impl FromStr for DayOfWeek {
    type Err = DayOfWeekParseError;
    fn from_str(s: &str) -> Result<DayOfWeek, DayOfWeekParseError> {
        s.parse::<u8>()
            .map_err(|_| DayOfWeekParseError)
            .and_then(|v| DayOfWeek::from_u8(v % 7).ok_or(DayOfWeekParseError))
            .or_else(|_| match &*s[..3].to_ascii_lowercase() {
                "sun" => Ok(DayOfWeek::Sunday),
                "mon" => Ok(DayOfWeek::Monday),
                "tue" => Ok(DayOfWeek::Tuesday),
                "wed" => Ok(DayOfWeek::Wednesday),
                "thu" => Ok(DayOfWeek::Thursday),
                "fri" => Ok(DayOfWeek::Friday),
                "sat" => Ok(DayOfWeek::Saturday),
                _ => Err(DayOfWeekParseError)
            })
    }
}

impl Add<u8> for DayOfWeek {
    type Output = DayOfWeek;
    fn add(self, rhs: u8) -> DayOfWeek {
        let val = self as u8 + rhs;
        if val > 6 { DayOfWeek::Saturday }
        else { FromPrimitive::from_u8(val).unwrap() }
    }
}

impl<T: Limited + FromStr> FromStr for Vec<Interval<T>> {
    type Err = IntervalParseError;
    fn from_str(s: &str) -> Result<Vec<Interval<T>>, IntervalParseError> {
        s.split(',').map(|v| v.parse::<Interval<T>>()).collect()
    }
}

fn main() {
    let s : Vec<Interval<DayOfWeek>> = "mon,sun-sat/2,*".parse().unwrap();
    println!("{}", s[1]);
    for v in s.iter().flat_map(Interval::iter) {
        println!("{:?}", v);
    }

    println!("{:?}", "* b c\td\t e  ".splitn(6, &[' ', '\t'][..]).collect::<Vec<&str>>());

    println!("{:?}", "* * * * * root command with args".parse::<CrontabRecord>());
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate termios;

use libc::STDIN_FILENO;
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Read, ErrorKind};

struct TermReset {
    orig_term: Termios
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

fn iscntrl(c: u8) -> bool {
    unsafe {
        libc::iscntrl(c as i32) != 0
    }
}

fn main() {
    let _reset = enable_raw_mode().unwrap();

    let mut stdin = io::stdin();
    let mut buf = [0; 1];

    loop {
        buf[0] = 0;
        let n = stdin.read(&mut buf)
                     .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                     .expect("read");
        if n > 0 {
            let c = buf[0];
            if c == b'q' {
                break;
            }
            if iscntrl(c) {
                print!("{}\r\n", &c);
            } else {
                print!("{} ({})\r\n", &c, c as char);
            }
        }
    }
}
<commit_msg>Quit program with ctrl-q<commit_after>extern crate libc;
extern crate termios;

use libc::STDIN_FILENO;
use termios::{Termios, tcsetattr, TCSAFLUSH, VMIN, VTIME};
use termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON};
use termios::{OPOST, CS8};
use termios::{ECHO, ICANON, IEXTEN, ISIG};

use std::io::{self, Read, ErrorKind};

macro_rules! ctrl_key {
    ($k:expr) => ($k & 0x1f);
}

struct TermReset {
    orig_term: Termios
}

impl Drop for TermReset {
    fn drop(&mut self) {
        tcsetattr(STDIN_FILENO, TCSAFLUSH, &self.orig_term).unwrap()
    }
}

fn enable_raw_mode() -> io::Result<TermReset> {
    let mut term = Termios::from_fd(STDIN_FILENO)?;
    let mode = TermReset { orig_term: term.clone() };

    term.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    term.c_oflag &= !OPOST;
    term.c_cflag |= CS8;
    term.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
    term.c_cc[VMIN] = 0;
    term.c_cc[VTIME] = 1;

    tcsetattr(STDIN_FILENO, TCSAFLUSH, &term)?;
    Ok(mode)
}

fn iscntrl(c: u8) -> bool {
    unsafe {
        libc::iscntrl(c as i32) != 0
    }
}

fn main() {
    let _reset = enable_raw_mode().unwrap();

    let mut stdin = io::stdin();
    let mut buf = [0; 1];

    loop {
        buf[0] = 0;
        let n = stdin.read(&mut buf)
                     .or_else(|e| if e.kind() == ErrorKind::WouldBlock { Ok(0) } else { Err(e) })
                     .expect("read");
        if n > 0 {
            let c = buf[0];
            if c == ctrl_key!(b'q') {
                break;
            }
            if iscntrl(c) {
                print!("{}\r\n", &c);
            } else {
                print!("{} ({})\r\n", &c, c as char);
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#![deny(non_camel_case_types)]
#![deny(non_uppercase_statics)]
#![deny(unnecessary_qualification)]
#![deny(unnecessary_typecast)]

#![feature(macro_rules)]
#![feature(phase)]

extern crate native;
extern crate serialize;
extern crate collections;
extern crate time;
extern crate rand;
extern crate cgmath;
extern crate glfw;
extern crate gl;
extern crate stb_image;
extern crate stb_tt;

#[phase(plugin, link)]
extern crate error_context;

use visualizer::visualizer::Visualizer;

mod core;
mod visualizer;

fn main() {
    let mut visualizer = Visualizer::new();
    while visualizer.is_running() {
        visualizer.tick();
    }
}

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Updated for Rust 0dfc90a: *const, *mut<commit_after>// See LICENSE file for copyright and license details.

#![deny(non_camel_case_types)]
#![deny(non_uppercase_statics)]
#![deny(unnecessary_qualification)]
#![deny(unnecessary_typecast)]

#![feature(macro_rules)]
#![feature(phase)]

extern crate native;
extern crate serialize;
extern crate collections;
extern crate time;
extern crate rand;
extern crate cgmath;
extern crate glfw;
extern crate gl;
extern crate stb_image;
extern crate stb_tt;

#[phase(plugin, link)]
extern crate error_context;

use visualizer::visualizer::Visualizer;

mod core;
mod visualizer;

fn main() {
    let mut visualizer = Visualizer::new();
    while visualizer.is_running() {
        visualizer.tick();
    }
}

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    native::start(argc, argv, main)
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>extern crate ast;

use ast::Evaluate;

fn main() {
	let program: ast::Program = ast::Program::If(
		ast::Condition::Less(
			Box::new(ast::Expression::Sensor(ast::Sensor::Vx)),
			Box::new(ast::Expression::Multiply(
				Box::new(ast::Expression::Constant(2.0)),
				Box::new(ast::Expression::Constant(3.0))
			))
		),
		Box::new(ast::Program::Command(ast::Command::Left)),
		Box::new(ast::Program::Command(ast::Command::Right))
	);

	let data: ast::SensorData = ast::SensorData { x: 37.0, y: 51.0, vx: 6.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		ast::Command::Skip  => "skip",
		ast::Command::Left  => "turnLeft",
		ast::Command::Right => "turnRight",
		ast::Command::Up    => "thruster",
	};

	println!("action is {}", message);
}
<commit_msg>Use `use` to remove some language noise<commit_after>extern crate ast;

use ast::Evaluate;

use ast::Program::{If,Command};
use ast::Condition::Less;
use ast::Expression::{Sensor,Multiply,Constant};

fn main() {
	let program: ast::Program = If(
			Less(
			Box::new(Sensor(ast::Sensor::Vx)),
			Box::new(Multiply(
				Box::new(Constant(2.0)),
				Box::new(Constant(3.0))
			))
		),
		Box::new(Command(ast::Command::Left)),
		Box::new(Command(ast::Command::Right))
	);

	let data: ast::SensorData = ast::SensorData { x: 37.0, y: 51.0, vx: 6.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		ast::Command::Skip  => "skip",
		ast::Command::Left  => "turnLeft",
		ast::Command::Right => "turnRight",
		ast::Command::Up    => "thruster",
	};

	println!("action is {}", message);
}
<|endoftext|>


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

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, str};
use std::cell::Cell;
use std::os::list_dir_path;
use std::rt::io::Reader;
use std::rt::io::process::{Process, ProcessConfig, Ignored, CreatePipe};

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    if !run_tests_console(&opts, tests) {
        os::set_exit_status(1);
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    // FIXME (#1094): not the right way to transform a path
    files.retain( |file| file.display().to_str().ends_with(".html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let create_pipe = CreatePipe(true, false); // rustc #10228

    let config = ProcessConfig {
        program: "./servo",
        args: [~"-z", infile.clone()],
        env: None,
        cwd: None,
        io: [Ignored, create_pipe, Ignored]
    };

    let mut prc = Process::new(config).unwrap();
    let stdout = prc.io[1].get_mut_ref();
    let mut output = ~[];
    loop {
        let byte = stdout.read_byte();
        match byte {
            Some(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            None => break
        }
    }

    let out = str::from_utf8(output);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<commit_msg>auto merge of #1273 : sammykim/servo/issue-1197, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, str};
use std::cell::Cell;
use std::os::list_dir_path;
use std::rt::io::Reader;
use std::rt::io::process::{Process, ProcessConfig, Ignored, CreatePipe};

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    if !run_tests_console(&opts, tests) {
        os::set_exit_status(1);
    }
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    files.retain(|file| file.extension_str() == Some("html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let create_pipe = CreatePipe(true, false); // rustc #10228

    let config = ProcessConfig {
        program: "./servo",
        args: [~"-z", infile.clone()],
        env: None,
        cwd: None,
        io: [Ignored, create_pipe, Ignored]
    };

    let mut prc = Process::new(config).unwrap();
    let stdout = prc.io[1].get_mut_ref();
    let mut output = ~[];
    loop {
        let byte = stdout.read_byte();
        match byte {
            Some(byte) => {
                print!("{}", byte as char);
                output.push(byte);
            }
            None => break
        }
    }

    let out = str::from_utf8(output);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<|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 stats;
extern crate clap;

mod args;
mod http_status;
mod log_parser;
use log_parser::parse_line;
use log_parser::log_events::*;
mod request_response_matcher;
use request_response_matcher::*;
mod filter;
mod analyzer;
mod render;
use render::*;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = args::parse_args(env::args()).unwrap();

    let input: Box<io::Read> = match args.filename.as_ref() {
        "-" => Box::new(io::stdin()),
        _ => Box::new(File::open(&args.filename).unwrap()),
    };

    let (times, first_request) = extract_times(input, &args.conditions);

    let result = analyzer::analyze(&times);

    match result {
        Some(result) => {
            if args.graphite_server.is_some() {
                let mut stream = TcpStream::connect((args.graphite_server.unwrap().as_ref(),
                                                 args.graphite_port.unwrap()))
                    .expect("Could not connect to the Graphite server");
                let timezone = first_request.unwrap().time.timezone();

                let mut renderer = render::GraphiteRenderer::new(
                    UTC::now().with_timezone(&timezone),
                    args.graphite_prefix,
                    &mut stream,
                );
                renderer.render(result);
            } else {
                let mut renderer = render::TerminalRenderer::new();
                renderer.render(result);
            }
        }
        None => println_stderr!("No matching log lines in file."),
    }
}

fn extract_times(input: Box<io::Read>,
                 conditions: &filter::FilterConditions)
                 -> (Vec<i64>, Option<Request>) {
    let reader = io::BufReader::new(input);
    let lines = reader.lines();

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();
    let mut times: Vec<i64> = Vec::new();

    // We need to store 1 Request in order to determine the timezone later
    let mut first_request: Option<Request> = None;

    for line in lines {
        let line_value = &line.unwrap();

        let parsed_line = parse_line(line_value);

        match parsed_line {
            Ok(event) => {
                match event {
                    LogEvent::Request(request) => {
                        if first_request.is_none() {
                            first_request = Some(request.clone());
                        }
                        requests.push(request)
                    }
                    LogEvent::Response(response) => responses.push(response),
                }

                let pairs = extract_matching_request_response_pairs(&mut requests, &mut responses);

                let mut new_times: Vec<i64> = pairs.iter()
                    .filter(|pair| filter::matches_filter(&pair, conditions))
                    .map(|pair| pair.response.response_time.num_milliseconds())
                    .collect();

                times.append(&mut new_times);
            }
            Err(err) => println_stderr!("{}", err),
        }
    }
    (times, first_request)
}

#[test]
fn test_extract_times() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let (times, first_request) = extract_times(Box::new(File::open("src/test/simple-1.log")
                                                   .unwrap()),
                                               &conditions);

    assert_eq!(times, vec![7, 10]);
    assert_eq!(first_request.unwrap().id, 1);
}

#[test]
fn test_extract_times_ignore_broken_lines() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let (times, first_request) = extract_times(Box::new(File::open("src/test/broken.log")
                                                   .unwrap()),
                                               &conditions);

    assert_eq!(times, vec![7]);
    assert_eq!(first_request.unwrap().id, 1);
}
<commit_msg>Cleaner Renderer creation<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 stats;
extern crate clap;

mod args;
mod http_status;
mod log_parser;
use log_parser::parse_line;
use log_parser::log_events::*;
mod request_response_matcher;
use request_response_matcher::*;
mod filter;
mod analyzer;
mod render;
use render::*;

// http://stackoverflow.com/a/27590832/376138
macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = args::parse_args(env::args()).unwrap();

    let input: Box<io::Read> = match args.filename.as_ref() {
        "-" => Box::new(io::stdin()),
        _ => Box::new(File::open(&args.filename).unwrap()),
    };

    let (times, first_request) = extract_times(input, &args.conditions);

    let result = analyzer::analyze(&times);

    let mut stream;
    let mut renderer: Box<Renderer>;

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

        renderer = Box::new(GraphiteRenderer::new(
                    UTC::now().with_timezone(&first_request.unwrap().time.timezone()),
                    args.graphite_prefix,
                    &mut stream,
                ));
    } else {
        renderer = Box::new(TerminalRenderer::new());
    }

    match result {
        Some(result) => {
            renderer.render(result);
        }
        None => println_stderr!("No matching log lines in file."),
    }
}

fn extract_times(input: Box<io::Read>,
                 conditions: &filter::FilterConditions)
                 -> (Vec<i64>, Option<Request>) {
    let reader = io::BufReader::new(input);
    let lines = reader.lines();

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();
    let mut times: Vec<i64> = Vec::new();

    // We need to store 1 Request in order to determine the timezone later
    let mut first_request: Option<Request> = None;

    for line in lines {
        let line_value = &line.unwrap();

        let parsed_line = parse_line(line_value);

        match parsed_line {
            Ok(event) => {
                match event {
                    LogEvent::Request(request) => {
                        if first_request.is_none() {
                            first_request = Some(request.clone());
                        }
                        requests.push(request)
                    }
                    LogEvent::Response(response) => responses.push(response),
                }

                let pairs = extract_matching_request_response_pairs(&mut requests, &mut responses);

                let mut new_times: Vec<i64> = pairs.iter()
                    .filter(|pair| filter::matches_filter(&pair, conditions))
                    .map(|pair| pair.response.response_time.num_milliseconds())
                    .collect();

                times.append(&mut new_times);
            }
            Err(err) => println_stderr!("{}", err),
        }
    }
    (times, first_request)
}

#[test]
fn test_extract_times() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let (times, first_request) = extract_times(Box::new(File::open("src/test/simple-1.log")
                                                   .unwrap()),
                                               &conditions);

    assert_eq!(times, vec![7, 10]);
    assert_eq!(first_request.unwrap().id, 1);
}

#[test]
fn test_extract_times_ignore_broken_lines() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let (times, first_request) = extract_times(Box::new(File::open("src/test/broken.log")
                                                   .unwrap()),
                                               &conditions);

    assert_eq!(times, vec![7]);
    assert_eq!(first_request.unwrap().id, 1);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::CString;
use std::io::{BufferedReader, Command, File, fs};
use std::os;
use std::path::Path;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

#[cfg(target_os = "linux")]
fn true_binary() -> &'static str {
    "/bin/true"
}

#[cfg(target_os = "macos")]
fn true_binary() -> &'static str {
    "/usr/bin/true"
}

fn build_snappy() {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new("make").args(&["-C", snappy_path.as_str().unwrap()])
                        .arg("distclean")
                        .status().unwrap();

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").cwd(&snappy_path)
                               .arg("CXXFLAGS=-fPIC")
                               .status().unwrap();

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new("make").args(&["-C", snappy_path.as_str().unwrap()])
                        .status().unwrap();

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let out_dir = Path::new(os::getenv("OUT_DIR").unwrap());

    println!("[build] Copying output files");
    fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a")).unwrap();
}

fn build_leveldb(with_snappy: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new("make").args(&["-C", leveldb_path.as_str().unwrap()])
                        .arg("clean")
                        .status().unwrap();

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<CString, CString> = os::env_as_bytes().into_iter().map(|(k, v)| {
        (
            CString::from_slice(k.as_slice()),
            CString::from_slice(v.as_slice())
        )
    }).collect();

    if with_snappy {
        let linker_path = os::getenv("OUT_DIR").unwrap();
        env_map.insert(
            CString::from_slice("LDFLAGS".as_bytes()),
            CString::from_slice(format!("-L{}", linker_path).as_bytes())
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            CString::from_slice("CXXFLAGS".as_bytes()),
            CString::from_slice(format!("-I{} -fPIC", snappy_path.as_str().unwrap()).as_bytes())
        );
    }

    // Convert to the format that `env_set_all` is expecting.
    let env_arr: Vec<(CString, CString)> = env_map.into_iter().collect();

    // Build the library
    println!("[leveldb] Building");
    Command::new("make")
            .args(&["-C", leveldb_path.as_str().unwrap()])
            .env_set_all(env_arr.as_slice())
            .status().unwrap();

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let out_dir = Path::new(os::getenv("OUT_DIR").unwrap());

    println!("[build] Copying output files");
    fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a")).unwrap();
}

fn main() {
    println!("[build] Started");

    let have_snappy = os::getenv("CARGO_FEATURE_SNAPPY").is_some();

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy();
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let mut file = BufferedReader::new(File::open(&template_path));

            file.lines().map(|line| {
                let mut line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str(true_binary());
                    tmp.push_str("  # ");
                    tmp.push_str(line.as_slice());
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path);
        for line in new_lines.iter() {
            f.write_str(line.as_slice());
        }

        println!("[build] Patching complete");
    }

    // Build LevelDB
    build_leveldb(have_snappy);

    // Print the appropriate linker flags
    let out_dir = os::getenv("OUT_DIR").unwrap();
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb -l stdc++"
    } else {
        "-l static=leveldb -l stdc++"
    };
    println!("cargo:rustc-flags=-L native={} {} -l stdc++", out_dir, linker_flags);

    println!("[build] Finished");
}
<commit_msg>Properly set permissions on LevelDB script<commit_after>use std::collections::HashMap;
use std::ffi::CString;
use std::io::{BufferedReader, Command, File, fs};
use std::os;
use std::path::Path;

use std::path::BytesContainer;

const SNAPPY_VERSION: &'static str  = "1.1.2";
const LEVELDB_VERSION: &'static str = "1.18";

fn build_snappy() {
    // Step 1: Build snappy
    // ----------------------------------------------------------------------
    let snappy_path = Path::new("deps")
                           .join(format!("snappy-{}", SNAPPY_VERSION));

    // Clean the build directory first.
    println!("[snappy] Cleaning");
    Command::new("make").args(&["-C", snappy_path.as_str().unwrap()])
                        .arg("distclean")
                        .status().unwrap();

    // Configure the build
    println!("[snappy] Configuring");
    Command::new("./configure").cwd(&snappy_path)
                               .arg("CXXFLAGS=-fPIC")
                               .status().unwrap();

    // Call "make" to build the C library
    println!("[snappy] Building");
    Command::new("make").args(&["-C", snappy_path.as_str().unwrap()])
                        .status().unwrap();

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let out_dir = Path::new(os::getenv("OUT_DIR").unwrap());

    println!("[build] Copying output files");
    fs::copy(&snappy_path.join(".libs").join("libsnappy.a"), &out_dir.join("libsnappy.a")).unwrap();
}

fn build_leveldb(with_snappy: bool) {
    // Step 1: Build LevelDB
    // ----------------------------------------------------------------------
    let leveldb_path = Path::new("deps")
                            .join(format!("leveldb-{}", LEVELDB_VERSION));

    // Clean the build directory first.
    println!("[leveldb] Cleaning");
    Command::new("make").args(&["-C", leveldb_path.as_str().unwrap()])
                        .arg("clean")
                        .status().unwrap();

    // Set up the process environment.  We essentially clone the existing
    // environment, and, if we're including Snappy, also include the appropriate
    // CXXFLAGS and LDFLAGS variables.
    let mut env_map: HashMap<CString, CString> = os::env_as_bytes().into_iter().map(|(k, v)| {
        (
            CString::from_slice(k.as_slice()),
            CString::from_slice(v.as_slice())
        )
    }).collect();

    if with_snappy {
        let linker_path = os::getenv("OUT_DIR").unwrap();
        env_map.insert(
            CString::from_slice("LDFLAGS".as_bytes()),
            CString::from_slice(format!("-L{}", linker_path).as_bytes())
        );

        let snappy_path = Path::new("deps")
                               .join(format!("snappy-{}", SNAPPY_VERSION));
        env_map.insert(
            CString::from_slice("CXXFLAGS".as_bytes()),
            CString::from_slice(format!("-I{} -fPIC", snappy_path.as_str().unwrap()).as_bytes())
        );
    } else {
        env_map.insert(
            CString::from_slice("CXXFLAGS".as_bytes()),
            CString::from_slice(format!("-fPIC").as_bytes())
        );
    }

    // Convert to the format that `env_set_all` is expecting.
    let env_arr: Vec<(CString, CString)> = env_map.into_iter().collect();

    // Build the library
    println!("[leveldb] Building");
    let mut pp = Command::new("make")
            .args(&["-C", leveldb_path.as_str().unwrap()])
            .env_set_all(env_arr.as_slice())
            .spawn().unwrap();
    let stdout_buff = pp.stdout.as_mut().unwrap().read_to_end().unwrap();
    let stdout = String::from_utf8_lossy(stdout_buff.as_slice());
    println!("[leveldb] Process stdout = \"{}\"", stdout.escape_default());

    let stderr_buff = pp.stderr.as_mut().unwrap().read_to_end().unwrap();
    let stderr = String::from_utf8_lossy(stderr_buff.as_slice());
    println!("[leveldb] Process stderr = \"{}\"", stderr.escape_default());

    // Step 2: Copy to output directories
    // ----------------------------------------------------------------------
    let out_dir = Path::new(os::getenv("OUT_DIR").unwrap());

    println!("[build] Copying output files");
    fs::copy(&leveldb_path.join("libleveldb.a"), &out_dir.join("libleveldb.a")).unwrap();
}

fn main() {
    println!("[build] Started");

    let have_snappy = os::getenv("CARGO_FEATURE_SNAPPY").is_some();

    // If we have the appropriate feature, then we build snappy.
    if have_snappy {
        build_snappy();
    }

    // Copy the build_detect_platform file into the appropriate place.
    let template_path = Path::new("deps")
                             .join("build_detect_platform");
    let detect_path = Path::new("deps")
                           .join(format!("leveldb-{}", LEVELDB_VERSION))
                           .join("build_detect_platform");
    if have_snappy {
        println!("[build] Copying the `build_detect_platform` template");
        fs::copy(&template_path, &detect_path).unwrap();
    } else {
        println!("[build] Patching the `build_detect_platform` template");

        // If we aren't using snappy, remove the lines from
        // build_detect_platform that enable Snappy.  This prevents us from
        // picking up a system-local copy of Snappy.
        let new_lines: Vec<String> = {
            let mut file = BufferedReader::new(File::open(&template_path));

            file.lines().map(|line| {
                let mut line = line.unwrap();
                if line.contains("-DSNAPPY") || line.contains("-lsnappy") {
                    let mut tmp = String::new();
                    tmp.push_str("true   #");
                    tmp.push_str(line.as_slice());
                    tmp
                } else {
                    line
                }
            }).collect()
        };

        let mut f = File::create(&detect_path);
        for line in new_lines.iter() {
            f.write_str(line.as_slice());
        }

        println!("[build] Patching complete");
    }

    // Set executable bits on the file
    fs::chmod(&detect_path, std::io::USER_EXEC).unwrap();

    // Build LevelDB
    build_leveldb(have_snappy);

    // Print the appropriate linker flags
    let out_dir = os::getenv("OUT_DIR").unwrap();
    let linker_flags = if have_snappy {
        "-l static=snappy -l static=leveldb -l stdc++"
    } else {
        "-l static=leveldb -l stdc++"
    };
    println!("cargo:rustc-flags=-L native={} {} -l stdc++", out_dir, linker_flags);

    println!("[build] Finished");
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
use std::error::Error;
extern crate toml;

mod decoders;

fn usage() {
  println!("rawloader <file>");
  std::process::exit(1);
}

fn error(err: &str) {
  println!("ERROR: {}", err);
  std::process::exit(2);
}

fn main() {
  let args: Vec<_> = env::args().collect();
  if args.len() != 2 {
    usage();
  }
  let file = &args[1];
  println!("Loading file \"{}\"", file);

  let mut f = match File::open(file) {
    Ok(val) => val,
    Err(e) => {error(e.description());unreachable!()},
  };
  let mut buffer = Vec::new();
  if let Err(err) = f.read_to_end(&mut buffer) {
    error(err.description());
  }
  println!("Total file is {} bytes in length", buffer.len());

  let rawloader = decoders::RawLoader::new("./data/cameras/");
  let decoder = match rawloader.get_decoder(&buffer) {
    Ok(val) => val,
    Err(e) => {error(&e);unreachable!()},
  };

  let camera = match decoder.identify() {
    Ok(val) => val,
    Err(e) => {error(&e);unreachable!()},
  };
  println!("Found camera \"{}\" model \"{}\"", camera.make, camera.model);

  let image = decoder.image();
  println!("Image size is {}x{}", image.width, image.height);
  println!("WB coeffs are {},{},{},{}", image.wb_coeffs[0],
                                        image.wb_coeffs[1],
                                        image.wb_coeffs[2],
                                        image.wb_coeffs[3]);

  let mut sum: u64 = 0;
  for i in 0..(image.width*image.height) {
    sum += image.data[i as usize] as u64;
  }
  println!("Image sum: {}", sum);
  let count: u64 = (image.width as u64) * (image.height as u64);
  println!("Image avg: {}", sum/count);
}
<commit_msg>Write out a ppm to test the output<commit_after>use std::env;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
extern crate toml;

mod decoders;

fn usage() {
  println!("rawloader <file>");
  std::process::exit(1);
}

fn error(err: &str) {
  println!("ERROR: {}", err);
  std::process::exit(2);
}

fn main() {
  let args: Vec<_> = env::args().collect();
  if args.len() != 2 {
    usage();
  }
  let file = &args[1];
  println!("Loading file \"{}\"", file);

  let mut f = match File::open(file) {
    Ok(val) => val,
    Err(e) => {error(e.description());unreachable!()},
  };
  let mut buffer = Vec::new();
  if let Err(err) = f.read_to_end(&mut buffer) {
    error(err.description());
  }
  println!("Total file is {} bytes in length", buffer.len());

  let rawloader = decoders::RawLoader::new("./data/cameras/");
  let decoder = match rawloader.get_decoder(&buffer) {
    Ok(val) => val,
    Err(e) => {error(&e);unreachable!()},
  };

  let camera = match decoder.identify() {
    Ok(val) => val,
    Err(e) => {error(&e);unreachable!()},
  };
  println!("Found camera \"{}\" model \"{}\"", camera.make, camera.model);

  let image = decoder.image();
  println!("Image size is {}x{}", image.width, image.height);
  println!("WB coeffs are {},{},{},{}", image.wb_coeffs[0],
                                        image.wb_coeffs[1],
                                        image.wb_coeffs[2],
                                        image.wb_coeffs[3]);

  let mut sum: u64 = 0;
  for i in 0..(image.width*image.height) {
    sum += image.data[i as usize] as u64;
  }
  println!("Image sum: {}", sum);
  let count: u64 = (image.width as u64) * (image.height as u64);
  println!("Image avg: {}", sum/count);

  let mut f = match File::create(format!("{}.ppm",file)) {
    Ok(val) => val,
    Err(e) => {error(e.description());unreachable!()},
  };
  let preamble = format!("P6 {} {} {}\n", image.width, image.height, 4095).into_bytes();
  if let Err(err) = f.write_all(&preamble) {
    error(err.description());
  }
  for row in 0..image.height {
    let from: usize = (row as usize) * (image.width as usize);
    let to: usize = ((row+1) as usize) * (image.width as usize);
    let imgline = &image.data[from .. to];

    for pixel in imgline {
      let bytes = [(pixel>>4) as u8, (pixel&0x0f) as u8, (pixel>>4) as u8, (pixel&0x0f) as u8, (pixel>>4) as u8, (pixel&0x0f) as u8];
       if let Err(err) = f.write_all(&bytes) {
        error(err.description());
      }
    }
  }
}
<|endoftext|>


<commit_before>extern crate cargo_tarpaulin;
extern crate nix;
extern crate gimli;
extern crate object;
extern crate memmap;
extern crate fallible_iterator;
extern crate rustc_demangle;
#[macro_use]
extern crate clap;

use std::path::Path;
use clap::{App, Arg, SubCommand, ArgSettings};
use cargo_tarpaulin::run;
use cargo_tarpaulin::config::*;

fn is_dir(d: String) -> Result<(), String> {
    if Path::new(&d).is_dir() {
        Ok(())
    } else {
        Err(String::from("root must be a directory"))
    }
}

const CI_SERVER_HELP: &'static str =
"Name of service, supported services are:
travis-ci, travis-pro, circle-ci, semaphore, jenkins and codeship.
If you are interfacing with coveralls.io or another site you can \
also specify a name that they will recognise. Refer to their documentation for this.";

fn main() {
    let args = App::new("cargo-tarpaulin")
        .author("Daniel McKenna, <danielmckenna93@gmail.com>")
        .about("Tool to analyse test coverage of cargo projects")
        .version(concat!("version: ", crate_version!()))
        .bin_name("cargo")
        .subcommand(SubCommand::with_name("tarpaulin")
            .about("Tool to analyse test coverage of cargo projects")
            .version(concat!("version: ", crate_version!()))
            .args_from_usage(
                 "--verbose -v 'Show extra output'
                 --ignore-tests 'ignore lines of test functions when collecting coverage'
                 --no-count   'Disables counting line hits for a faster run'
                 --ignored -i 'Run ignored tests as well'
                 --line -l    'Line coverage'
                 --skip-clean 'Skips the clean stage to reduce build times, may affect coverage results'
                 --branch -b  'Branch coverage: NOT IMPLEMENTED'
                 --forward -f 'Forwards unexpected signals to test. Tarpaulin will still take signals it is expecting.'
                 --coveralls [KEY]  'Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver'
                 --features [FEATURE]... 'Features to be included in the target project'
                 --all        'Build all packages in the workspace'
                 --packages -p [PACKAGE]... 'Package id specifications for which package should be build. See cargo help pkgid for more info'
                 --exclude -e [PACKAGE]... 'Package id specifications to exclude from coverage. See cargo help pkgid for more info'
                 --exclude-files [FILE]... 'Exclude given files from coverage results (must include .rs extension)'")
            .args(&[
                Arg::from_usage("--out -o [FMT]   'Output path'")
                    .possible_values(&OutputFile::variants())
                    .multiple(true),
                Arg::from_usage("--root -r [DIR]  'Root directory containing Cargo.toml to use'")
                    .validator(is_dir),
                Arg::from_usage("--ciserver [SERVICE] 'CI server being used'")
                    .help(CI_SERVER_HELP),
                Arg::with_name("args")
                    .set(ArgSettings::Last)
                    .multiple(true)
            ]))
        .get_matches();

    let args = args.subcommand_matches("tarpaulin").unwrap_or(&args);
    let config = Config::from_args(args);
    match run(config) {
        Ok(()) => println!("Tarpaulin finished"),
        Err(e) => {
            println!("Error during run");
            std::process::exit(e);
        },
    }
}
<commit_msg>Updated help message<commit_after>extern crate cargo_tarpaulin;
extern crate nix;
extern crate gimli;
extern crate object;
extern crate memmap;
extern crate fallible_iterator;
extern crate rustc_demangle;
#[macro_use]
extern crate clap;

use std::path::Path;
use clap::{App, Arg, SubCommand, ArgSettings};
use cargo_tarpaulin::run;
use cargo_tarpaulin::config::*;

fn is_dir(d: String) -> Result<(), String> {
    if Path::new(&d).is_dir() {
        Ok(())
    } else {
        Err(String::from("root must be a directory"))
    }
}

const CI_SERVER_HELP: &'static str =
"Name of service, supported services are:
travis-ci, travis-pro, circle-ci, semaphore, jenkins and codeship.
If you are interfacing with coveralls.io or another site you can \
also specify a name that they will recognise. Refer to their documentation for this.";

fn main() {
    let args = App::new("cargo-tarpaulin")
        .author("Daniel McKenna, <danielmckenna93@gmail.com>")
        .about("Tool to analyse test coverage of cargo projects")
        .version(concat!("version: ", crate_version!()))
        .bin_name("cargo")
        .subcommand(SubCommand::with_name("tarpaulin")
            .about("Tool to analyse test coverage of cargo projects")
            .version(concat!("version: ", crate_version!()))
            .args_from_usage(
                 "--verbose -v 'Show extra output'
                 --ignore-tests 'ignore lines of test functions when collecting coverage'
                 --no-count   'Disables counting line hits for a faster run'
                 --ignored -i 'Run ignored tests as well'
                 --line -l    'Line coverage'
                 --skip-clean 'Skips the clean stage to reduce build times, may affect coverage results'
                 --branch -b  'Branch coverage: NOT IMPLEMENTED'
                 --forward -f 'Forwards unexpected signals to test. Tarpaulin will still take signals it is expecting.'
                 --coveralls [KEY]  'Coveralls key, either the repo token, or if you're using travis use $TRAVIS_JOB_ID and specify travis-{ci|pro} in --ciserver'
                 --features [FEATURE]... 'Features to be included in the target project'
                 --all        'Build all packages in the workspace'
                 --packages -p [PACKAGE]... 'Package id specifications for which package should be build. See cargo help pkgid for more info'
                 --exclude -e [PACKAGE]... 'Package id specifications to exclude from coverage. See cargo help pkgid for more info'
                 --exclude-files [FILE]... 'Exclude given files from coverage results has * wildcard'")
            .args(&[
                Arg::from_usage("--out -o [FMT]   'Output path'")
                    .possible_values(&OutputFile::variants())
                    .multiple(true),
                Arg::from_usage("--root -r [DIR]  'Root directory containing Cargo.toml to use'")
                    .validator(is_dir),
                Arg::from_usage("--ciserver [SERVICE] 'CI server being used'")
                    .help(CI_SERVER_HELP),
                Arg::with_name("args")
                    .set(ArgSettings::Last)
                    .multiple(true)
            ]))
        .get_matches();

    let args = args.subcommand_matches("tarpaulin").unwrap_or(&args);
    let config = Config::from_args(args);
    match run(config) {
        Ok(()) => println!("Tarpaulin finished"),
        Err(e) => {
            println!("Error during run");
            std::process::exit(e);
        },
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate hyper;
extern crate iron;
extern crate regex;
extern crate router;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate scoped_threadpool;
extern crate tera;

use std::collections::{BTreeMap, HashMap};
use std::env;
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH};

use iron::headers::ContentType;
use iron::prelude::*;
use iron::status;
use router::Router;
use scoped_threadpool::Pool;
use tera::{Context, Tera};

pub mod battle_net_api_client;
pub mod thread_throttler;

use battle_net_api_client::{AuctionListing, BattleNetApiClient};

/// Represents a single option available for sale from the blood vendor.
#[derive(Debug, Deserialize)]
struct BloodVendorItem {
    name: String,
    quantity: u64,
    id: u64,
}

/// Value of an item on a realm.
#[derive(Debug)]
struct ItemValue {
    id: u64,
    value: u64,
}

/// The calculated values for items on a particular realm.
#[derive(Debug)]
struct CurrentRealmValues {
    last_update: u64,  // The last time we got this info, as reported by the Blizzard API.
    auction_values: Arc<Vec<ItemValue>>,  // Should be sorted by value.
}

/// All the data in a single row in our price list for a realm.
#[derive(Debug, Serialize)]
struct PriceRow {
    name: String,
    quantity: u64,
    icon: String,
    value_ratio: u64,
    gold: u64,
    silver: u64,
    copper: u64,
}

/// Number of threads to use when fetching auction house results.
const NUM_AUCTION_DATA_THREADS: u32 = 5;

/// Number of seconds to wait between fetching new auction results.
const RESULT_FETCH_PERIOD: u64 = 60 * 30;

/// Given a vec of auction listings for a realm and a map of the items we care about,
/// returns a vec of (item_id, value) sorted by decreasing value, where value is
/// based on the 5th percentile buyout price.
fn calculate_auction_values(listings: &Vec<AuctionListing>, items: &HashMap<u64, BloodVendorItem>) -> Vec<ItemValue> {
    // Calculate 5th percentiles for the items we care about.
    let mut price_points: BTreeMap<u64, Vec<(u64, u64)>> = BTreeMap::new();
    for listing in listings {
        if items.contains_key(&listing.item) && listing.buyout > 0 {
            price_points.entry(listing.item).or_insert(Vec::new()).push((listing.quantity, listing.buyout / listing.quantity));
        }
    }
    for quantities_and_buyouts in price_points.values_mut() {
        quantities_and_buyouts.sort_by_key(|a| a.1);
    }
    let total_item_quantities: BTreeMap<u64, u64> =
        price_points.iter().map(|(k, v)| {
            (*k, v.iter().fold(0, |sum, quantity_and_buyout| sum + quantity_and_buyout.0))
        }).collect();
    let fifth_percentile_price_points: BTreeMap<u64, u64> =
        price_points.iter().map(|(item_id, ref item_listings)| {
            let fifth_percentile_quantity = total_item_quantities.get(item_id).unwrap() / 20;
            let mut running_sum: u64 = 0;
            let fifth_percentile_listing = item_listings.iter().find(|&&(quantity, _)| {
                running_sum += quantity;
                running_sum >= fifth_percentile_quantity
            }).unwrap();
            (*item_id, fifth_percentile_listing.1)
        }).collect();
    let mut item_values: Vec<ItemValue> = items.values().map(|item|
        ItemValue {
            id: item.id,
            value: fifth_percentile_price_points.get(&item.id).unwrap_or(&0u64) * item.quantity,
        }
    ).collect();
    item_values.sort_by_key(|item_value| !item_value.value);
    item_values
}

fn main() {
    let token = match env::args().nth(1) {
        Some(token) => token,
        None => {
            println!("Usage: bloodmoney <api token>");
            return;
        }
    };
    let client = Arc::new(BattleNetApiClient::new(&token));
    // Process our item options and grab their icon names.
    let items: Vec<BloodVendorItem> = serde_json::from_str(include_str!("../catalog/items.json"))
        .expect("Error reading items.");
    let item_id_map: Arc<HashMap<u64, BloodVendorItem>> = Arc::new(items.into_iter().map(|x| (x.id, x)).collect());
    let item_icons: Arc<HashMap<u64, String>> = Arc::new(item_id_map.keys().map(|&id| (id, client.get_item_info(id).icon)).collect());

    // Get the list of realms and create an empty price map so we can render pages while
    // waiting for the auction results to be retrieved.
    let realms = Arc::new(client.get_realms());
    let connected_realms = BattleNetApiClient::process_connected_realms(&realms);
    let price_map: Arc<BTreeMap<String, RwLock<CurrentRealmValues>>> =
        Arc::new(realms.iter().map(|realm| (realm.slug.clone(), RwLock::new(CurrentRealmValues {
            last_update: 0,
            auction_values: Arc::new(item_id_map.keys().map(|id| ItemValue{id: *id, value: 0u64}).collect()),
        }))).collect());

    // Set up our web-app.
    let tera = Arc::new(Tera::new("templates/**/*"));
    let mut router = Router::new();
    {
        let realms = realms.clone();
        let tera = tera.clone();
        router.get("/blood-money", move |_: &mut Request| {
            let mut context = Context::new();
            context.add("realms", &realms);
            Ok(Response::with((ContentType::html().0, status::Ok, tera.render("index.html", context).unwrap())))
        }, "index");
    }
    {
        let price_map = price_map.clone();
        let item_id_map = item_id_map.clone();
        let realms = realms.clone();
        let tera = tera.clone();
        router.get("/blood-money/:realm", move |req : &mut Request| {
            let realm = req.extensions.get::<Router>().unwrap().find("realm").unwrap();
            if let Some(realm_prices_lock) = price_map.get(realm) {
                let mut context = Context::new();
                let realm_prices = realm_prices_lock.read().unwrap();
                // Build up a list of entries.
                let highest_value = realm_prices.auction_values.get(0).unwrap().value;
                let price_rows: Vec<PriceRow> = realm_prices.auction_values.iter().map(|&ItemValue{id, value}| {
                    let item_info = item_id_map.get(&id).unwrap();
                    let gold = value / (10_000);
                    let silver = (value - gold * 10_000) / 100;
                    let copper = value - gold * 10_000 - silver * 100;
                    let value_ratio = match highest_value {
                        0u64 => 0u64,
                        _ => value*100/highest_value,  // Percentile!
                    };
                    PriceRow {
                        name: item_info.name.clone(),
                        quantity: item_info.quantity,
                        icon: item_icons.get(&id).unwrap().clone(),
                        value_ratio: value_ratio,
                        gold: gold,
                        silver: silver,
                        copper: copper,
                    }
                }).collect();
                context.add("realm_name", &realms.iter().find(|&realm_info| &realm_info.slug == realm).unwrap().name);
                context.add("price_rows", &price_rows);
                // TODO: Change this to something more human readable.
                if realm_prices.last_update == 0 {
                    context.add("update_age", &-1);
                } else {
                    context.add("update_age",
                        &(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() - realm_prices.last_update / 1000));
                }
                Ok(Response::with((ContentType::html().0, status::Ok, tera.render("prices.html", context).unwrap())))
            } else {
                return Ok(Response::with(status::NotFound));
            }
        }, "realm-prices");
    }
    let http_result = Iron::new(router).http("0.0.0.0:80");
    println!("Ready for web traffic.");

    // Now that the webserver is up, periodically fetch
    // new auction house data.
    let mut pool = Pool::new(NUM_AUCTION_DATA_THREADS);
    loop {
        let download_start = Instant::now();
        let next_download_time = download_start + Duration::from_secs(RESULT_FETCH_PERIOD);
        println!("Starting download of auction data.");
        pool.scoped(|scope| {
            for realm_list in &connected_realms {
                // We have to move realm_list into the closure.
                // Clone other values.
                let client = client.clone();
                let price_map = price_map.clone();
                let item_id_map = item_id_map.clone();
                scope.execute(move || {
                    let lead_realm = realm_list.get(0).unwrap();
                    let update_time: u64;
                    let auction_listings: Vec<AuctionListing>;
                    println!("Downloading {}", lead_realm);
                    {
                        let current_realm_values =
                            price_map.get(lead_realm).unwrap().read().unwrap();
                        match client.get_auction_listings(lead_realm, current_realm_values.last_update) {
                            Some((ts, al)) => {
                                update_time = ts;
                                auction_listings = al;
                            },
                            None => return,
                        }
                    }
                    let auction_values = Arc::new(calculate_auction_values(&auction_listings, &item_id_map));
                    for realm in realm_list {
                        println!("Updating {}", realm);
                        let mut current_realm_values =
                            price_map.get(realm).unwrap().write().unwrap();
                        current_realm_values.auction_values = auction_values.clone();
                        current_realm_values.last_update = update_time;
                    }
                })
            }
            scope.join_all();
        });
        let download_end_time = Instant::now();
        println!("Downloading all realms took {} seconds.", download_end_time.duration_since(download_start).as_secs());
        if download_end_time < next_download_time {
            println!("Sleeping for {}", next_download_time.duration_since(download_end_time).as_secs());
            sleep(next_download_time.duration_since(download_end_time));
        }
    }
}
<commit_msg>Refresh every 5min<commit_after>#![feature(proc_macro)]

extern crate hyper;
extern crate iron;
extern crate regex;
extern crate router;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate scoped_threadpool;
extern crate tera;

use std::collections::{BTreeMap, HashMap};
use std::env;
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH};

use iron::headers::ContentType;
use iron::prelude::*;
use iron::status;
use router::Router;
use scoped_threadpool::Pool;
use tera::{Context, Tera};

pub mod battle_net_api_client;
pub mod thread_throttler;

use battle_net_api_client::{AuctionListing, BattleNetApiClient};

/// Represents a single option available for sale from the blood vendor.
#[derive(Debug, Deserialize)]
struct BloodVendorItem {
    name: String,
    quantity: u64,
    id: u64,
}

/// Value of an item on a realm.
#[derive(Debug)]
struct ItemValue {
    id: u64,
    value: u64,
}

/// The calculated values for items on a particular realm.
#[derive(Debug)]
struct CurrentRealmValues {
    last_update: u64,  // The last time we got this info, as reported by the Blizzard API.
    auction_values: Arc<Vec<ItemValue>>,  // Should be sorted by value.
}

/// All the data in a single row in our price list for a realm.
#[derive(Debug, Serialize)]
struct PriceRow {
    name: String,
    quantity: u64,
    icon: String,
    value_ratio: u64,
    gold: u64,
    silver: u64,
    copper: u64,
}

/// Number of threads to use when fetching auction house results.
const NUM_AUCTION_DATA_THREADS: u32 = 5;

/// Number of seconds to wait between fetching new auction results.
const RESULT_FETCH_PERIOD: u64 = 60 * 5;

/// Given a vec of auction listings for a realm and a map of the items we care about,
/// returns a vec of (item_id, value) sorted by decreasing value, where value is
/// based on the 5th percentile buyout price.
fn calculate_auction_values(listings: &Vec<AuctionListing>, items: &HashMap<u64, BloodVendorItem>) -> Vec<ItemValue> {
    // Calculate 5th percentiles for the items we care about.
    let mut price_points: BTreeMap<u64, Vec<(u64, u64)>> = BTreeMap::new();
    for listing in listings {
        if items.contains_key(&listing.item) && listing.buyout > 0 {
            price_points.entry(listing.item).or_insert(Vec::new()).push((listing.quantity, listing.buyout / listing.quantity));
        }
    }
    for quantities_and_buyouts in price_points.values_mut() {
        quantities_and_buyouts.sort_by_key(|a| a.1);
    }
    let total_item_quantities: BTreeMap<u64, u64> =
        price_points.iter().map(|(k, v)| {
            (*k, v.iter().fold(0, |sum, quantity_and_buyout| sum + quantity_and_buyout.0))
        }).collect();
    let fifth_percentile_price_points: BTreeMap<u64, u64> =
        price_points.iter().map(|(item_id, ref item_listings)| {
            let fifth_percentile_quantity = total_item_quantities.get(item_id).unwrap() / 20;
            let mut running_sum: u64 = 0;
            let fifth_percentile_listing = item_listings.iter().find(|&&(quantity, _)| {
                running_sum += quantity;
                running_sum >= fifth_percentile_quantity
            }).unwrap();
            (*item_id, fifth_percentile_listing.1)
        }).collect();
    let mut item_values: Vec<ItemValue> = items.values().map(|item|
        ItemValue {
            id: item.id,
            value: fifth_percentile_price_points.get(&item.id).unwrap_or(&0u64) * item.quantity,
        }
    ).collect();
    item_values.sort_by_key(|item_value| !item_value.value);
    item_values
}

fn main() {
    let token = match env::args().nth(1) {
        Some(token) => token,
        None => {
            println!("Usage: bloodmoney <api token>");
            return;
        }
    };
    let client = Arc::new(BattleNetApiClient::new(&token));
    // Process our item options and grab their icon names.
    let items: Vec<BloodVendorItem> = serde_json::from_str(include_str!("../catalog/items.json"))
        .expect("Error reading items.");
    let item_id_map: Arc<HashMap<u64, BloodVendorItem>> = Arc::new(items.into_iter().map(|x| (x.id, x)).collect());
    let item_icons: Arc<HashMap<u64, String>> = Arc::new(item_id_map.keys().map(|&id| (id, client.get_item_info(id).icon)).collect());

    // Get the list of realms and create an empty price map so we can render pages while
    // waiting for the auction results to be retrieved.
    let realms = Arc::new(client.get_realms());
    let connected_realms = BattleNetApiClient::process_connected_realms(&realms);
    let price_map: Arc<BTreeMap<String, RwLock<CurrentRealmValues>>> =
        Arc::new(realms.iter().map(|realm| (realm.slug.clone(), RwLock::new(CurrentRealmValues {
            last_update: 0,
            auction_values: Arc::new(item_id_map.keys().map(|id| ItemValue{id: *id, value: 0u64}).collect()),
        }))).collect());

    // Set up our web-app.
    let tera = Arc::new(Tera::new("templates/**/*"));
    let mut router = Router::new();
    {
        let realms = realms.clone();
        let tera = tera.clone();
        router.get("/blood-money", move |_: &mut Request| {
            let mut context = Context::new();
            context.add("realms", &realms);
            Ok(Response::with((ContentType::html().0, status::Ok, tera.render("index.html", context).unwrap())))
        }, "index");
    }
    {
        let price_map = price_map.clone();
        let item_id_map = item_id_map.clone();
        let realms = realms.clone();
        let tera = tera.clone();
        router.get("/blood-money/:realm", move |req : &mut Request| {
            let realm = req.extensions.get::<Router>().unwrap().find("realm").unwrap();
            if let Some(realm_prices_lock) = price_map.get(realm) {
                let mut context = Context::new();
                let realm_prices = realm_prices_lock.read().unwrap();
                // Build up a list of entries.
                let highest_value = realm_prices.auction_values.get(0).unwrap().value;
                let price_rows: Vec<PriceRow> = realm_prices.auction_values.iter().map(|&ItemValue{id, value}| {
                    let item_info = item_id_map.get(&id).unwrap();
                    let gold = value / (10_000);
                    let silver = (value - gold * 10_000) / 100;
                    let copper = value - gold * 10_000 - silver * 100;
                    let value_ratio = match highest_value {
                        0u64 => 0u64,
                        _ => value*100/highest_value,  // Percentile!
                    };
                    PriceRow {
                        name: item_info.name.clone(),
                        quantity: item_info.quantity,
                        icon: item_icons.get(&id).unwrap().clone(),
                        value_ratio: value_ratio,
                        gold: gold,
                        silver: silver,
                        copper: copper,
                    }
                }).collect();
                context.add("realm_name", &realms.iter().find(|&realm_info| &realm_info.slug == realm).unwrap().name);
                context.add("price_rows", &price_rows);
                // TODO: Change this to something more human readable.
                if realm_prices.last_update == 0 {
                    context.add("update_age", &-1);
                } else {
                    context.add("update_age",
                        &(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() - realm_prices.last_update / 1000));
                }
                Ok(Response::with((ContentType::html().0, status::Ok, tera.render("prices.html", context).unwrap())))
            } else {
                return Ok(Response::with(status::NotFound));
            }
        }, "realm-prices");
    }
    let http_result = Iron::new(router).http("0.0.0.0:80");
    println!("Ready for web traffic.");

    // Now that the webserver is up, periodically fetch
    // new auction house data.
    let mut pool = Pool::new(NUM_AUCTION_DATA_THREADS);
    loop {
        let download_start = Instant::now();
        let next_download_time = download_start + Duration::from_secs(RESULT_FETCH_PERIOD);
        println!("Starting download of auction data.");
        pool.scoped(|scope| {
            for realm_list in &connected_realms {
                // We have to move realm_list into the closure.
                // Clone other values.
                let client = client.clone();
                let price_map = price_map.clone();
                let item_id_map = item_id_map.clone();
                scope.execute(move || {
                    let lead_realm = realm_list.get(0).unwrap();
                    let update_time: u64;
                    let auction_listings: Vec<AuctionListing>;
                    println!("Downloading {}", lead_realm);
                    {
                        let current_realm_values =
                            price_map.get(lead_realm).unwrap().read().unwrap();
                        match client.get_auction_listings(lead_realm, current_realm_values.last_update) {
                            Some((ts, al)) => {
                                update_time = ts;
                                auction_listings = al;
                            },
                            None => return,
                        }
                    }
                    let auction_values = Arc::new(calculate_auction_values(&auction_listings, &item_id_map));
                    for realm in realm_list {
                        println!("Updating {}", realm);
                        let mut current_realm_values =
                            price_map.get(realm).unwrap().write().unwrap();
                        current_realm_values.auction_values = auction_values.clone();
                        current_realm_values.last_update = update_time;
                    }
                })
            }
            scope.join_all();
        });
        let download_end_time = Instant::now();
        println!("Downloading all realms took {} seconds.", download_end_time.duration_since(download_start).as_secs());
        if download_end_time < next_download_time {
            println!("Sleeping for {}", next_download_time.duration_since(download_end_time).as_secs());
            sleep(next_download_time.duration_since(download_end_time));
        }
    }
}
<|endoftext|>