<commit_before>extern crate image;

use image::{
    ImageBuffer,
    Pixel,
};
use image::imageops::flip_vertical;
use std::ops::{
    Deref,
    DerefMut,
};

trait Painting<P> where P: Pixel {
    fn line(&mut self, x0: u32, y0: u32, x1: u32, y1: u32, color: P) -> &mut Self;
}

impl<P, Container> Painting<P> for ImageBuffer<P, Container>
where P: Pixel + 'static,
      Container: Deref<Target=[P::Subpixel]> + DerefMut,
      P::Subpixel: 'static {

    fn line(&mut self, x0: u32, y0: u32, x1: u32, y1: u32, color: P) -> &mut Self {
        if x0 == x1 && y0 == y1 {
            self.put_pixel(x0, y0, color);
        } else {
            let transpose = (x0 as i32 - x1 as i32).abs() < (y0 as i32 - y1 as i32).abs();
            let reverse = (!transpose && x0 > x1) || (transpose && y0 > y1);
            let a0 = if transpose {if reverse {y1} else {y0}} else {if reverse {x1} else {x0}};
            let a1 = if transpose {if reverse {y0} else {y1}} else {if reverse {x0} else {x1}};
            let b0 = if transpose {if reverse {x1} else {x0}} else {if reverse {y1} else {y0}};
            let b1 = if transpose {if reverse {x0} else {x1}} else {if reverse {y0} else {y1}};

            for a in a0..a1+1 {
                let t = (a - a0) as f64 / (a1 - a0) as f64;
                let b = (b0 as f64 * (1.0 - t) + b1 as f64 * t) as u32;

                if transpose {
                    self.put_pixel(b, a, color);
                } else {
                    self.put_pixel(a, b, color);
                }
            }
        }

        self
    }
}

fn main() {
    // load/create image
    let mut img = ImageBuffer::new(100, 100);

    // image processing
    let red = image::Rgb([0xff, 0x00, 0x00]);
    let white = image::Rgb([0xff, 0xff, 0xff]);

    for _ in 0..1000000 {
        img.line(13, 20, 80, 40, white);
        img.line(20, 13, 40, 80, red);
        img.line(80, 40, 13, 20, red);
    }

    img = flip_vertical(&img);

    // save image
    let _ = img.save("output.ppm");
}
<commit_msg>introduce error variable (diff from ideal line)<commit_after>extern crate image;

use image::{
    ImageBuffer,
    Pixel,
};
use image::imageops::flip_vertical;
use std::ops::{
    Deref,
    DerefMut,
};

trait Painting<P> where P: Pixel {
    fn line(&mut self, x0: u32, y0: u32, x1: u32, y1: u32, color: P) -> &mut Self;
}

impl<P, Container> Painting<P> for ImageBuffer<P, Container>
where P: Pixel + 'static,
      Container: Deref<Target=[P::Subpixel]> + DerefMut,
      P::Subpixel: 'static {

    fn line(&mut self, x0: u32, y0: u32, x1: u32, y1: u32, color: P) -> &mut Self {
        if x0 == x1 && y0 == y1 {
            self.put_pixel(x0, y0, color);
        } else {
            let transpose = (x0 as i32 - x1 as i32).abs() < (y0 as i32 - y1 as i32).abs();
            let reverse = (!transpose && x0 > x1) || (transpose && y0 > y1);
            let a0 = if transpose {if reverse {y1} else {y0}} else {if reverse {x1} else {x0}};
            let a1 = if transpose {if reverse {y0} else {y1}} else {if reverse {x0} else {x1}};
            let b0 = if transpose {if reverse {x1} else {x0}} else {if reverse {y1} else {y0}};
            let b1 = if transpose {if reverse {x0} else {x1}} else {if reverse {y0} else {y1}};
            let derr = ((b1 as i32 - b0 as i32) as f64 / (a1 - a0) as f64).abs();
            let mut err = 0.0;
            let mut a = a0;
            let mut b = b0;

            while a <= a1 {
                if transpose {
                    self.put_pixel(b, a, color);
                } else {
                    self.put_pixel(a, b, color);
                }

                err += derr;

                if err > 0.5 {
                    if b1 > b0 {b += 1;} else {b -= 1;};
                    err -= 1.0;
                }

                a += 1;
            }
        }

        self
    }
}

fn main() {
    // load/create image
    let mut img = ImageBuffer::new(100, 100);

    // image processing
    let red = image::Rgb([0xff, 0x00, 0x00]);
    let white = image::Rgb([0xff, 0xff, 0xff]);

    for _ in 0..1000000 {
        img.line(13, 20, 80, 40, white);
        img.line(20, 13, 40, 80, red);
        img.line(80, 40, 13, 20, red);
    }

    img = flip_vertical(&img);

    // save image
    let _ = img.save("output.ppm");
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate term;

use libc::{c_uint, c_uchar, c_int};
use std::io;

// used in Termios struct
pub const NCCS:uint = 32;

// stdin, stdout, stderr have standard file descriptors
pub const STDIN:c_int = 0;

// constants for control sequences is useful
pub const EOF:char = '\u{4}';
pub const DEL:char = '\u{7f}';

// select termios constants that we use
pub const ICANON:c_uint   = 2;
pub const ECHO:c_uint     = 8;
pub const TCSANOW:c_int   = 0;
pub const TCSADRAIN:c_int = 1;
pub const TCSAFLUSH:c_int = 2;

// types used in Termios struct
#[allow(non_camel_case_types)]
pub type cc_t = c_uchar;
#[allow(non_camel_case_types)]
pub type speed_t = c_uint;
#[allow(non_camel_case_types)]
pub type tcflag_t = c_uint;

#[repr(C)]
#[deriving(Copy)]
#[deriving(Clone)]
pub struct Termios {
    c_iflag: tcflag_t,
    c_oflag: tcflag_t,
    c_cflag: tcflag_t,
    c_lflag: tcflag_t,
    c_line: cc_t,
    c_cc: [c_uchar, ..NCCS],
    c_ispeed: speed_t,
    c_ospeed: speed_t,
}

impl Termios {
    pub fn new() -> Termios {
        Termios {
            c_cc: [0, ..NCCS],
            c_cflag: 0,
            c_iflag: 0,
            c_ispeed: 0,
            c_lflag: 0,
            c_line: 0,
            c_oflag: 0,
            c_ospeed: 0,
        }
    }

    pub fn get_from(&mut self, fd:c_int) -> bool {
        unsafe {
            return tcgetattr(fd, self) == 0;
        }
    }

    pub fn get(&mut self) -> bool {
        self.get_from(STDIN)
    }

    pub fn set_to(&self, fd:c_int) -> bool {
        unsafe {
            return tcsetattr(fd, TCSANOW, self) == 0;
        }
    }

    pub fn set(&self) -> bool {
        self.set_to(STDIN)
    }

    pub fn lenable(&mut self, flag:c_uint) {
        self.c_lflag |= flag;
    }

    pub fn ldisable(&mut self, flag:c_uint) {
        self.c_lflag &= !flag;
    }
}

#[link(name = "c")]
extern {
    pub fn tcgetattr(fd: c_int, termios: *mut Termios) -> c_int;
    pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *const Termios) -> c_int;
}

fn empty_escape(esc:&mut Iterator<char>) -> String {
    let mut out = String::new();
    loop {
        match esc.next() {
            Some(c) => out.push(c),
            None => break
        }
    }
    return out;
}

fn prepare_terminal() -> Termios {
    // new terminal mode info
    let mut tios = Termios::new();
    // populate terminal info
    tios.get();
    let tios_clone = tios.clone();
    // turn off canonical mode
    tios.ldisable(ICANON);
    // turn off echo mode
    tios.ldisable(ECHO);
    // set the terminal mode
    update_terminal(tios);
    // return the old terminal mode
    return tios_clone;
}

fn update_terminal(tios:Termios) -> bool {
    if !tios.set() {
        io::stderr().write_line("Warning: Could not set terminal mode").unwrap_err();
        return false;
    }
    return true;
}

fn main() {
    let old_tios = prepare_terminal();
    let mut stdin = io::stdin();
    loop {
        // Note: in non-canonical mode
        match stdin.read_char() {
            Ok(EOF) => break,
            Ok(DEL) => {
                print!("{} {}", DEL, DEL);
            },
            Ok(c) => {
                print!("{}", empty_escape(&mut c.escape_default()))
            },
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        }
    }
    // print so we know we've reached this code
    println!("Exiting");
    // restore old term state
    update_terminal(old_tios);
}
<commit_msg>Remove uneeded pub's<commit_after>extern crate libc;
extern crate term;

use libc::{c_uint, c_uchar, c_int};
use std::io;

// used in Termios struct
const NCCS:uint = 32;

// stdin, stdout, stderr have standard file descriptors
const STDIN:c_int = 0;

// constants for control sequences is useful
const EOF:char = '\u{4}';
const DEL:char = '\u{7f}';

// select termios constants that we use
const ICANON:c_uint   = 2;
const ECHO:c_uint     = 8;
const TCSANOW:c_int   = 0;
const TCSADRAIN:c_int = 1;
const TCSAFLUSH:c_int = 2;

// types used in Termios struct
#[allow(non_camel_case_types)]
type cc_t = c_uchar;
#[allow(non_camel_case_types)]
type speed_t = c_uint;
#[allow(non_camel_case_types)]
type tcflag_t = c_uint;

#[repr(C)]
#[deriving(Copy)]
#[deriving(Clone)]
struct Termios {
    c_iflag: tcflag_t,
    c_oflag: tcflag_t,
    c_cflag: tcflag_t,
    c_lflag: tcflag_t,
    c_line: cc_t,
    c_cc: [c_uchar, ..NCCS],
    c_ispeed: speed_t,
    c_ospeed: speed_t,
}

impl Termios {
    fn new() -> Termios {
        Termios {
            c_cc: [0, ..NCCS],
            c_cflag: 0,
            c_iflag: 0,
            c_ispeed: 0,
            c_lflag: 0,
            c_line: 0,
            c_oflag: 0,
            c_ospeed: 0,
        }
    }

    fn get_from(&mut self, fd:c_int) -> bool {
        unsafe {
            return tcgetattr(fd, self) == 0;
        }
    }

    fn get(&mut self) -> bool {
        self.get_from(STDIN)
    }

    fn set_to(&self, fd:c_int) -> bool {
        unsafe {
            return tcsetattr(fd, TCSANOW, self) == 0;
        }
    }

    fn set(&self) -> bool {
        self.set_to(STDIN)
    }

    fn lenable(&mut self, flag:c_uint) {
        self.c_lflag |= flag;
    }

    fn ldisable(&mut self, flag:c_uint) {
        self.c_lflag &= !flag;
    }
}

#[link(name = "c")]
extern {
    fn tcgetattr(fd: c_int, termios: *mut Termios) -> c_int;
    fn tcsetattr(fd: c_int, optional_actions: c_int, termios: *const Termios) -> c_int;
}

fn empty_escape(esc:&mut Iterator<char>) -> String {
    let mut out = String::new();
    loop {
        match esc.next() {
            Some(c) => out.push(c),
            None => break
        }
    }
    return out;
}

fn prepare_terminal() -> Termios {
    // new terminal mode info
    let mut tios = Termios::new();
    // populate terminal info
    tios.get();
    let tios_clone = tios.clone();
    // turn off canonical mode
    tios.ldisable(ICANON);
    // turn off echo mode
    tios.ldisable(ECHO);
    // set the terminal mode
    update_terminal(tios);
    // return the old terminal mode
    return tios_clone;
}

fn update_terminal(tios:Termios) -> bool {
    if !tios.set() {
        io::stderr().write_line("Warning: Could not set terminal mode").unwrap_err();
        return false;
    }
    return true;
}

fn main() {
    let old_tios = prepare_terminal();
    let mut stdin = io::stdin();
    loop {
        // Note: in non-canonical mode
        match stdin.read_char() {
            Ok(EOF) => break,
            Ok(DEL) => {
                print!("{} {}", DEL, DEL);
            },
            Ok(c) => {
                print!("{}", empty_escape(&mut c.escape_default()))
            },
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        }
    }
    // print so we know we've reached this code
    println!("Exiting");
    // restore old term state
    update_terminal(old_tios);
}
<|endoftext|>


<commit_before>#![feature(duration)]
#![feature(duration_span)]

extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize as rustc_serialize;
extern crate threadpool;
extern crate num_cpus;
extern crate tray_rust;

use std::vec::Vec;
use std::sync::{Arc};
use std::sync::mpsc::{self, Sender, Receiver};
use std::path::Path;
use std::time::Duration;

use threadpool::ThreadPool;
use rand::StdRng;
use docopt::Docopt;

use tray_rust::film;
use tray_rust::geometry::Geometry;
use tray_rust::sampler::{self, Sampler};
use tray_rust::scene;
use tray_rust::integrator::Integrator;

static WIDTH: usize = 800;
static HEIGHT: usize = 600;
static USAGE: &'static str = "
Usage: tray_rust [options]

Options:
  -o <file>     Specify the output file to save the image. Supported formats are
                PNG, JPG and PPM. Default is 'out.png'.
  -n <number>   Specify the number of threads to use for rendering. Defaults to the number of cores
                on the system.
  -h, --help    Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_o: Option<String>,
    flag_n: Option<usize>,
}

// TODO: AREA LIGHTS NOTES:
// - They should be intersectable so they're like wierd instances.
// - What if point lights were also instances that just always returned None
//   for intersection tests?
// - Then each thread would build a list of &Instance that refer to the emissive
//   instances in the scene and we'd pass this around for the various lighting calculations.
//   It's a bit ugly but maybe cleaner than what was done previously in tray
//   It breaks the awkward handling of mixing point and area lights with each other which
//   is a plus.

/// Threads are each sent a sender end of the channel that is
/// read from by the render target thread which then saves the
/// values recieved to the render target
fn thread_work(tx: Sender<(f32, f32, film::Colorf)>, queue: Arc<sampler::BlockQueue>,
               scene: Arc<scene::Scene>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), 4);
    let mut samples = Vec::with_capacity(sampler.max_spp());
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(&*scene, &ray, &hit, &mut sampler, &mut rng).clamp();
                    samples.push((s.0, s.1, c));
                }
            }
            for s in samples.iter() {
                if let Err(e) = tx.send(*s) {
                    println!("Worker thread exiting with send error {:?}", e);
                    return;
                }
            }
            samples.clear();
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers(pool: &ThreadPool, n: usize, scene: Arc<scene::Scene>) -> Receiver<(f32, f32, film::Colorf)> {
    let (tx, rx) = mpsc::channel();
    let block_queue = Arc::new(sampler::BlockQueue::new((WIDTH as u32, HEIGHT as u32), (8, 8)));
    for _ in 0..n {
        let q = block_queue.clone();
        let t = tx.clone();
        let s = scene.clone();
        pool.execute(move || {
            thread_work(t, q, s);
        });
    }
    rx
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, n: usize){
    let scene = Arc::new(scene::Scene::new(WIDTH, HEIGHT));
    let pool = ThreadPool::new(n);
    let rx = spawn_workers(&pool, n, scene);
    for m in rx.iter() {
        rt.write(m.0, m.1, &m.2);
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let mut rt = film::RenderTarget::new(WIDTH, HEIGHT);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get(),
    };
    println!("Rendering using {} threads", n);
    let d = Duration::span(|| render_parallel(&mut rt, n));
    println!("Rendering took {}", d);
    let img = rt.get_render();
    let out_file = match args.flag_o {
        Some(f) => f,
        None => "out.png".to_string(),
    };
    match image::save_buffer(&Path::new(&out_file), &img[..], WIDTH as u32, HEIGHT as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<commit_msg>Considering reducing number of atomic ops by just sending the whole vec<commit_after>#![feature(duration)]
#![feature(duration_span)]
#![feature(collections_drain)]

extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize as rustc_serialize;
extern crate threadpool;
extern crate num_cpus;
extern crate tray_rust;

use std::vec::Vec;
use std::sync::{Arc};
use std::sync::mpsc::{self, Sender, Receiver};
use std::path::Path;
use std::time::Duration;

use threadpool::ThreadPool;
use rand::StdRng;
use docopt::Docopt;

use tray_rust::film;
use tray_rust::geometry::Geometry;
use tray_rust::sampler::{self, Sampler};
use tray_rust::scene;
use tray_rust::integrator::Integrator;

static WIDTH: usize = 800;
static HEIGHT: usize = 600;
static USAGE: &'static str = "
Usage: tray_rust [options]

Options:
  -o <file>     Specify the output file to save the image. Supported formats are
                PNG, JPG and PPM. Default is 'out.png'.
  -n <number>   Specify the number of threads to use for rendering. Defaults to the number of cores
                on the system.
  -h, --help    Show this message.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_o: Option<String>,
    flag_n: Option<usize>,
}

// TODO: AREA LIGHTS NOTES:
// - They should be intersectable so they're like wierd instances.
// - What if point lights were also instances that just always returned None
//   for intersection tests?
// - Then each thread would build a list of &Instance that refer to the emissive
//   instances in the scene and we'd pass this around for the various lighting calculations.
//   It's a bit ugly but maybe cleaner than what was done previously in tray
//   It breaks the awkward handling of mixing point and area lights with each other which
//   is a plus.

/// Threads are each sent a sender end of the channel that is
/// read from by the render target thread which then saves the
/// values recieved to the render target
fn thread_work(tx: Sender<Vec<(f32, f32, film::Colorf)>>, queue: Arc<sampler::BlockQueue>,
               scene: Arc<scene::Scene>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), 4);
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            let mut samples = Vec::with_capacity(sampler.max_spp());
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(&*scene, &ray, &hit, &mut sampler, &mut rng).clamp();
                    samples.push((s.0, s.1, c));
                }
            }
            if let Err(e) = tx.send(samples) {
                println!("Worker thread exiting with send error {:?}", e);
                return;
            }
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers(pool: &ThreadPool, n: usize, scene: Arc<scene::Scene>)
                 -> Receiver<Vec<(f32, f32, film::Colorf)>> {
    let (tx, rx) = mpsc::channel();
    let block_queue = Arc::new(sampler::BlockQueue::new((WIDTH as u32, HEIGHT as u32), (8, 8)));
    for _ in 0..n {
        let q = block_queue.clone();
        let t = tx.clone();
        let s = scene.clone();
        pool.execute(move || {
            thread_work(t, q, s);
        });
    }
    rx
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, n: usize){
    let scene = Arc::new(scene::Scene::new(WIDTH, HEIGHT));
    let pool = ThreadPool::new(n);
    let rx = spawn_workers(&pool, n, scene);
    for mut v in rx.iter() {
        for s in v.drain(..) {
            rt.write(s.0, s.1, &s.2);
        }
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit());

    let mut rt = film::RenderTarget::new(WIDTH, HEIGHT);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get(),
    };
    println!("Rendering using {} threads", n);
    let d = Duration::span(|| render_parallel(&mut rt, n));
    println!("Rendering took {}", d);
    let img = rt.get_render();
    let out_file = match args.flag_o {
        Some(f) => f,
        None => "out.png".to_string(),
    };
    match image::save_buffer(&Path::new(&out_file), &img[..], WIDTH as u32, HEIGHT as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<|endoftext|>


<commit_before>struct Item(&'static str);

struct Location {
    description: &'static str,
    items: Vec<Item>,
}

// how to do actions?
// as an enum? sounds reasonable.
// what properties do they have?
// a keyword which is typed in
// one or more arguments, possibly a variable number
// something which happens when they are invoked

// "look": print the area description
// "take + item": move the item to the player's inventory
// "go + direction": move to the area in that direction
// "use + item (+ object)": maybe remove the item, invoke a (targeted?) effect

// alternatively, instantiate actions at runtime
// write a struct for each one with arity and synonyms
// problem: each one is associated with a function of some sort
// do not want to go adding these at runtime if it can be avoided

fn parse(command: String) {
    let mut tokens = command.split(' ');
    let verb = tokens.nth(0);
    match verb {
        Some("look") => println!("You look around."),
        Some("take") => println!("You take something."),
        Some("go") => println!("You go somewhere."),
        Some("use") => println!("You use something."),
        _ => println!("Unknown command!"),
    }
    // look should just check for arity 0 invoke an associated function
    // take should parse rest of the command, see if there is an item with a name equal to the rest of the command
    // go should parse exactly one more token and go in that direction... how?
    // use should parse either one or two tokens and act accordingly
}

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
}
<commit_msg>Commands only seem to be recognized if an argument is supplied. Also, should verify the difference between 'use' and 'extern'.<commit_after>use std::io;

struct Item(&'static str);

struct Location {
    description: &'static str,
    items: Vec<Item>,
}

// how to do actions?
// as an enum? sounds reasonable.
// what properties do they have?
// a keyword which is typed in
// one or more arguments, possibly a variable number
// something which happens when they are invoked

// "look": print the area description
// "take + item": move the item to the player's inventory
// "go + direction": move to the area in that direction
// "use + item (+ object)": maybe remove the item, invoke a (targeted?) effect

// alternatively, instantiate actions at runtime
// write a struct for each one with arity and synonyms
// problem: each one is associated with a function of some sort
// do not want to go adding these at runtime if it can be avoided

fn parse(command: String) {
    let mut tokens = command.split(' ');
    let verb = tokens.nth(0);
    match verb {
        Some("look") => println!("You look around."),
        Some("take") => println!("You take something."),
        Some("go") => println!("You go somewhere."),
        Some("use") => println!("You use something."),
        Some("quit") => println!("Need CTRL-D for now."),
        _ => println!("Unknown command!"),
    }
    // look should just check for arity 0 invoke an associated function
    // take should parse rest of the command, see if there is an item with a name equal to the rest of the command
    // go should parse exactly one more token and go in that direction... how?
    // use should parse either one or two tokens and act accordingly
}

fn main() {
    let item1 = Item("Little key");
    let item2 = Item("Big key");
    let hall = Location{ description: "A wide open space. Streams of lava flow on both sides of the entry gate.",
                         items: vec![item1, item2] };
    loop {
        let input = io::stdin().read_line()
                               .ok()
                               .expect("Failed to read line");
        parse(input);
    }
}
<|endoftext|>


<commit_before>#![feature(inclusive_range_fields, range_contains)]

extern crate dotenv;
extern crate itertools;
#[macro_use]
extern crate lazy_static;
extern crate rand;
extern crate serenity;

use std::collections::BTreeMap;
use std::env;
use std::ops::RangeInclusive;

use dotenv::dotenv;
use itertools::Itertools;
use rand::Rng;
use serenity::prelude::*;
use serenity::model::prelude::*;

trait Command {
    fn required_arg_count(&self) -> RangeInclusive<usize>; //impl Range<usize>;
    fn exec(&self, ctx: &Context, msg: &Message, args: &[&str]);
}
type CommandMap = BTreeMap<&'static str, Box<Command + Sync>>;

lazy_static! {
    static ref COMMAND_MAP: CommandMap = {
        let mut commands = CommandMap::new();
        commands.insert("help", Box::new(Help));
        commands.insert("flip", Box::new(Flip));
        commands.insert("roll", Box::new(Roll));
        commands
    };
}

fn main() {
    let _ = dotenv();

    let creds = env::var("Z_CREDENTIALS")
        .expect("Unspecified credentials: set Z_CREDENTIALS in the environment (or in `.env`).");
    let mut client = Client::new(&creds, Handler).unwrap();
    client.start().unwrap();
}

struct Handler;
impl EventHandler for Handler {
    fn ready(&self, ctx: Context, _: Ready) {
        ctx.set_presence(Some(Game::playing("Rust")), OnlineStatus::Online)
    }

    fn message(&self, ctx: Context, msg: Message) {
        if msg.content.chars().next() == Some('!') {
            let mut tokens = msg.content[1..].split_whitespace();
            let maybe_command = tokens.next();
            let args = tokens.collect::<Vec<_>>();

            if let Some(command) = maybe_command {
                if let Some(command_handler) = COMMAND_MAP.get(command) {
                    let valid_arg_range = command_handler.required_arg_count();
                    if valid_arg_range.contains(args.len()) {
                        command_handler.exec(&ctx, &msg, &*args);
                    } else {
                        msg.reply(&format!(
                            "This command requires {} to {} arguments.",
                            valid_arg_range.start, valid_arg_range.end
                        )).unwrap();
                    }
                } else {
                    msg.reply(&format!("Unknown command: {}", command)).unwrap();
                }
            } else {
                msg.reply("No command specified.").unwrap();
            }
        }
    }
}

struct Help;
impl Command for Help {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        let help_output = COMMAND_MAP
            .keys()
            .intersperse(&", !")
            .fold("Available commands:\n!".to_owned(), |output, command| {
                output + command
            });

        msg.channel_id.say(&help_output).unwrap();
    }
}

struct Flip;
impl Command for Flip {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        if rand::thread_rng().gen() {
            msg.reply("Heads!").unwrap();
        } else {
            msg.reply("Tails!").unwrap();
        }
    }
}

struct Roll;
impl Command for Roll {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=1
    }

    fn exec(&self, _ctx: &Context, msg: &Message, args: &[&str]) {
        let upper_bound = if args.len() == 0 {
            6
        } else if args.len() == 1 {
            if let Ok(num) = args[0].parse() {
                num
            } else {
                msg.reply("That is not a number.").unwrap();
                return;
            }
        } else {
            unreachable!();
        };

        if upper_bound <= 0 {
            msg.reply("The upper bound must be a positive number.")
                .unwrap();
        } else {
            let result = rand::thread_rng().gen_range(0, upper_bound) + 1;
            msg.reply(&format!("{}", result)).unwrap();
        }
    }
}
<commit_msg>Apparently the range trait has been renamed.<commit_after>#![feature(inclusive_range_fields, range_contains)]

extern crate dotenv;
extern crate itertools;
#[macro_use]
extern crate lazy_static;
extern crate rand;
extern crate serenity;

use std::collections::BTreeMap;
use std::env;
use std::ops::RangeInclusive;

use dotenv::dotenv;
use itertools::Itertools;
use rand::Rng;
use serenity::prelude::*;
use serenity::model::prelude::*;

trait Command {
    fn required_arg_count(&self) -> RangeInclusive<usize>; //impl RangeArgument<usize>;
    fn exec(&self, ctx: &Context, msg: &Message, args: &[&str]);
}
type CommandMap = BTreeMap<&'static str, Box<Command + Sync>>;

lazy_static! {
    static ref COMMAND_MAP: CommandMap = {
        let mut commands = CommandMap::new();
        commands.insert("help", Box::new(Help));
        commands.insert("flip", Box::new(Flip));
        commands.insert("roll", Box::new(Roll));
        commands
    };
}

fn main() {
    let _ = dotenv();

    let creds = env::var("Z_CREDENTIALS")
        .expect("Unspecified credentials: set Z_CREDENTIALS in the environment (or in `.env`).");
    let mut client = Client::new(&creds, Handler).unwrap();
    client.start().unwrap();
}

struct Handler;
impl EventHandler for Handler {
    fn ready(&self, ctx: Context, _: Ready) {
        ctx.set_presence(Some(Game::playing("Rust")), OnlineStatus::Online)
    }

    fn message(&self, ctx: Context, msg: Message) {
        if msg.content.chars().next() == Some('!') {
            let mut tokens = msg.content[1..].split_whitespace();
            let maybe_command = tokens.next();
            let args = tokens.collect::<Vec<_>>();

            if let Some(command) = maybe_command {
                if let Some(command_handler) = COMMAND_MAP.get(command) {
                    let valid_arg_range = command_handler.required_arg_count();
                    if valid_arg_range.contains(args.len()) {
                        command_handler.exec(&ctx, &msg, &*args);
                    } else {
                        msg.reply(&format!(
                            "This command requires {} to {} arguments.",
                            valid_arg_range.start, valid_arg_range.end
                        )).unwrap();
                    }
                } else {
                    msg.reply(&format!("Unknown command: {}", command)).unwrap();
                }
            } else {
                msg.reply("No command specified.").unwrap();
            }
        }
    }
}

struct Help;
impl Command for Help {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        let help_output = COMMAND_MAP
            .keys()
            .intersperse(&", !")
            .fold("Available commands:\n!".to_owned(), |output, command| {
                output + command
            });

        msg.channel_id.say(&help_output).unwrap();
    }
}

struct Flip;
impl Command for Flip {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        if rand::thread_rng().gen() {
            msg.reply("Heads!").unwrap();
        } else {
            msg.reply("Tails!").unwrap();
        }
    }
}

struct Roll;
impl Command for Roll {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=1
    }

    fn exec(&self, _ctx: &Context, msg: &Message, args: &[&str]) {
        let upper_bound = if args.len() == 0 {
            6
        } else if args.len() == 1 {
            if let Ok(num) = args[0].parse() {
                num
            } else {
                msg.reply("That is not a number.").unwrap();
                return;
            }
        } else {
            unreachable!();
        };

        if upper_bound <= 0 {
            msg.reply("The upper bound must be a positive number.")
                .unwrap();
        } else {
            let result = rand::thread_rng().gen_range(0, upper_bound) + 1;
            msg.reply(&format!("{}", result)).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]

mod tmi;
mod vn64c;
mod demc;

extern crate regex;
extern crate toml;
extern crate time;

use std::fs::File;
use std::io::Read;

use regex::Regex;

use time::Duration;

use vn64c::{Controller, ButtonName};
use demc::DemC;
use demc::TimedInputCommand;
use vn64c::InputCommand;

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const VJOY_DEVICE_NUMBER: u8 = 1;
const MAX_JOYSTICK_COMMAND_DURATION: u32 = 5000;
const MAX_BUTTON_COMMAND_DURATION: u32 = 5000;

// Parse the TPPM toml configuration file; return the server, password, nick, and channel
fn parse_config_file() -> (String, String, String, String) {
    let mut config_file = File::open(CONFIG_FILE_PATH).unwrap();
    let mut config_string = String::new();
    config_file.read_to_string(&mut config_string);

    //@todo understand this generics magic
    let toml_tree: toml::Value = config_string.parse().unwrap();

    let server = String::from(toml_tree.lookup("irc.server").unwrap().as_str().unwrap());
    let pass = String::from(toml_tree.lookup("irc.pass").unwrap().as_str().unwrap());
    let nick = String::from(toml_tree.lookup("irc.nick").unwrap().as_str().unwrap());
    let channel = String::from(toml_tree.lookup("irc.channel").unwrap().as_str().unwrap());

    (server, pass, nick, channel)
}

// Attempt to parse an IRC message into a list of controller commands
//@todo just use a custom state machine rather than regex, this has to be insanely slow
//@todo this function is huge
fn parse_string_as_commands(msg: &String, re: &Regex) -> Option<Vec<TimedInputCommand>> {
    let mut last_cap_end = None;
    let mut cumulative_delay: u32 = 0;
    let mut last_command: Option<TimedInputCommand> = None;
    let mut cap_start_zero = false;
    let mut final_cap_end: usize = 0;
    let mut res: Vec<TimedInputCommand> = Vec::new();

    for cap in re.captures_iter(&msg.to_lowercase()) {
        let (cap_start, cap_end) = cap.pos(0).unwrap();

        // Raise a flag if this capture starts at the first string position - after iterating over all captures, we'll
        // make sure it was raised, and if it wasn't, we didn't parse a valid command message
        if cap_start == 0 {
            cap_start_zero = true;
        }

        // Make sure that all captures are continuous; that we're parsing commands and only commands
        // eg. we don't want "hahah" to parse as two "a" commands
        if let Some(last_cap_end) = last_cap_end {
            if last_cap_end != cap_start {
                return None;
            }
        }

        // Store the last capture's ending position - after iterating over all captures, we'll make sure the last one
        // ended
        final_cap_end = cap_end;

        // Our regex should match on exactly one of three groups: "joystick", "button", or "delay"
        if let Some(_) = cap.name("joystick") {
            match last_command {
                Some(command) => {
                    cumulative_delay += command.duration.num_milliseconds() as u32;
                    match command.command {
                        InputCommand::Joystick{direction: _, strength: _} => {
                            cumulative_delay += 51;
                        },
                        InputCommand::Button{name: _, value: _} => {
                            ()
                        }
                    }
                },
                None =>  ()
            }
            // joystick command - should have one, two, or four groups:
            // "joystick_strength" (optional)
            // "joystick_direction" (mandatory)
            // "joystick_duration" (optional),
            // "joystick_duration_units" (optional; must be present if joystick_duration is)
            let mut joystick_strength: f32 = 1.0;
            let mut joystick_direction: u16 = 0;
            let mut joystick_duration: u32 = 500;
            if let Some(jscap) = cap.name("joystick_strength") {
                match jscap.parse::<u8>() {
                    Ok(strength_u8) => { joystick_strength = strength_u8 as f32 / 100.0; },
                    _ => return None
                }
            }
            if let Some(jdcap) = cap.name("joystick_direction") {
                match jdcap {
                    "up" => { joystick_direction = 90; },
                    "down" => { joystick_direction = 270; },
                    "left" => { joystick_direction = 180; },
                    "right" => { joystick_direction = 0; },
                    _ => ()
                }
            } else {
                return None;
            }
            if let Some(jdcap) = cap.name("joystick_duration") {
                match jdcap.parse::<u32>() {
                    Ok(duration_u32) => { joystick_duration = duration_u32; },
                    _ => return None
                }

                if let Some(jdcap_units) = cap.name("joystick_duration_units") {
                    if jdcap_units == "s" {
                        joystick_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            // treat joystick commands with strength <0%, >100% or duration >5s as invalid
            if joystick_strength > 1.0 || joystick_strength < 0.0 || joystick_duration > MAX_JOYSTICK_COMMAND_DURATION {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + time::Duration::milliseconds(cumulative_delay as i64),
                                                             duration: time::Duration::milliseconds(joystick_duration as i64),
                                                             command: InputCommand::Joystick { direction: joystick_direction,
                                                                                strength: joystick_strength} };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(_) = cap.name("button") {
            match last_command {
                Some(command) => {
                    match command.command {
                        InputCommand::Joystick{direction: _, strength: _} => {
                            cumulative_delay += command.duration.num_milliseconds() as u32;
                            if command.duration.num_milliseconds() >= 17 {
                                cumulative_delay -= 17;
                            }
                        },
                        InputCommand::Button{name: _, value: _} => {
                            if command.duration.num_milliseconds() == 167 {
                                cumulative_delay += 500; //massive hack
                            } else {
                                cumulative_delay += command.duration.num_milliseconds() as u32;
                            }
                            cumulative_delay += 51;
                        }
                    }
                },
                None =>  ()
            }
            // button command - should have one or three groups:
            // "button_name" (mandatory)
            // "button_duration" (optional),
            // "button_duration_units" (optional; must be present if joystick_duration is)
            let mut button_name;
            let mut button_duration: u32 = 167;

            if let Some(bncap) = cap.name("button_name") {
                button_name = match bncap {
                    "a" => ButtonName::A,
                    "b" => ButtonName::B,
                    "z" => ButtonName::Z,
                    "l" => ButtonName::L,
                    "r" => ButtonName::R,
                    "start" => ButtonName::Start,
                    "cup" => ButtonName::Cup,
                    "cdown" => ButtonName::Cdown,
                    "cleft" => ButtonName::Cleft,
                    "cright" => ButtonName::Cright,
                    "dup" => ButtonName::Dup,
                    "ddown" => ButtonName::Ddown,
                    "dleft" => ButtonName::Dleft,
                    "dright" => ButtonName::Dright,
                    _ => return None
                };
            } else {
                return None;
            }

            if let Some(bdcap) = cap.name("button_duration") {
                match bdcap.parse::<u32>() {
                    Ok(duration_u32) => { button_duration = duration_u32; },
                    _ => return None
                }

                if let Some(bdcap_units) = cap.name("button_duration_units") {
                    if bdcap_units == "s" {
                        button_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            if button_duration > MAX_BUTTON_COMMAND_DURATION {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + Duration::milliseconds(cumulative_delay as i64),
                                              duration: time::Duration::milliseconds(button_duration as i64),
                                              command: InputCommand::Button { name: button_name, value: true } };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(dcap) = cap.name("delay") {
            // delay command - only one argument, the delay to insert
            match dcap {
                "+" => { cumulative_delay += 17; },
                "!" => { cumulative_delay += 217; },
                _ => { return None; }
            }
            last_command = None
        }

        last_cap_end = Some(cap_end);
    }

    if final_cap_end != msg.len() {
        return None;
    }

    if cap_start_zero != true {
        return None;
    }

    return Some(res);
}

fn main() {
    // Parse our configuration file
    let (server, pass, nick, channel) = parse_config_file();

    // Initialize a democratized virtual N64 controller
    let controller = Controller::new(VJOY_DEVICE_NUMBER).unwrap();
    let dem_controller = DemC::new(controller);

    // Start our IRC connection
    let tmi_stream = tmi::TmiStream::establish(server, pass, nick, channel).unwrap();

    // Our regex for parsing IRC messages - this is here so that it need not be instantiated every
    // time we handle an IRC message
    let re = Regex::new(r"\s*((?P<joystick>((?P<joystick_strength>[:digit:]+)%\s*)?(?P<joystick_direction>up|down|left|right)(\s*(?P<joystick_duration>[:digit:]+)(?P<joystick_duration_units>s|ms))?)|(?P<button>((?P<button_name>start|cup|cdown|cleft|cright|dup|ddown|dleft|dright|a|b|z|l|r)(\s*(?P<button_duration>[:digit:]+)(?P<button_duration_units>s|ms))?))|(?P<delay>[\+!]))\s*").unwrap();

    // Poll the IRC connection and handle its messages forever
    loop {
        let (sender, message) = tmi_stream.receive();
        println!("{}: {}", sender, message);
        if let Some(cmds) = parse_string_as_commands(&message, &re) {
            for &cmd in cmds.iter() {
                dem_controller.add_command(cmd);
            }
        }
    }
}
<commit_msg>Write all of chat into a file, prefixing command messages with an underscore<commit_after>#![allow(unused_must_use)]

mod tmi;
mod vn64c;
mod demc;

extern crate regex;
extern crate toml;
extern crate time;

use std::path::Path;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::Read;
use std::io::Write;

use regex::Regex;

use time::Duration;

use vn64c::{Controller, ButtonName};
use demc::DemC;
use demc::TimedInputCommand;
use vn64c::InputCommand;

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const CHAT_LOG_PATH: &'static str = "chat.txt";
const VJOY_DEVICE_NUMBER: u8 = 1;
const MAX_JOYSTICK_COMMAND_DURATION: u32 = 5000;
const MAX_BUTTON_COMMAND_DURATION: u32 = 5000;

// Parse the TPPM toml configuration file; return the server, password, nick, and channel
fn parse_config_file() -> (String, String, String, String) {
    let mut config_file = File::open(CONFIG_FILE_PATH).unwrap();
    let mut config_string = String::new();
    config_file.read_to_string(&mut config_string);

    //@todo understand this generics magic
    let toml_tree: toml::Value = config_string.parse().unwrap();

    let server = String::from(toml_tree.lookup("irc.server").unwrap().as_str().unwrap());
    let pass = String::from(toml_tree.lookup("irc.pass").unwrap().as_str().unwrap());
    let nick = String::from(toml_tree.lookup("irc.nick").unwrap().as_str().unwrap());
    let channel = String::from(toml_tree.lookup("irc.channel").unwrap().as_str().unwrap());

    (server, pass, nick, channel)
}

// Attempt to parse an IRC message into a list of controller commands
//@todo just use a custom state machine rather than regex, this has to be insanely slow
//@todo this function is huge
fn parse_string_as_commands(msg: &String, re: &Regex) -> Option<Vec<TimedInputCommand>> {
    let mut last_cap_end = None;
    let mut cumulative_delay: u32 = 0;
    let mut last_command: Option<TimedInputCommand> = None;
    let mut cap_start_zero = false;
    let mut final_cap_end: usize = 0;
    let mut res: Vec<TimedInputCommand> = Vec::new();

    for cap in re.captures_iter(&msg.to_lowercase()) {
        let (cap_start, cap_end) = cap.pos(0).unwrap();

        // Raise a flag if this capture starts at the first string position - after iterating over all captures, we'll
        // make sure it was raised, and if it wasn't, we didn't parse a valid command message
        if cap_start == 0 {
            cap_start_zero = true;
        }

        // Make sure that all captures are continuous; that we're parsing commands and only commands
        // eg. we don't want "hahah" to parse as two "a" commands
        if let Some(last_cap_end) = last_cap_end {
            if last_cap_end != cap_start {
                return None;
            }
        }

        // Store the last capture's ending position - after iterating over all captures, we'll make sure the last one
        // ended
        final_cap_end = cap_end;

        // Our regex should match on exactly one of three groups: "joystick", "button", or "delay"
        if let Some(_) = cap.name("joystick") {
            match last_command {
                Some(command) => {
                    cumulative_delay += command.duration.num_milliseconds() as u32;
                    match command.command {
                        InputCommand::Joystick{direction: _, strength: _} => {
                            cumulative_delay += 51;
                        },
                        InputCommand::Button{name: _, value: _} => {
                            ()
                        }
                    }
                },
                None =>  ()
            }
            // joystick command - should have one, two, or four groups:
            // "joystick_strength" (optional)
            // "joystick_direction" (mandatory)
            // "joystick_duration" (optional),
            // "joystick_duration_units" (optional; must be present if joystick_duration is)
            let mut joystick_strength: f32 = 1.0;
            let mut joystick_direction: u16 = 0;
            let mut joystick_duration: u32 = 500;
            if let Some(jscap) = cap.name("joystick_strength") {
                match jscap.parse::<u8>() {
                    Ok(strength_u8) => { joystick_strength = strength_u8 as f32 / 100.0; },
                    _ => return None
                }
            }
            if let Some(jdcap) = cap.name("joystick_direction") {
                match jdcap {
                    "up" => { joystick_direction = 90; },
                    "down" => { joystick_direction = 270; },
                    "left" => { joystick_direction = 180; },
                    "right" => { joystick_direction = 0; },
                    _ => ()
                }
            } else {
                return None;
            }
            if let Some(jdcap) = cap.name("joystick_duration") {
                match jdcap.parse::<u32>() {
                    Ok(duration_u32) => { joystick_duration = duration_u32; },
                    _ => return None
                }

                if let Some(jdcap_units) = cap.name("joystick_duration_units") {
                    if jdcap_units == "s" {
                        joystick_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            // treat joystick commands with strength <0%, >100% or duration >5s as invalid
            if joystick_strength > 1.0 || joystick_strength < 0.0 || joystick_duration > MAX_JOYSTICK_COMMAND_DURATION {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + time::Duration::milliseconds(cumulative_delay as i64),
                                                             duration: time::Duration::milliseconds(joystick_duration as i64),
                                                             command: InputCommand::Joystick { direction: joystick_direction,
                                                                                strength: joystick_strength} };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(_) = cap.name("button") {
            match last_command {
                Some(command) => {
                    match command.command {
                        InputCommand::Joystick{direction: _, strength: _} => {
                            cumulative_delay += command.duration.num_milliseconds() as u32;
                            if command.duration.num_milliseconds() >= 17 {
                                cumulative_delay -= 17;
                            }
                        },
                        InputCommand::Button{name: _, value: _} => {
                            if command.duration.num_milliseconds() == 167 {
                                cumulative_delay += 500; //massive hack
                            } else {
                                cumulative_delay += command.duration.num_milliseconds() as u32;
                            }
                            cumulative_delay += 51;
                        }
                    }
                },
                None =>  ()
            }
            // button command - should have one or three groups:
            // "button_name" (mandatory)
            // "button_duration" (optional),
            // "button_duration_units" (optional; must be present if joystick_duration is)
            let mut button_name;
            let mut button_duration: u32 = 167;

            if let Some(bncap) = cap.name("button_name") {
                button_name = match bncap {
                    "a" => ButtonName::A,
                    "b" => ButtonName::B,
                    "z" => ButtonName::Z,
                    "l" => ButtonName::L,
                    "r" => ButtonName::R,
                    "start" => ButtonName::Start,
                    "cup" => ButtonName::Cup,
                    "cdown" => ButtonName::Cdown,
                    "cleft" => ButtonName::Cleft,
                    "cright" => ButtonName::Cright,
                    "dup" => ButtonName::Dup,
                    "ddown" => ButtonName::Ddown,
                    "dleft" => ButtonName::Dleft,
                    "dright" => ButtonName::Dright,
                    _ => return None
                };
            } else {
                return None;
            }

            if let Some(bdcap) = cap.name("button_duration") {
                match bdcap.parse::<u32>() {
                    Ok(duration_u32) => { button_duration = duration_u32; },
                    _ => return None
                }

                if let Some(bdcap_units) = cap.name("button_duration_units") {
                    if bdcap_units == "s" {
                        button_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            if button_duration > MAX_BUTTON_COMMAND_DURATION {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + Duration::milliseconds(cumulative_delay as i64),
                                              duration: time::Duration::milliseconds(button_duration as i64),
                                              command: InputCommand::Button { name: button_name, value: true } };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(dcap) = cap.name("delay") {
            // delay command - only one argument, the delay to insert
            match dcap {
                "+" => { cumulative_delay += 17; },
                "!" => { cumulative_delay += 217; },
                _ => { return None; }
            }
            last_command = None
        }

        last_cap_end = Some(cap_end);
    }

    if final_cap_end != msg.len() {
        return None;
    }

    if cap_start_zero != true {
        return None;
    }

    return Some(res);
}

fn main() {
    // Parse our configuration file
    let (server, pass, nick, channel) = parse_config_file();

    // Initialize a democratized virtual N64 controller
    let controller = Controller::new(VJOY_DEVICE_NUMBER).unwrap();
    let dem_controller = DemC::new(controller);

    // Start our IRC connection
    let tmi_stream = tmi::TmiStream::establish(server, pass, nick, channel).unwrap();

    // Our regex for parsing IRC messages - this is here so that it need not be instantiated every
    // time we handle an IRC message
    let re = Regex::new(r"\s*((?P<joystick>((?P<joystick_strength>[:digit:]+)%\s*)?(?P<joystick_direction>up|down|left|right)(\s*(?P<joystick_duration>[:digit:]+)(?P<joystick_duration_units>s|ms))?)|(?P<button>((?P<button_name>start|cup|cdown|cleft|cright|dup|ddown|dleft|dright|a|b|z|l|r)(\s*(?P<button_duration>[:digit:]+)(?P<button_duration_units>s|ms))?))|(?P<delay>[\+!]))\s*").unwrap();

    let chat_log_path = Path::new(CHAT_LOG_PATH);
    let mut chat_log_file = match OpenOptions::new().read(true).write(true).append(true).create(true).
                                  open(&chat_log_path)
    {
        Ok(file) => file,
        Err(reason) => panic!("Couldn't open chat log file for writing! {}", std::error::Error::description(&reason))
    };

    // Poll the IRC connection and handle its messages forever
    loop {
        let (sender, message) = tmi_stream.receive();
        let mut log_string: String;
        if let Some(cmds) = parse_string_as_commands(&message, &re) {
            for &cmd in cmds.iter() {
                dem_controller.add_command(cmd);
            }
            log_string = format!("_{}: {}", sender, message)
        } else {
            log_string = format!("{}: {}", sender, message)
        }

        chat_log_file.write_all(&log_string.as_bytes());
        chat_log_file.write_all("\r\n".as_bytes());
        chat_log_file.flush();
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate structopt;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;
#[macro_use]
mod syslog;

use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use structs::Config;

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
}
<commit_msg>Suppress a warning of clippy<commit_after>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate structopt;
extern crate toml;

mod error;
mod ghclient;
mod statics;
mod structs;
#[macro_use]
mod syslog;

use statics::CONF_PATH;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Command {
    /// Gets user public key
    Key {
        #[structopt(parse(from_str))]
        user: String,
    },
    /// Executes pam check
    Pam,
    /// Check configuration
    Check {
        #[structopt(parse(from_os_str))]
        confpath: std::path::PathBuf,
    },
    /// Cleans caches up
    #[structopt(alias = "cleanup")]
    CleanUp,
    /// Get rate limit for github api
    #[structopt(alias = "ratelimit")]
    RateLimit,
    /// Displays version details
    Version,
    /// Displays completion
    Completion {
        #[structopt(subcommand)]
        shell: Shell,
    },
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
enum Shell {
    Bash,
    Fish,
    Zsh,
    PowerShell,
    Elvish,
}

fn main() {
    let command = Command::from_args();

    use ghclient::GithubClient;
    use std::env;
    use std::process;
    use structs::Config;

    match command {
        Command::Check { confpath } => match Config::from_path(&confpath) {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(11),
        },
        Command::Key { user } => {
            match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                               .and_then(|client| client.print_user_public_key(&user))
            {
                Ok(_) => process::exit(0),
                Err(_) => process::exit(21),
            }
        }
        Command::Pam => match env::var("PAM_USER") {
            Ok(user) => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                           .and_then(|client| client.check_pam(&user))
            {
                Ok(true) => process::exit(0),
                Ok(false) => process::exit(1),
                Err(_) => process::exit(31),
            },
            Err(_) => process::exit(41),
        },
        Command::CleanUp => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                               .and_then(|client| client.clear_all_caches())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(51),
        },
        Command::RateLimit => match Config::from_path(&CONF_PATH).and_then(|conf| Ok(GithubClient::new(&conf)))
                                                                 .and_then(|client| client.print_rate_limit())
        {
            Ok(_) => process::exit(0),
            Err(_) => process::exit(61),
        },
        Command::Version => {
            println!("{}",
                     concat!(env!("CARGO_PKG_VERSION"),
                             include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))));
        }
        Command::Completion { shell } => {
            let shell = match shell {
                Shell::Bash => structopt::clap::Shell::Bash,
                Shell::Fish => structopt::clap::Shell::Fish,
                Shell::Zsh => structopt::clap::Shell::Zsh,
                Shell::PowerShell => structopt::clap::Shell::PowerShell,
                Shell::Elvish => structopt::clap::Shell::Elvish,
            };
            Command::clap().gen_completions_to("sectora", shell, &mut std::io::stdout());
        }
    };
}
<|endoftext|>


<commit_before>use instr::Instr;
use cpu::Cpu;
use cpu::CpuInterrupt;
use time::precise_time_ns;
use std::fs::File;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

use glium::DisplayBuild;
use glium::Surface;
use glium::SwapBuffersError;
use glium::glutin::Api;
use glium::glutin::GlRequest;
use glium::glutin::Event;

extern crate time;
extern crate getopts;
#[macro_use]
extern crate glium;
extern crate cgmath;

mod instr;
mod cpu;
mod mem;
mod render;

#[derive(Copy, Clone)]
pub enum IntType {
    Vblank,
    Hblank,
    IoTimer,
}

struct ClockInt {
    pub int_target: u64,
    pub int_type: IntType,
}

impl PartialEq for ClockInt {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.int_target == other.int_target
    }
}

impl Eq for ClockInt {}

impl PartialOrd for ClockInt {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match self.int_target.partial_cmp(&other.int_target) {
            Some(Ordering::Less) => Some(Ordering::Greater),
            Some(Ordering::Greater) => Some(Ordering::Less),
            ord => ord,
        }
    }
}

impl Ord for ClockInt {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        match self.int_target.cmp(&other.int_target) {
            Ordering::Less => Ordering::Greater,
            Ordering::Greater => Ordering::Less,
            ord => ord,
        }
    }
}

const NS_PER_S: u64 = 1_000_000_000;
const MS_PER_NS: u64 = 1_000_000;

// 10ms
const BUSY_WAIT_THRESHOLD: u64 = 10_000_000;

pub struct Clock {
    freq:       u32,
    period:     u64,
    int_heap:   BinaryHeap<ClockInt>,
}

impl Clock {

    pub fn new(freq: u32) -> Clock {
        Clock {
            freq: freq,
            period: NS_PER_S / (freq as u64),
            int_heap: BinaryHeap::new(),
        }
    }

    pub fn set_interrupt(&mut self, itype: IntType, period: u64) {
        let start = precise_time_ns();
        let int = ClockInt {
            int_type: itype,
            int_target: start + period,
        };
        self.int_heap.push(int);
    }

    pub fn wait_cycles(&mut self, n: u32) -> Option<IntType> {
        let start = precise_time_ns();
        let real_wait = self.period * (n as u64);
        let real_target = real_wait + start;
        let (target, result) = if let Some(interrupt) = self.int_heap.pop() {
            if real_target > interrupt.int_target {
                (interrupt.int_target, Some(interrupt.int_type))
            } else {
                self.int_heap.push(interrupt);
                (real_target, None)
            }
        } else {
            (real_target, None)
        };
        let mut curtime = start;
        if target > start && target - start > BUSY_WAIT_THRESHOLD {
            std::thread::sleep_ms(((target - start) * MS_PER_NS) as u32);
            return result;
        } else {
            loop {
                if curtime >= target {
                    return result;
                }
                curtime = precise_time_ns();
            }
        }
    }

}

fn main() {
    //  Gather command line args
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(e) => panic!("Error: {}", e),
    };
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("No input ROM");
        return;
    };

    // Build graphics context and window
    let display = glium::glutin::WindowBuilder::new()
        .with_title("Gameboy Rust".to_string())
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 2)))
        .build_glium()
        .unwrap();

    // Do machine initialization
    let mut cpu = Cpu::new();
    cpu.init();
    {
        let mut ram = cpu.get_ram();
        let mut biosfile = match File::open(std::path::Path::new("rom/bios.bin")) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening bios file");
                return;
            },
        };
        let mut romfile = match File::open(std::path::Path::new(&input)) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening file: {}", e);
                return;
            }
        };
        if let Err(e) = ram.load_bios(&mut biosfile) {
            println!("Error loading bios data: {}", e);
            return;
        }
        if let Err(e) = ram.load_rom(&mut romfile) {
            println!("Error loading rom data: {}", e);
            return;
        }
    }

    // Initialize virtual LCD
    let mut lcd = render::GbDisplay::new(&display);

    let mut viewport = {
        let window = display.get_window();
        let (width, height) = window.unwrap().get_inner_size_pixels().unwrap();
        render::calculate_viewport(width, height)
    };

    // Initialize virtual hardware clocks
    let mut clock = Clock::new(cpu::GB_FREQUENCY);
    clock.set_interrupt(IntType::Vblank, render::VBLANK_PERIOD);
    clock.set_interrupt(IntType::Hblank, render::HBLANK_PERIOD);
    clock.set_interrupt(IntType::IoTimer, cpu::TIMER_BASE_PERIOD_NS);

    // Simulate CPU
    'main: loop {
        // Collect user input
        for ev in display.poll_events() {
            match ev {
                Event::Closed => {
                    break 'main;
                },
                Event::Resized(..) => {
                    let window = display.get_window();
                    let (width, height) = window.unwrap().get_inner_size_pixels().unwrap();
                    viewport = render::calculate_viewport(width, height);
                },
                _ => (),
            }
        }

        // Simulate CPU and hardware timers
        'sim: loop  {
            if let Some(int) = clock.wait_cycles(cpu.do_instr()) {
                // Handle timer interrupt
                match int {
                    // Interrupt at the start of the vblank period
                    IntType::Vblank => {
                        clock.set_interrupt(IntType::Vblank, render::VBLANK_PERIOD);
                        cpu.interrupt(CpuInterrupt::Vblank);
                        let ly = lcd.set_ly_vblank();
                        let ram = cpu.get_ram();
                        ram[mem::IOREG_LY] = ly;
                    }
                    // ~10 H-Blanks occur after the V-Blank starts
                    IntType::Hblank => {
                        clock.set_interrupt(IntType::Hblank, render::HBLANK_PERIOD);
                        let ly = lcd.inc_ly_counter();
                        let ram = cpu.get_ram();
                        ram[mem::IOREG_LY] = ly;
                        // At the end, collect data from VRAM and render it
                        if ly == 0 {
                            break 'sim;
                        }
                    }
                    // Do timer computations
                    IntType::IoTimer => {
                        clock.set_interrupt(IntType::IoTimer, cpu::TIMER_BASE_PERIOD_NS);
                        cpu.inc_io_timer();
                    }
                }
            }
        }

        // Redraw screen
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        lcd.clear_viewport(&mut target, viewport, (1.0, 1.0, 1.0, 1.0));
        lcd.draw(&display, &mut target, viewport, cpu.get_ram());
        match target.finish().err() {
            Some(SwapBuffersError::ContextLost) => {
                panic!("OpenGL contetxt lost!");
            },
            Some(SwapBuffersError::AlreadySwapped) => {
                println!("Warning: OpenGL buffer already swapped");
            },
            None => (),
        }
        display.flush();
    }
}
<commit_msg>Fix unit error that would result in long sleep<commit_after>use instr::Instr;
use cpu::Cpu;
use cpu::CpuInterrupt;
use time::precise_time_ns;
use std::fs::File;
use std::cmp::Ordering;
use std::collections::BinaryHeap;

use glium::DisplayBuild;
use glium::Surface;
use glium::SwapBuffersError;
use glium::glutin::Api;
use glium::glutin::GlRequest;
use glium::glutin::Event;

extern crate time;
extern crate getopts;
#[macro_use]
extern crate glium;
extern crate cgmath;

mod instr;
mod cpu;
mod mem;
mod render;

#[derive(Copy, Clone)]
pub enum IntType {
    Vblank,
    Hblank,
    IoTimer,
}

struct ClockInt {
    pub int_target: u64,
    pub int_type: IntType,
}

impl PartialEq for ClockInt {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.int_target == other.int_target
    }
}

impl Eq for ClockInt {}

impl PartialOrd for ClockInt {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        match self.int_target.partial_cmp(&other.int_target) {
            Some(Ordering::Less) => Some(Ordering::Greater),
            Some(Ordering::Greater) => Some(Ordering::Less),
            ord => ord,
        }
    }
}

impl Ord for ClockInt {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        match self.int_target.cmp(&other.int_target) {
            Ordering::Less => Ordering::Greater,
            Ordering::Greater => Ordering::Less,
            ord => ord,
        }
    }
}

const NS_PER_S: u64 = 1_000_000_000;
const NS_PER_MS: u64 = 1_000_000;

// 10ms
const BUSY_WAIT_THRESHOLD: u64 = 10_000_000;

pub struct Clock {
    freq:       u32,
    period:     u64,
    int_heap:   BinaryHeap<ClockInt>,
}

impl Clock {

    pub fn new(freq: u32) -> Clock {
        Clock {
            freq: freq,
            period: NS_PER_S / (freq as u64),
            int_heap: BinaryHeap::new(),
        }
    }

    pub fn set_interrupt(&mut self, itype: IntType, period: u64) {
        let start = precise_time_ns();
        let int = ClockInt {
            int_type: itype,
            int_target: start + period,
        };
        self.int_heap.push(int);
    }

    pub fn wait_cycles(&mut self, n: u32) -> Option<IntType> {
        let start = precise_time_ns();
        let real_wait = self.period * (n as u64);
        let real_target = real_wait + start;
        let (target, result) = if let Some(interrupt) = self.int_heap.pop() {
            if real_target > interrupt.int_target {
                (interrupt.int_target, Some(interrupt.int_type))
            } else {
                self.int_heap.push(interrupt);
                (real_target, None)
            }
        } else {
            (real_target, None)
        };
        let mut curtime = start;
        if target > start && target - start > BUSY_WAIT_THRESHOLD {
            std::thread::sleep_ms(((target - start) / NS_PER_MS) as u32);
            return result;
        } else {
            loop {
                if curtime >= target {
                    return result;
                }
                curtime = precise_time_ns();
            }
        }
    }

}

fn main() {
    //  Gather command line args
    let args: Vec<String> = std::env::args().collect();
    let mut opts = getopts::Options::new();
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m },
        Err(e) => panic!("Error: {}", e),
    };
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        println!("No input ROM");
        return;
    };

    // Build graphics context and window
    let display = glium::glutin::WindowBuilder::new()
        .with_title("Gameboy Rust".to_string())
        .with_gl(GlRequest::Specific(Api::OpenGl, (3, 2)))
        .build_glium()
        .unwrap();

    // Do machine initialization
    let mut cpu = Cpu::new();
    cpu.init();
    {
        let mut ram = cpu.get_ram();
        let mut biosfile = match File::open(std::path::Path::new("rom/bios.bin")) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening bios file");
                return;
            },
        };
        let mut romfile = match File::open(std::path::Path::new(&input)) {
            Ok(f) => { f },
            Err(e) => {
                println!("Error opening file: {}", e);
                return;
            }
        };
        if let Err(e) = ram.load_bios(&mut biosfile) {
            println!("Error loading bios data: {}", e);
            return;
        }
        if let Err(e) = ram.load_rom(&mut romfile) {
            println!("Error loading rom data: {}", e);
            return;
        }
    }

    // Initialize virtual LCD
    let mut lcd = render::GbDisplay::new(&display);

    let mut viewport = {
        let window = display.get_window();
        let (width, height) = window.unwrap().get_inner_size_pixels().unwrap();
        render::calculate_viewport(width, height)
    };

    // Initialize virtual hardware clocks
    let mut clock = Clock::new(cpu::GB_FREQUENCY);
    clock.set_interrupt(IntType::Vblank, render::VBLANK_PERIOD);
    clock.set_interrupt(IntType::Hblank, render::HBLANK_PERIOD);
    clock.set_interrupt(IntType::IoTimer, cpu::TIMER_BASE_PERIOD_NS);

    // Simulate CPU
    'main: loop {
        // Collect user input
        for ev in display.poll_events() {
            match ev {
                Event::Closed => {
                    break 'main;
                },
                Event::Resized(..) => {
                    let window = display.get_window();
                    let (width, height) = window.unwrap().get_inner_size_pixels().unwrap();
                    viewport = render::calculate_viewport(width, height);
                },
                _ => (),
            }
        }

        // Simulate CPU and hardware timers
        'sim: loop  {
            if let Some(int) = clock.wait_cycles(cpu.do_instr()) {
                // Handle timer interrupt
                match int {
                    // Interrupt at the start of the vblank period
                    IntType::Vblank => {
                        clock.set_interrupt(IntType::Vblank, render::VBLANK_PERIOD);
                        cpu.interrupt(CpuInterrupt::Vblank);
                        let ly = lcd.set_ly_vblank();
                        let ram = cpu.get_ram();
                        ram[mem::IOREG_LY] = ly;
                    }
                    // ~10 H-Blanks occur after the V-Blank starts
                    IntType::Hblank => {
                        clock.set_interrupt(IntType::Hblank, render::HBLANK_PERIOD);
                        let ly = lcd.inc_ly_counter();
                        let ram = cpu.get_ram();
                        ram[mem::IOREG_LY] = ly;
                        // At the end, collect data from VRAM and render it
                        if ly == 0 {
                            break 'sim;
                        }
                    }
                    // Do timer computations
                    IntType::IoTimer => {
                        clock.set_interrupt(IntType::IoTimer, cpu::TIMER_BASE_PERIOD_NS);
                        cpu.inc_io_timer();
                    }
                }
            }
        }

        // Redraw screen
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        lcd.clear_viewport(&mut target, viewport, (1.0, 1.0, 1.0, 1.0));
        lcd.draw(&display, &mut target, viewport, cpu.get_ram());
        match target.finish().err() {
            Some(SwapBuffersError::ContextLost) => {
                panic!("OpenGL contetxt lost!");
            },
            Some(SwapBuffersError::AlreadySwapped) => {
                println!("Warning: OpenGL buffer already swapped");
            },
            None => (),
        }
        display.flush();
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate serde_derive;

mod grammar;

use grammar::{TurtleParser, Rule};
use pest::{Parser, iterators, inputs};
use std::{fs, env};
use std::io::Read;

#[derive(Serialize, Deserialize)]
struct Result {
    rule: String,
    text: Option<String>,
    children: Vec<Result>,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut file = fs::File::open(&args[1]).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents);

    let pairs = TurtleParser::parse_str(Rule::turtle_doc, &contents)
        .unwrap_or_else(|e| panic!("{}", e));
    let mut result = Vec::new();
    print_deep(pairs, &mut result);
    println!("{}", serde_json::to_string(&result).unwrap());
}

fn print_deep(pairs: iterators::Pairs<grammar::Rule, inputs::StrInput>, result: &mut Vec<Result>) {
    for pair in pairs {
        let rule = format!("{:?}", pair.as_rule());
        let text = String::from(pair.as_str());
        let mut children = Vec::new();
        print_deep(pair.into_inner(), &mut children);
        result.push(Result {
            rule,
            text: if children.len() == 0 {
              Some(text)
            } else {
              None
            },
            children,
        });
    }
}
<commit_msg>Rename print_deep -> create_result_from_pairs<commit_after>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate pest;
#[macro_use]
extern crate pest_derive;
#[macro_use]
extern crate serde_derive;

mod grammar;

use grammar::{TurtleParser, Rule};
use pest::{Parser, iterators, inputs};
use std::{fs, env};
use std::io::Read;

#[derive(Serialize, Deserialize)]
struct Result {
    rule: String,
    text: Option<String>,
    children: Vec<Result>,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut file = fs::File::open(&args[1]).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents);

    let pairs = TurtleParser::parse_str(Rule::turtle_doc, &contents)
        .unwrap_or_else(|e| panic!("{}", e));
    let mut result = Vec::new();
    create_result_from_pairs(pairs, &mut result);
    println!("{}", serde_json::to_string(&result).unwrap());
}

fn create_result_from_pairs(pairs: iterators::Pairs<grammar::Rule, inputs::StrInput>, result: &mut Vec<Result>) {
    for pair in pairs {
        let rule = format!("{:?}", pair.as_rule());
        let text = String::from(pair.as_str());
        let mut children = Vec::new();
        create_result_from_pairs(pair.into_inner(), &mut children);
        result.push(Result {
            rule,
            text: if children.len() == 0 {
              Some(text)
            } else {
              None
            },
            children,
        });
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::process::exit;
use std::sync::mpsc;
use std::{thread, time};

extern crate clap;
use clap::{Arg, ArgMatches, App, SubCommand};

extern crate glop;
use glop::grammar;
use glop::runtime;

type AppResult<T> = Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    CLI(clap::Error),
    IO(io::Error),
    Parse(glop::grammar::ParseError),
}

impl From<clap::Error> for Error {
    fn from(err: clap::Error) -> Error {
        Error::CLI(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::CLI(ref err) => write!(f, "{}", err),
            Error::IO(ref err) => write!(f, "{}", err),
            Error::Parse(ref err) => write!(f, "{}", err),
        }
    }
}

impl From<glop::grammar::ParseError> for Error {
    fn from(err: glop::grammar::ParseError) -> Error {
        Error::Parse(err)
    }
}

fn main() {
    let app = App::new("glop")
        .version("0")
        .author("Casey Marshall")
        .about("Glue Language for OPerations")
        .subcommand(SubCommand::with_name("agent")
            .about("run the interpreter agent")
            .arg(Arg::with_name("GLOPFILE").index(1).multiple(true).required(true)))
        .subcommand(SubCommand::with_name("set")
            .about("set variable in context")
            .arg(Arg::with_name("KEY").index(1).required(true))
            .arg(Arg::with_name("VALUE").index(2).required(true)))
        .subcommand(SubCommand::with_name("get")
            .about("get value of variable or message content")
            .arg(Arg::with_name("KEY").index(1).required(true)))
        .subcommand(SubCommand::with_name("send")
            .about("send a message")
            .arg(Arg::with_name("recipient").long("recipient").short("r").default_value("self"))
            .arg(Arg::with_name("topic").long("topic").short("t").required(true))
            .arg(Arg::with_name("CONTENTS").index(1).multiple(true).required(false)));
    let app_m = app.get_matches();
    let result = match app_m.subcommand_name() {
        Some("agent") => cmd_agent(app_m.subcommand_matches("agent").unwrap()),
        Some("get") => cmd_get(app_m.subcommand_matches("get").unwrap()),
        Some("set") => cmd_set(app_m.subcommand_matches("set").unwrap()),
        Some("send") => cmd_send(app_m.subcommand_matches("send").unwrap()),
        Some(subcmd) => {
            println!("unsupported command {}", subcmd);
            println!("{}", app_m.usage());
            Err(Error::CLI(clap::Error::with_description("unsupported command",
                                                         clap::ErrorKind::HelpDisplayed)))
        }
        None => {
            println!("{}", app_m.usage());
            Err(Error::CLI(clap::Error::with_description("missing subcommand",
                                                         clap::ErrorKind::HelpDisplayed)))
        }
    };
    match result {
        Ok(_) => exit(0),
        Err(_) => exit(1),
    };
}

fn read_file(path: &str) -> AppResult<String> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    f.read_to_string(&mut s).map_err(Error::IO)?;
    Ok(s)
}

fn cmd_agent<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    let glop_file = app_m.value_of("GLOPFILE").unwrap();
    let glop_contents = try!(read_file(glop_file));
    let glop = grammar::glop(&glop_contents).map_err(Error::Parse)?;
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    let m_excs =
        glop.matches.iter().map(|m_ast| runtime::Match::new_from_ast(&m_ast)).collect::<Vec<_>>();
    let (tx_result, rx_result) = mpsc::channel();
    thread::spawn(move || {
        loop {
            for m_exc in &m_excs {
                match st.eval(&m_exc) {
                    Some(ref mut ctx) => {
                        let result = ctx.apply(&m_exc);
                        tx_result.send(result).unwrap();
                    }
                    None => {}
                }
                thread::sleep(time::Duration::from_millis(200));
            }
        }
    });
    loop {
        match rx_result.recv().unwrap() {
            Ok(_) => println!("Ok"),
            Err(e) => println!("Err {}", e),
        }
    }
}

fn cmd_get<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    println!("TODO: get");
    Ok(())
}

fn cmd_set<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    println!("TODO: set");
    Ok(())
}

fn cmd_send<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    println!("TODO: send");
    Ok(())
}
<commit_msg>Implement get/set script context commands.<commit_after>extern crate clap;
extern crate futures;
extern crate tokio_core;

use std::env;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::{Read, Write};
use std::net;
use std::process::exit;
use std::sync::mpsc;
use std::{thread, time};

use clap::{Arg, ArgMatches, App, SubCommand};
use futures::future::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;

extern crate glop;
use glop::grammar;
use glop::runtime;

type AppResult<T> = Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    AddrParse(net::AddrParseError),
    CLI(clap::Error),
    IO(io::Error),
    Parse(glop::grammar::ParseError),
    Env(env::VarError),
}

impl From<clap::Error> for Error {
    fn from(err: clap::Error) -> Error {
        Error::CLI(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::IO(err)
    }
}

impl From<net::AddrParseError> for Error {
    fn from(err: net::AddrParseError) -> Error {
        Error::AddrParse(err)
    }
}

impl From<env::VarError> for Error {
    fn from(err: env::VarError) -> Error {
        Error::Env(err)
    }
}

impl From<glop::grammar::ParseError> for Error {
    fn from(err: glop::grammar::ParseError) -> Error {
        Error::Parse(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::AddrParse(ref err) => write!(f, "{}", err),
            Error::CLI(ref err) => write!(f, "{}", err),
            Error::Env(ref err) => write!(f, "{}", err),
            Error::IO(ref err) => write!(f, "{}", err),
            Error::Parse(ref err) => write!(f, "{}", err),
        }
    }
}

fn main() {
    let app = App::new("glop")
        .version("0")
        .author("Casey Marshall")
        .about("Glue Language for OPerations")
        .subcommand(SubCommand::with_name("agent")
            .about("run the interpreter agent")
            .arg(Arg::with_name("GLOPFILE").index(1).multiple(true).required(true)))
        .subcommand(SubCommand::with_name("set")
            .about("set variable in context")
            .arg(Arg::with_name("KEY").index(1).required(true))
            .arg(Arg::with_name("VALUE").index(2).required(true)))
        .subcommand(SubCommand::with_name("get")
            .about("get value of variable or message content")
            .arg(Arg::with_name("KEY").index(1).required(true)))
        .subcommand(SubCommand::with_name("send")
            .about("send a message")
            .arg(Arg::with_name("recipient").long("recipient").short("r").default_value("self"))
            .arg(Arg::with_name("topic").long("topic").short("t").required(true))
            .arg(Arg::with_name("CONTENTS").index(1).multiple(true).required(false)));
    let app_m = app.get_matches();
    let result = match app_m.subcommand_name() {
        Some("agent") => cmd_agent(app_m.subcommand_matches("agent").unwrap()),
        Some("get") => cmd_get(app_m.subcommand_matches("get").unwrap()),
        Some("set") => cmd_set(app_m.subcommand_matches("set").unwrap()),
        Some(subcmd) => {
            println!("unsupported command {}", subcmd);
            println!("{}", app_m.usage());
            Err(Error::CLI(clap::Error::with_description("unsupported command",
                                                         clap::ErrorKind::HelpDisplayed)))
        }
        None => {
            println!("{}", app_m.usage());
            Err(Error::CLI(clap::Error::with_description("missing subcommand",
                                                         clap::ErrorKind::HelpDisplayed)))
        }
    };
    match result {
        Ok(_) => exit(0),
        Err(_) => exit(1),
    };
}

fn read_file(path: &str) -> AppResult<String> {
    let mut f = try!(File::open(path));
    let mut s = String::new();
    f.read_to_string(&mut s).map_err(Error::IO)?;
    Ok(s)
}

fn cmd_agent<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    let glop_file = app_m.value_of("GLOPFILE").unwrap();
    let glop_contents = try!(read_file(glop_file));
    let glop = grammar::glop(&glop_contents).map_err(Error::Parse)?;
    let mut st = runtime::State::new();
    st.push_msg("init", runtime::Msg::new());
    let m_excs =
        glop.matches.iter().map(|m_ast| runtime::Match::new_from_ast(&m_ast)).collect::<Vec<_>>();
    let (tx_result, rx_result) = mpsc::channel();
    thread::spawn(move || {
        loop {
            for m_exc in &m_excs {
                match st.eval(&m_exc) {
                    Some(ref mut ctx) => {
                        let result = ctx.apply(&m_exc);
                        tx_result.send(result).unwrap();
                    }
                    None => {}
                }
                thread::sleep(time::Duration::from_millis(200));
            }
        }
    });
    loop {
        match rx_result.recv().unwrap() {
            Ok(_) => println!("Ok"),
            Err(e) => println!("Err {}", e),
        }
    }
}

fn cmd_get<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    let addr_str = env::var("ADDR").map_err(Error::Env)?;
    let addr = addr_str.parse().map_err(Error::AddrParse)?;
    let cmd = format!("get {}", app_m.value_of("KEY").unwrap());
    let mut core = Core::new()?;
    let handle = core.handle();
    let socket = TcpStream::connect(&addr, &handle);
    let request = socket.and_then(|mut sock| {
        sock.write_all(cmd.as_bytes())?;
        Ok(sock)
    });
    let response = request.and_then(|mut sock| {
        let mut s = String::new();
        sock.read_to_string(&mut s)?;
        Ok(s)
    });
    let value = match core.run(response) {
        Ok(data) => {
            let mut values = data.split(" -> ");
            match values.nth(1) {
                Some(v) => v.to_string(),
                None => {
                    return Err(Error::IO(io::Error::new(io::ErrorKind::Other,
                                                        "get: malformed response")));
                }
            }
        }
        Err(e) => {
            return Err(Error::IO(e));
        }
    };
    println!("{}", value);
    Ok(())
}

fn cmd_set<'a>(app_m: &ArgMatches<'a>) -> AppResult<()> {
    let addr_str = env::var("ADDR").map_err(Error::Env)?;
    let addr = addr_str.parse().map_err(Error::AddrParse)?;
    let cmd = format!("set {} {}",
                      app_m.value_of("KEY").unwrap(),
                      app_m.value_of("VALUE").unwrap());
    let mut core = Core::new()?;
    let handle = core.handle();
    let socket = TcpStream::connect(&addr, &handle);
    let request = socket.and_then(|mut sock| {
        sock.write_all(cmd.as_bytes())?;
        Ok(sock)
    });
    let response = request.and_then(|mut sock| {
        let mut s = String::new();
        sock.read_to_string(&mut s)?;
        Ok(s)
    });
    match core.run(response) {
        Ok(_) => Ok(()),
        Err(e) => {
            return Err(Error::IO(e));
        }
    }
}
<|endoftext|>