<commit_before>// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  // let sr = SerialResponse::Response {
  //     data: "HEY YOU".to_string(),
  //     base64: None,
  // };
  // info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = format!(include_str!("websockets.html"), ws_port = ws_port);

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<SerialRequest>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).
                  expect(&format!("Failed to create http server on port {}",port));
                  http_server
                    .handle(http_handler)
                    .expect(&"Failed to listen");
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).
  expect(&format!("Failed bind on websocket port {}",ws_port));

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

fn spawn_ws_handler(sub_tx_clone: Sender<SubscriptionRequest>,
                    sreq_tx_clone: Sender<SerialRequest>,
                    connection: WsUpgrade<TcpStream>) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection));
}

fn ws_handler(sub_tx: &Sender<SubscriptionRequest>,
              sreq_tx: &Sender<SerialRequest>,
              connection: WsUpgrade<TcpStream>) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(SubscriptionRequest {
            sub_id: sub_id.clone(),
            subscriber: sub_resp_tx,
          })
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  // TODO Check thread cleanup
  // The new WS Client thread msg loop
  let mut exit = false;

  let sleep_dur = Duration::from_millis(33);

  while !exit {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            info!("{}: Client {} disconnected", sub_id, ip);
            exit = true;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send(req) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            // Weird, but message sending dose work
            // Do I misunderstand unwrap_or?
            sender
              .send_message(&reply)
              .unwrap_or(info!("{}: Could not send message '{}' to client '{}'",
                               sub_id,
                               json,
                               ip));
          }
          Err(e) => {}
        }
      }
      _ => { /*Logging*/ }
    };
    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!",sub_id);

  fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
    let error = e::to_serial_response_error(error);
    serde_json::to_string(&error)
      .map_err(|err| e::ErrorKind::Json(err))
      .map(|json| Message::text(json))
      .map(|msg| {
             sender
               .send_message::<Message, _>(&msg)
               .map_err::<e::Error,_>(|err| {e::ErrorKind::SendWsMessage(err).into()})
           })
      .unwrap_or_else(|_|{warn!(
        "{}: Problem sending bad json error response", sub_id);
        Ok(())
      }).is_ok(); // This shouldn't be needed?

  }

}
<commit_msg>Formatting tweaks<commit_after>// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  // let sr = SerialResponse::Response {
  //     data: "HEY YOU".to_string(),
  //     base64: None,
  // };
  // info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = format!(include_str!("websockets.html"), ws_port = ws_port);

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<SerialRequest>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(move || {
                  let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).
                  expect(&format!("Failed to create http server on port {}",port));
                  http_server
                    .handle(http_handler)
                    .expect(&"Failed to listen");
                });

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).
  expect(&format!("Failed bind on websocket port {}",ws_port));

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

fn spawn_ws_handler(sub_tx_clone: Sender<SubscriptionRequest>,
                    sreq_tx_clone: Sender<SerialRequest>,
                    connection: WsUpgrade<TcpStream>) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection));
}

fn ws_handler(sub_tx: &Sender<SubscriptionRequest>,
              sreq_tx: &Sender<SerialRequest>,
              connection: WsUpgrade<TcpStream>) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(SubscriptionRequest {
            sub_id: sub_id.clone(),
            subscriber: sub_resp_tx,
          })
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  // TODO Check thread cleanup
  // The new WS Client thread msg loop
  let mut exit = false;

  let sleep_dur = Duration::from_millis(33);

  while !exit {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            info!("{}: Client {} disconnected", sub_id, ip);
            exit = true;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send(req) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            // Weird, but message sending dose work
            // Do I misunderstand unwrap_or?
            sender
              .send_message(&reply)
              .unwrap_or(info!("{}: Could not send message '{}' to client '{}'",
                               sub_id,
                               json,
                               ip));
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };
    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!", sub_id);

  fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
    let error = e::to_serial_response_error(error);
    serde_json::to_string(&error)
      .map_err(|err| e::ErrorKind::Json(err))
      .map(|json| Message::text(json))
      .map(|msg| {
             sender
               .send_message::<Message, _>(&msg)
               .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
           })
      .unwrap_or_else(|_| {
                        warn!("{}: Problem sending bad json error response", sub_id);
                        Ok(())
                      })
      .is_ok(); // This shouldn't be needed?

  }

}
<|endoftext|>


<commit_before>#![feature(duration_span, drain)]

extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;
extern crate num_cpus;
extern crate scoped_threadpool;
extern crate tray_rust;

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

use rand::StdRng;
use docopt::Docopt;

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

static USAGE: &'static str = "
Usage: tray_rust <scenefile> [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 {
    arg_scenefile: String,
    flag_o: Option<String>,
    flag_n: Option<u32>,
}

/// 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<ImageSample>>, spp: usize, queue: &sampler::BlockQueue,
               scene: &scene::Scene, target: &film::RenderTarget, light_list: &Vec<&Emitter>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), spp);
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut time_samples: Vec<_> = iter::repeat(0.0).take(sampler.max_spp()).collect();
    let block_dim = queue.block_dim();
    let mut block_samples = Vec::with_capacity(sampler.max_spp() * (block_dim.0 * block_dim.1) as usize);
    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);
            sampler.get_samples_1d(&mut time_samples[..], &mut rng);
            let mut samples = Vec::with_capacity(sampler.max_spp());
            for (s, t) in sample_pos.iter().zip(time_samples.iter()) {
                let mut ray = scene.camera.generate_ray(s, *t);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(scene, light_list, &ray,
                                                          &hit, &mut sampler, &mut rng).clamp();
                    samples.push(ImageSample::new(s.0, s.1, c));
                    block_samples.push(ImageSample::new(s.0, s.1, c));
                }
            }
            if let Err(e) = tx.send(samples) {
                println!("Worker thread exiting with send error {:?}", e);
                return;
            }
        }
        target.write_block(&block_samples, sampler.get_region());
        block_samples.clear();
    }
}

/// Render the scene in parallel using `n` threads and write the result to the render target
fn render_parallel(rt: &mut film::RenderTarget, scene: &scene::Scene, n: u32, spp: usize){
    let mut pool = scoped_threadpool::Pool::new(n);
    println!("Rendering using {} threads", n);
    pool.scoped(|scope| {
        let dim = rt.dimensions();
        let block_queue = sampler::BlockQueue::new((dim.0 as u32, dim.1 as u32), (8, 8));
        let light_list: Vec<_> = scene.bvh.into_iter().filter_map(|x| {
            match x {
                &Instance::Emitter(ref e) => Some(e),
                _ => None,
            }
        }).collect();
        assert!(!light_list.is_empty(), "At least one light is required");

        let rx = {
            let (tx, rx) = mpsc::channel();
            for _ in 0..n {
                let t = tx.clone();
                let b = &block_queue;
                let r = &*rt;
                let l = &light_list;
                scope.execute(move || {
                    thread_work(t, spp, b, scene, r, l);
                });
            }
            rx
        };

        for mut v in rx.iter() {
            for s in v.drain(..) {
                rt.write(s.x, s.y, &s.color);
            }
        }
    });
}

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

    let (mut scene, spp, (width, height)) = scene::Scene::load_file(&args.arg_scenefile[..]);
    let mut rt = film::RenderTarget::new(width, height,
                    Box::new(filter::MitchellNetravali::new(2.0, 2.0, 1.0 / 3.0, 1.0 / 3.0))
                    as Box<filter::Filter + Send + Sync>);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get() as u32,
    };

    // Render 5 frames. TODO: This should be read from scene file
    let scene_time = 0.0;
    let frames = 1;
    let time_step = scene_time / (frames as f32);
    for i in 0..frames {
        scene.camera.update_shutter(i as f32 * time_step, (i as f32 + 1.0) * time_step);
        let d = Duration::span(|| render_parallel(&mut rt, &scene, n, spp));
        let time = d.as_secs() as f64 + (d.subsec_nanos() as f64) / 1_000_000_000.0;
        println!("Rendering took {}s", time);

        let img = rt.get_render();
        let out_file = match &args.flag_o {
            &Some(ref f) => f.to_string(),
            &None => format!("out_frame{:03}.png", i).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),
        };
        let img = rt.get_block_render();
        match image::save_buffer(&Path::new("block_out.png"), &img[..], width as u32, height as u32, image::RGB(8)) {
            Ok(_) => {},
            Err(e) => println!("Error saving image, {}", e),
        };
        rt.clear();
    }
}

<commit_msg>Remove mpsc usage from block locking branch<commit_after>#![feature(duration_span)]

extern crate image;
extern crate rand;
extern crate docopt;
extern crate rustc_serialize;
extern crate num_cpus;
extern crate scoped_threadpool;
extern crate tray_rust;

use std::vec::Vec;
use std::iter;
use std::path::Path;
use std::time::Duration;

use rand::StdRng;
use docopt::Docopt;

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

static USAGE: &'static str = "
Usage: tray_rust <scenefile> [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 {
    arg_scenefile: String,
    flag_o: Option<String>,
    flag_n: Option<u32>,
}

/// 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(spp: usize, queue: &sampler::BlockQueue, scene: &scene::Scene,
               target: &film::RenderTarget, light_list: &Vec<&Emitter>) {
    let mut sampler = sampler::LowDiscrepancy::new(queue.block_dim(), spp);
    let mut sample_pos = Vec::with_capacity(sampler.max_spp());
    let mut time_samples: Vec<_> = iter::repeat(0.0).take(sampler.max_spp()).collect();
    let block_dim = queue.block_dim();
    let mut block_samples = Vec::with_capacity(sampler.max_spp() * (block_dim.0 * block_dim.1) as usize);
    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);
            sampler.get_samples_1d(&mut time_samples[..], &mut rng);
            for (s, t) in sample_pos.iter().zip(time_samples.iter()) {
                let mut ray = scene.camera.generate_ray(s, *t);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(scene, light_list, &ray,
                                                          &hit, &mut sampler, &mut rng).clamp();
                    block_samples.push(ImageSample::new(s.0, s.1, c));
                }
            }
        }
        target.write_block(&block_samples, sampler.get_region());
        block_samples.clear();
    }
}

/// Render the scene in parallel using `n` threads and write the result to the render target
fn render_parallel(rt: &mut film::RenderTarget, scene: &scene::Scene, n: u32, spp: usize){
    let mut pool = scoped_threadpool::Pool::new(n);
    println!("Rendering using {} threads", n);
    pool.scoped(|scope| {
        let dim = rt.dimensions();
        let block_queue = sampler::BlockQueue::new((dim.0 as u32, dim.1 as u32), (8, 8));
        let light_list: Vec<_> = scene.bvh.into_iter().filter_map(|x| {
            match x {
                &Instance::Emitter(ref e) => Some(e),
                _ => None,
            }
        }).collect();
        assert!(!light_list.is_empty(), "At least one light is required");

        for _ in 0..n {
            let b = &block_queue;
            let r = &*rt;
            let l = &light_list;
            scope.execute(move || {
                thread_work(spp, b, scene, r, l);
            });
        }
    });
}

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

    let (mut scene, spp, (width, height)) = scene::Scene::load_file(&args.arg_scenefile[..]);
    let mut rt = film::RenderTarget::new(width, height,
                    Box::new(filter::MitchellNetravali::new(2.0, 2.0, 1.0 / 3.0, 1.0 / 3.0))
                    as Box<filter::Filter + Send + Sync>);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get() as u32,
    };

    // Render 5 frames. TODO: This should be read from scene file
    let scene_time = 0.0;
    let frames = 1;
    let time_step = scene_time / (frames as f32);
    for i in 0..frames {
        scene.camera.update_shutter(i as f32 * time_step, (i as f32 + 1.0) * time_step);
        let d = Duration::span(|| render_parallel(&mut rt, &scene, n, spp));
        let time = d.as_secs() as f64 + (d.subsec_nanos() as f64) / 1_000_000_000.0;
        println!("Rendering took {}s", time);

        let img = rt.get_render();
        let out_file = match &args.flag_o {
            &Some(ref f) => f.to_string(),
            &None => format!("out_frame{:03}.png", i).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),
        };
        let img = rt.get_block_render();
        match image::save_buffer(&Path::new("block_out.png"), &img[..], width as u32, height as u32, image::RGB(8)) {
            Ok(_) => {},
            Err(e) => println!("Error saving image, {}", e),
        };
        rt.clear();
    }
}

<|endoftext|>


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

use std::{env, fs};
use std::fs::File;

fn loop_over_files(path: &str, saver: &File) {
    match fs::read_dir(path) {
        Ok(it) => {
            for entry in it {
                check_path_type(entry.path().to_str().unwrap(), saver);
            }
        }
        Err(e) => {
            println!("Error while trying to iterate over {}: {}", path, e);
        }
    }
}

fn strip_comments(path: &str, saver: &File) {
    match File::open(path) {
        Ok(f) => {
            let mut reader = BufReader::new(f);
            let mut line = String::new();

        }
        Err(e) => {
            println!("Unable to open \"{}\": {}", path, e);
        }
    }
}

fn check_path_type(path: &str, saver: &File) {
    match fs::metadata(path) {
        Ok(m) => {
            if m.is_dir() {
                loop_over_files(path, saver);
            } else {
                strip_comments(path, saver);
            }
        }
        Err(e) => {
            println!("An error occurred: {}", e);
        }
    }
}

fn main() {
    for arg in env::args() {

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

use std::{env, fs};
use std::fs::{File, OpenOptions};
use std::io::BufReader;

struct CommentEntry {
    line: String,
    file: String,
    comment_lines: Vec<String>,
}

impl CommentEntry {
    pub fn new(file: &str) -> CommentEntry {
        CommentEntry {
            line: String::new(),
	    file: file.into_owned(),
	    comment_lines: Vec::new(),
        }
    }
}

impl Display for CommentEntry {
    fn display(&self, f: &mut Formatter) -> io::Result<> {
        write!(f, "=|={}", self.line);
        writeln!(f, "=!={}", self.file);
	for comment in self.comment_lines {
             write!(f, "{}", comment);
        }
    }
}

fn loop_over_files(path: &str, comments: &mut Vec<CommentEntry>) {
    match fs::read_dir(path) {
        Ok(it) => {
            for entry in it {
                check_path_type(entry.path().to_str().unwrap(), comments);
            }
        }
        Err(e) => {
            println!("Error while trying to iterate over {}: {}", path, e);
        }
    }
}

fn move_reader(reader: &mut BufReader, first_line: &str, file: &str,
               comments: &mut Vec<CommentEntry>) -> Option<String> {
    let mut cm = CommentEntry::new(file);
    let mut current = String::new();

    cm.comment_lines.push(first_line.to_owned());
    loop {
        if reader.read_line(&mut current).unwrap() < 1 {
            // error
	    return None;
        }
	if current.trim_left().starts_with("///") {
            cm.comment_lines.push(current.clone());
        } else {
            break;
        }
    }
    cm.line = current.clone();
    comments.push(cm);
    Some(current)
}

fn strip_comments(path: &str, comments: &mut Vec<CommentEntry>) {
    match FileOptions::new().read(true).write(true).open(path) {
        Ok(f) => {
            let mut reader = BufReader::new(f);
            let mut line = String::new();
	    let mut out_lines = vec!();

	    while reader.read_line(&mut buffer).unwrap() > 0 {
                let mut worker = buffer.trim_left().to_owned();

                if worker.starts_with("///") {
                    // "normal" doc comments
                    out_lines.push(move_reader(&mut reader, &line, path, comments).unwrap());
                } else if worker.starts_with("//!")/* || worker.starts_with("/*!")*/ {
                    // module comments
                }
                buffer.clear();
            }
	    f.seek(SeekFrom::Start(0));
            let mut writer = BufWriter::new(f);

	    for line in out_lines {
                write!(writer, "{}", line).unwrap();
            }
        }
        Err(e) => {
            println!("Unable to open \"{}\": {}", path, e);
        }
    }
}

fn check_path_type(path: &str, comments: &mut Vec<CommentEntry>) {
    match fs::metadata(path) {
        Ok(m) => {
            if m.is_dir() {
                loop_over_files(path, comments);
            } else {
                strip_comments(path, comments);
            }
        }
        Err(e) => {
            println!("An error occurred: {}", e);
        }
    }
}

fn main() {
    let mut comments = vec!();

    check_path_type(".", &mut comments);
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_must_use, dead_code)]

extern crate bencode;
extern crate rand;
extern crate bittorrent;
extern crate hyper;

use std::{env, str, thread};
use std::io::{Read, Write};
use std::collections::HashMap;
use std::net::{Ipv4Addr, TcpStream, SocketAddrV4};
use std::sync::mpsc::channel;
use bencode::{deserialize, deserialize_file, Bencode, TypedMethods, BencodeVecOption};
use rand::{Rng, thread_rng};
use bittorrent::querystring::QueryString;
use bittorrent::metadata::{MetadataDict, Metadata};
use bittorrent::bt_messages::{decode_message, test};
use hyper::Client;
use hyper::header::Connection;

const PEER_ID_LENGTH:usize = 20;
const PEER_ID_PREFIX:&'static str = "-TR1000-";

#[derive(Debug)]
enum Address {
    TCP(Ipv4Addr, u16)
}

fn gen_rand_peer_id (prefix: &str) -> String {
    let rand_length = PEER_ID_LENGTH - prefix.len();
    let rand = thread_rng().gen_ascii_chars()
                           .take(rand_length)
                           .collect::<String>();

    prefix.to_string() + &rand
}

fn ping_tracker (announce: &String, args: Vec<(&str, String)>) -> Option<HashMap<String, Bencode>> {
    let req_addr = announce.to_string() + "?" + &QueryString::from(args).query_string();
    println!("pinging tracker {}", req_addr);
    let client = Client::new();
    let mut res = client.get(&req_addr)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = Vec::new();
    res.read_to_end(&mut body).unwrap();

    deserialize(&body).to_singleton_dict()
}

/// Gets peer addresses from a received tracker response. These are just Ipv4 addresses currently
fn get_peers <T> (tracker_response: &T) -> Vec<Address> where T:TypedMethods {
    let peers = tracker_response.get_owned_string("peers").unwrap_or_else(||panic!("no peers found"));
    //for now keep the bottom unused value, it's for ipv6. which maybe will be addressed
    (0..peers.len()/6).map(|x| {
        let ip_start = x * 6;
        let ip_end = ip_start + 4;
        let ip_bytes = &peers[ip_start..ip_end];
        let ip = Ipv4Addr::new(ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]);
        let port = (peers[ip_end] as u16)*256 + peers[ip_end+1] as u16;
        Address::TCP(ip, port)
    }).collect::<Vec<Address>>()
}

/// The peer handshake message, according to protocol
///
fn to_handshake (pstr:&str, info_hash: &[u8; 20], peer_id: &String) -> Vec<u8> {
    let reserved = [0u8; 8];
    let pstr_bytes = pstr.to_string().into_bytes();
    let a = [pstr_bytes.len() as u8];
    let b = pstr_bytes;
    let c = reserved;
    let d = info_hash;
    let e = peer_id.clone().into_bytes();

    [a.iter(),
     b.iter(),
     c.iter(),
     d.iter(),
     e.iter()].iter().flat_map(|y| {
         y.to_owned().map(|x| *x).collect::<Vec<u8>>()
     }).collect::<Vec<u8>>()
}

fn decode_handshake(resp: &[u8]) -> (&[u8], &[u8], &[u8], &[u8]){
    //i realize this is the goofiest looking block ever... but you cant really destructure a
    //vector so i'm sticking with the tuples for now. maybe i'll make it look normal later
    let (pstrlen, a0) = {
        let (l, r) = resp.split_at(1 as usize);
        (l[0], r)
    };
    let (protocol, a1) = a0.split_at(pstrlen as usize);
    let (reserved, a2) = a1.split_at(8);
    let (info_hash, a3) = a2.split_at(20);
    let (peer_id, _) = a3.split_at(20);

    (protocol, reserved, info_hash, peer_id)
}

fn connect_to_peer (address: Address, metadata: &Metadata, peer_id: &String) -> Result<Vec<u8>, String> {
    println!("connecting to {:?}", address);
    let (ip, port) = match address {
        Address::TCP(ip_address, port) => (ip_address, port)
    };

    let mut stream = match TcpStream::connect(SocketAddrV4::new(ip, port)) {
        Ok(tcp_stream) => tcp_stream,
        Err(err) => return Err(format!("unable to connect to peer {:?}", ip))
    };

    println!("connected to {:?}", address);

    let _ = stream.write_all(&to_handshake("BitTorrent protocol", &metadata.info_hash, peer_id));
    let _ = stream.flush();

    //for now enforce a maximum handshake size of 512 bytes
    let mut buffer = [0; 512];
    match stream.read(&mut buffer) {
        Ok(0) => Err(format!("invalid handshake from peer")),
        Ok(bytes_read) => {
            let something = &buffer[0..bytes_read];
            let (protocol, reserved, info_hash, peer_id) = decode_handshake(&buffer[0..bytes_read]);
            let info_hash = metadata.info_hash;
            match (protocol, info_hash) {
                (b"BitTorrent protocol", info_hash) => Ok(peer_id.to_owned()),
                _ => Err(format!("invalid peer handshake"))
            }
        },
        Err(err) => Err(format!("unable to read from peer {:?}", ip))
    }
}

fn get_http_tracker_peers (peer_id: &String, metadata: &Metadata, listen_port:u32, bytes_dled: u32) -> Option<Vec<Address>> {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let bytes_left = metadata.get_total_length() - bytes_dled;

    let info_hash_escaped = QueryString::encode_component(&metadata.info_hash);
    let response = ping_tracker(&metadata.announce, vec![
                                ("info_hash", info_hash_escaped),
                                ("peer_id", peer_id.clone()),
                                ("port", listen_port.to_string()),
                                ("uploaded", 0.to_string()),
                                ("downloaded", bytes_dled.to_string()),
                                ("left", bytes_left.to_string()),
                                ("compact", 1.to_string()),
                                ("event", "started".to_string()),
                                ("num_want", "15".to_string())
                                ]);

    match response {
        Some(resp) => Some(get_peers(&resp)),
        None => panic!("no valid bencode response from tracker")
    }
}

fn init (metadata: &Metadata, listen_port: u32, bytes_dled: u32) {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let peers = match get_http_tracker_peers(&peer_id, metadata, listen_port, bytes_dled) {
        Some(peers) => peers,
        _ => panic!("cannot get peers from tracker")
    };

    println!("got {} peers", peers.len());

    let (tx, rx) = channel();

    //TODO: the sink initialization should be done outside of init() as one sink can realistically
    //handle multiple torrents relatively trivially
    //all threads will send messages asynchronously to the sink. tbh the loop could be shoved onto the main
    //thread, but for the sake of modularity lets dedicated one for the sink
    let sink = thread::spawn(move || {
        loop {
            let res = rx.recv().unwrap();
            println!("{:?}", res);
        }
    });

    for peer in peers {
        let child_meta = metadata.clone();
        let peer_id = peer_id.clone();
        let tx = tx.clone();
        thread::spawn(move || {
            let conn = connect_to_peer(peer, &child_meta, &peer_id).unwrap();
            tx.send(conn);
        });
    }

    //block until the sink shuts down
    let _ = sink.join();
}

fn start_torrenting () {
    let path = env::args().nth(1)
                          .unwrap_or_else(||panic!("no path to torrent provided"));

    let content = deserialize_file(path).unwrap_or_else(||panic!("unable to parse bencoded metadata"));

    assert_eq!(content.len(), 1);

    let metadata = match content.first() {
        Some(&Bencode::Dict(ref dict)) => dict.to_metadata(),
        _ => panic!("no valid information in torrent file")
    }.unwrap();

    init(&metadata, 6887, 0);
}

fn main () {
    start_torrenting();
    //test();
}
<commit_msg>need a match guard in connect_peer<commit_after>//#![allow(unused_imports, unused_must_use, dead_code)]

extern crate bencode;
extern crate rand;
extern crate bittorrent;
extern crate hyper;

use std::{env, thread};
use std::io::{Read, Write};
use std::collections::HashMap;
use std::net::{Ipv4Addr, TcpStream, SocketAddrV4};
use std::sync::mpsc::channel;
use bencode::{deserialize, deserialize_file, Bencode, TypedMethods, BencodeVecOption};
use rand::{Rng, thread_rng};
use bittorrent::querystring::QueryString;
use bittorrent::metadata::{MetadataDict, Metadata};
use bittorrent::bt_messages::{decode_message, test};
use hyper::Client;
use hyper::header::Connection;

const PEER_ID_LENGTH:usize = 20;
const PEER_ID_PREFIX:&'static str = "-TR1000-";

#[derive(Debug)]
enum Address {
    TCP(Ipv4Addr, u16)
}

fn gen_rand_peer_id (prefix: &str) -> String {
    let rand_length = PEER_ID_LENGTH - prefix.len();
    let rand = thread_rng().gen_ascii_chars()
                           .take(rand_length)
                           .collect::<String>();

    prefix.to_string() + &rand
}

fn ping_tracker (announce: &String, args: Vec<(&str, String)>) -> Option<HashMap<String, Bencode>> {
    let req_addr = announce.to_string() + "?" + &QueryString::from(args).query_string();
    println!("pinging tracker {}", req_addr);
    let client = Client::new();
    let mut res = client.get(&req_addr)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = Vec::new();
    res.read_to_end(&mut body).unwrap();

    deserialize(&body).to_singleton_dict()
}

/// Gets peer addresses from a received tracker response. These are just Ipv4 addresses currently
fn get_peers <T> (tracker_response: &T) -> Vec<Address> where T:TypedMethods {
    let peers = tracker_response.get_owned_string("peers").unwrap_or_else(||panic!("no peers found"));
    //for now keep the bottom unused value, it's for ipv6. which maybe will be addressed
    (0..peers.len()/6).map(|x| {
        let ip_start = x * 6;
        let ip_end = ip_start + 4;
        let ip_bytes = &peers[ip_start..ip_end];
        let ip = Ipv4Addr::new(ip_bytes[0], ip_bytes[1], ip_bytes[2], ip_bytes[3]);
        let port = (peers[ip_end] as u16)*256 + peers[ip_end+1] as u16;
        Address::TCP(ip, port)
    }).collect::<Vec<Address>>()
}

/// The peer handshake message, according to protocol
///
fn to_handshake (pstr:&str, info_hash: &[u8; 20], peer_id: &String) -> Vec<u8> {
    let reserved = [0u8; 8];
    let pstr_bytes = pstr.to_string().into_bytes();
    let a = [pstr_bytes.len() as u8];
    let b = pstr_bytes;
    let c = reserved;
    let d = info_hash;
    let e = peer_id.clone().into_bytes();

    [a.iter(),
     b.iter(),
     c.iter(),
     d.iter(),
     e.iter()].iter().flat_map(|y| {
         y.to_owned().map(|x| *x).collect::<Vec<u8>>()
     }).collect::<Vec<u8>>()
}

fn decode_handshake(resp: &[u8]) -> (&[u8], &[u8], &[u8], &[u8]){
    //i realize this is the goofiest looking block ever... but you cant really destructure a
    //vector so i'm sticking with the tuples for now. maybe i'll make it look normal later
    let (pstrlen, a0) = {
        let (l, r) = resp.split_at(1 as usize);
        (l[0], r)
    };
    let (protocol, a1) = a0.split_at(pstrlen as usize);
    let (reserved, a2) = a1.split_at(8);
    let (info_hash, a3) = a2.split_at(20);
    let (peer_id, _) = a3.split_at(20);

    (protocol, reserved, info_hash, peer_id)
}

fn connect_to_peer (address: Address, metadata: &Metadata, peer_id: &String) -> Result<Vec<u8>, String> {
    println!("connecting to {:?}", address);
    let (ip, port) = match address {
        Address::TCP(ip_address, port) => (ip_address, port)
    };

    let mut stream = match TcpStream::connect(SocketAddrV4::new(ip, port)) {
        Ok(tcp_stream) => tcp_stream,
        Err(_) => return Err(format!("unable to connect to peer {:?}", ip))
    };

    println!("connected to {:?}", address);

    let _ = stream.write_all(&to_handshake("BitTorrent protocol", &metadata.info_hash, peer_id));
    let _ = stream.flush();

    //for now enforce a maximum handshake size of 512 bytes
    let mut buffer = [0; 512];
    match stream.read(&mut buffer) {
        Ok(0) => Err(format!("invalid handshake from peer")),
        Ok(bytes_read) => {
            let (protocol, _, info_hash, peer_id) = decode_handshake(&buffer[0..bytes_read]);
            match (protocol, info_hash) {
                (b"BitTorrent protocol", i_h) if i_h == metadata.info_hash => Ok(peer_id.to_owned()),
                _ => Err(format!("invalid peer handshake"))
            }
        },
        Err(err) => Err(format!("unable to read from peer {:?}", ip))
    }
}

fn get_http_tracker_peers (peer_id: &String, metadata: &Metadata, listen_port:u32, bytes_dled: u32) -> Option<Vec<Address>> {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let bytes_left = metadata.get_total_length() - bytes_dled;

    let info_hash_escaped = QueryString::encode_component(&metadata.info_hash);
    let response = ping_tracker(&metadata.announce, vec![
                                ("info_hash", info_hash_escaped),
                                ("peer_id", peer_id.clone()),
                                ("port", listen_port.to_string()),
                                ("uploaded", 0.to_string()),
                                ("downloaded", bytes_dled.to_string()),
                                ("left", bytes_left.to_string()),
                                ("compact", 1.to_string()),
                                ("event", "started".to_string()),
                                ("num_want", "15".to_string())
                                ]);

    match response {
        Some(resp) => Some(get_peers(&resp)),
        None => panic!("no valid bencode response from tracker")
    }
}

fn init (metadata: &Metadata, listen_port: u32, bytes_dled: u32) {
    let peer_id = gen_rand_peer_id(PEER_ID_PREFIX);
    let peers = match get_http_tracker_peers(&peer_id, metadata, listen_port, bytes_dled) {
        Some(peers) => peers,
        _ => panic!("cannot get peers from tracker")
    };

    println!("got {} peers", peers.len());

    let (tx, rx) = channel();

    //TODO: the sink initialization should be done outside of init() as one sink can realistically
    //handle multiple torrents relatively trivially
    //all threads will send messages asynchronously to the sink. tbh the loop could be shoved onto the main
    //thread, but for the sake of modularity lets dedicated one for the sink
    let sink = thread::spawn(move || {
        loop {
            let res = rx.recv().unwrap();
            println!("{:?}", res);
        }
    });

    for peer in peers {
        let child_meta = metadata.clone();
        let peer_id = peer_id.clone();
        let tx = tx.clone();
        thread::spawn(move || {
            let conn = connect_to_peer(peer, &child_meta, &peer_id).unwrap();
            tx.send(conn);
        });
    }

    //block until the sink shuts down
    let _ = sink.join();
}

fn start_torrenting () {
    let path = env::args().nth(1)
                          .unwrap_or_else(||panic!("no path to torrent provided"));

    let content = deserialize_file(path).unwrap_or_else(||panic!("unable to parse bencoded metadata"));

    assert_eq!(content.len(), 1);

    let metadata = match content.first() {
        Some(&Bencode::Dict(ref dict)) => dict.to_metadata(),
        _ => panic!("no valid information in torrent file")
    }.unwrap();

    init(&metadata, 6887, 0);
}

fn main () {
    start_torrenting();
    //test();
}
<|endoftext|>


<commit_before>#[derive(Debug)]
enum Expr {
    Numeral(i64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Divide(Box<Expr>, Box<Expr>),
    Negate(Box<Expr>),
}

fn main() {
    let n1: Expr = Expr::Numeral(5);
    println!("{:?}", n1);
}
<commit_msg>Impl fmt::Display for Expr<commit_after>use std::fmt;

#[derive(Debug)]
enum Expr {
    Numeral(i64),
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Divide(Box<Expr>, Box<Expr>),
    Negate(Box<Expr>),
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Numeral(i) => write!(f, "{}", i),
            &Expr::Plus(ref i, ref j) => write!(f, "{} + {}", i, j),
            &Expr::Minus(ref i, ref j) => write!(f, "{} - {}", i, j),
            &Expr::Times(ref i, ref j) => write!(f, "{} * {}", i, j),
            &Expr::Divide(ref i, ref j) => write!(f, "{} / {}", i, j),
            &Expr::Negate(ref i) => write!(f, "-{}", i),
        }
    }
}

fn main() {
    let n1: Expr = Expr::Numeral(5);
    let p: Expr = Expr::Plus(Box::new(Expr::Numeral(5)), Box::new(Expr::Numeral(7)));
    let m: Expr = Expr::Minus(Box::new(Expr::Numeral(5)), Box::new(Expr::Numeral(7)));
    let t: Expr = Expr::Times(Box::new(Expr::Numeral(5)), Box::new(Expr::Numeral(7)));
    let d: Expr = Expr::Divide(Box::new(Expr::Numeral(5)), Box::new(Expr::Numeral(7)));
    let n: Expr = Expr::Negate(Box::new(Expr::Numeral(5)));
    println!("{}", n1);
    println!("{}", p);
    println!("{}", m);
    println!("{}", t);
    println!("{}", d);
    println!("{}", n);
}
<|endoftext|>


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

pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;

extern crate glutin;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,
    mouse_pos: (i32, i32),
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    })
        .unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let mut window = glutin::WindowBuilder::new()
                         .with_title("Steven".to_string())
                         .with_dimensions(854, 480)
                         .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                         .with_gl_profile(glutin::GlProfile::Core)
                         .with_depth_buffer(24)
                         .with_stencil_buffer(0)
                         .with_vsync()
                         .build()
                         .expect("Could not create Glutin window.");

    unsafe {
        window.make_current().expect("Could not set current context.");
    }

    gl::init(&mut window);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new()));

    let mut game = Game {
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager,
        console: con,
        should_close: false,
        mouse_pos: (0, 0),
    };

    while !game.should_close {
        {
            game.resource_manager.write().unwrap().tick();
        }

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.get_inner_size_pixels().unwrap();

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(delta, width, height);

        let _ = window.swap_buffers();

        for event in window.poll_events() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &glutin::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: glutin::Event) {
    use glutin::{Event, VirtualKeyCode};
    match event {
        Event::Closed => game.should_close = true,

        Event::MouseMoved((x, y)) => {
            game.mouse_pos = (x, y);
            let (width, height) = window.get_inner_size_pixels().unwrap();

            ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
        }

        Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
            let (x, y) = game.mouse_pos;
            let (width, height) = window.get_inner_size_pixels().unwrap();

            ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
        }

        Event::MouseWheel(delta) => {
            let (x, y) = match delta {
                glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
                glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y),
            };

            game.screen_sys.on_scroll(x as f64, y as f64);
        }

        Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _)
            | Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
            println!("Key: {:?} {:?}", key, virt);
        }

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

pub mod protocol;
pub mod format;
pub mod nbt;
pub mod item;
pub mod gl;
pub mod types;
pub mod resources;
pub mod render;
pub mod ui;
pub mod screen;
#[macro_use]
pub mod console;

extern crate glutin;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;

use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;

const CL_BRAND: console::CVar<String> = console::CVar {
    ty: PhantomData,
    name: "cl_brand",
    description: "cl_brand has the value of the clients current 'brand'. e.g. \"Steven\" or \
                  \"Vanilla\"",
    mutable: false,
    serializable: false,
    default: &|| "Steven".to_owned(),
};

pub struct Game {
    renderer: render::Renderer,
    screen_sys: screen::ScreenSystem,
    resource_manager: Arc<RwLock<resources::Manager>>,
    console: Arc<Mutex<console::Console>>,
    should_close: bool,
    mouse_pos: (i32, i32),
}

fn main() {
    let con = Arc::new(Mutex::new(console::Console::new()));
    {
        let mut con = con.lock().unwrap();
        con.register(CL_BRAND);
        con.load_config();
        con.save_config();
    }

    let proxy = console::ConsoleProxy::new(con.clone());

    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::Trace);
        Box::new(proxy)
    })
        .unwrap();

    info!("Starting steven");

    let resource_manager = Arc::new(RwLock::new(resources::Manager::new()));
    {
        resource_manager.write().unwrap().tick();
    }

    let mut window = glutin::WindowBuilder::new()
                         .with_title("Steven".to_string())
                         .with_dimensions(854, 480)
                         .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                         .with_gl_profile(glutin::GlProfile::Core)
                         .with_depth_buffer(24)
                         .with_stencil_buffer(0)
                         .with_vsync()
                         .build()
                         .expect("Could not create Glutin window.");

    unsafe {
        window.make_current().expect("Could not set current context.");
    }

    gl::init(&mut window);

    let renderer = render::Renderer::new(resource_manager.clone());
    let mut ui_container = ui::Container::new();

    let mut last_frame = time::now();
    let frame_time = (time::Duration::seconds(1).num_nanoseconds().unwrap() as f64) / 60.0;

    let mut screen_sys = screen::ScreenSystem::new();
    screen_sys.add_screen(Box::new(screen::Login::new()));

    let mut game = Game {
        renderer: renderer,
        screen_sys: screen_sys,
        resource_manager: resource_manager,
        console: con,
        should_close: false,
        mouse_pos: (0, 0),
    };

    while !game.should_close {
        {
            game.resource_manager.write().unwrap().tick();
        }

        let now = time::now();
        let diff = now - last_frame;
        last_frame = now;
        let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time;
        let (width, height) = window.get_inner_size_pixels().unwrap();

        game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container);
        game.console
            .lock()
            .unwrap()
            .tick(&mut ui_container, &mut game.renderer, delta, width as f64);
        ui_container.tick(&mut game.renderer, delta, width as f64, height as f64);
        game.renderer.tick(delta, width, height);

        let _ = window.swap_buffers();

        for event in window.poll_events() {
            handle_window_event(&window, &mut game, &mut ui_container, event)
        }
    }
}

fn handle_window_event(window: &glutin::Window,
                       game: &mut Game,
                       ui_container: &mut ui::Container,
                       event: glutin::Event) {
    use glutin::{Event, VirtualKeyCode};
    match event {
        Event::Closed => game.should_close = true,

        Event::MouseMoved((x, y)) => {
            game.mouse_pos = (x, y);
            let (width, height) = window.get_inner_size_pixels().unwrap();

            ui_container.hover_at(game, x as f64, y as f64, width as f64, height as f64);
        }

        Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) => {
            let (x, y) = game.mouse_pos;
            let (width, height) = window.get_inner_size_pixels().unwrap();

            ui_container.click_at(game, x as f64, y as f64, width as f64, height as f64);
        }

        Event::MouseWheel(delta) => {
            let (x, y) = match delta {
                glutin::MouseScrollDelta::LineDelta(x, y) => (x, y),
                glutin::MouseScrollDelta::PixelDelta(x, y) => (x, y),
            };

            game.screen_sys.on_scroll(x as f64, y as f64);
        }

        Event::KeyboardInput(glutin::ElementState::Pressed, 41 /* ` GRAVE */, _)
            | Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(VirtualKeyCode::Grave)) => {
            game.console.lock().unwrap().toggle();
        }
        Event::KeyboardInput(glutin::ElementState::Pressed, key, virt) => {
            println!("Key: {:?} {:?}", key, virt);
        }

        _ => (),
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate walkdir;
extern crate twox_hash;

use std::collections::HashMap;
use std::collections::BTreeSet;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::os::linux::fs::MetadataExt;

use clap::{App, Arg, ArgMatches};
use walkdir::WalkDir;
use twox_hash::XxHash;
use std::hash::Hasher;

#[derive(Default)]
struct Stats {
    file_count: u64,
    total_size: u64,
    duplicate_count: u64,
}

fn parse_args<'a>() -> ArgMatches<'a> {
    App::new("dupr")
        .version("0.1.0")
        .author("Mike Sampson")
        .about("Duplicate file finder")
        .arg(
            Arg::with_name("DIR")
                .help("Directory to process")
                .required(true),
        )
        .arg(Arg::with_name("noempty").short("n").long("noempty").help(
            "Exclude zero length files",
        ))
        .arg(Arg::with_name("summary").short("s").long("summary").help(
            "Print out summary information after duplicates",
        ))
        .get_matches()
}

fn collect_paths(path: &str, noempty: bool, stats: &mut Stats) -> HashMap<u64, Vec<PathBuf>> {

    let mut length_paths = HashMap::new();
    let spinner = ["|", "/", "-", "\\"];

    for (idx, entry) in WalkDir::new(path).into_iter().enumerate() {
        eprint!("\rBuilding file list {} ", spinner[idx % spinner.len()]);
        let entry = match entry {
            Ok(e) => e,
            Err(err) => {
                eprintln!("dupr: {}", err);
                continue;
            }
        };

        if !entry.file_type().is_file() {
            continue;
        }

        let metadata = match entry.metadata() {
            Ok(e) => e,
            Err(err) => {
                eprintln!("dupr: {}", err);
                continue;
            }
        };

        if noempty && metadata.len() == 0 {
            continue;
        }

        stats.file_count += 1;
        stats.total_size += metadata.len();

        let path = entry.path().to_path_buf();

        length_paths
            .entry(metadata.len())
            .or_insert(Vec::new())
            .push(path);
    }
    eprint!("\r{:40}", " ");

    length_paths
}

fn main() {
    let matches = parse_args();

    let mut stats: Stats = Default::default();

    let files = collect_paths(
        matches.value_of("DIR").unwrap(),
        matches.is_present("noempty"),
        &mut stats,
    );

    let file_count = files.len();

    let mut len_hash_path = HashMap::new();

    for (idx, (len, paths)) in files.iter().enumerate() {

        eprint!(
            "\rProgress [{}/{}] {:.0}%",
            idx,
            file_count,
            100.0 * idx as f64 / file_count as f64
        );

        if paths.len() < 2 {
            continue;
        }

        let mut inode_paths = HashMap::new();

        for path in paths {
            let metadata = match path.metadata() {
                Ok(m) => m,
                Err(err) => {
                    eprintln!("dupr: {}", err);
                    continue;
                }
            };

            let dev_inode = (metadata.st_dev(), metadata.st_ino());

            inode_paths.entry(dev_inode).or_insert(Vec::new()).push(
                path,
            );
        }

        if inode_paths.len() > 1 {
            for paths in inode_paths.values() {
                len_hash_path
                    .entry((len, hash_file(paths[0])))
                    .or_insert(BTreeSet::new())
                    .insert(paths[0]);
            }
        }
    }
    eprint!("\r{:40}\r", " ");

    let mut keys:Vec<_> = len_hash_path.iter().filter(|&(_,v)| v.len() > 1).collect();
    keys.sort();

    for (_, paths) in keys {
        for path in paths {
            println!("{}", path.display());
        }
        println!();
    }

    if matches.is_present("summary") {
        println!(
            "Processed {} files with a total size of {} bytes. {} duplicates found.",
            stats.file_count,
            stats.total_size,
            stats.duplicate_count
        );
    }
}

fn hash_file<P: AsRef<Path>>(path: P) -> u64 {
    let mut file = File::open(path).unwrap();

    let mut hash = XxHash::with_seed(0);

    let mut buffer = [0; 32 * 1024];

    while let Ok(n) = file.read(&mut buffer) {
        if n == 0 {
            break;
        }
        hash.write(&buffer[0..n]);
    }

    hash.finish()
}
<commit_msg>Add duplicate counter back in.<commit_after>extern crate clap;
extern crate walkdir;
extern crate twox_hash;

use std::collections::HashMap;
use std::collections::BTreeSet;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::os::linux::fs::MetadataExt;

use clap::{App, Arg, ArgMatches};
use walkdir::WalkDir;
use twox_hash::XxHash;
use std::hash::Hasher;

#[derive(Default)]
struct Stats {
    file_count: u64,
    total_size: u64,
    duplicate_count: u64,
}

fn parse_args<'a>() -> ArgMatches<'a> {
    App::new("dupr")
        .version("0.1.0")
        .author("Mike Sampson")
        .about("Duplicate file finder")
        .arg(
            Arg::with_name("DIR")
                .help("Directory to process")
                .required(true),
        )
        .arg(Arg::with_name("noempty").short("n").long("noempty").help(
            "Exclude zero length files",
        ))
        .arg(Arg::with_name("summary").short("s").long("summary").help(
            "Print out summary information after duplicates",
        ))
        .get_matches()
}

fn collect_paths(path: &str, noempty: bool, stats: &mut Stats) -> HashMap<u64, Vec<PathBuf>> {

    let mut length_paths = HashMap::new();
    let spinner = ["|", "/", "-", "\\"];

    for (idx, entry) in WalkDir::new(path).into_iter().enumerate() {
        eprint!("\rBuilding file list {} ", spinner[idx % spinner.len()]);
        let entry = match entry {
            Ok(e) => e,
            Err(err) => {
                eprintln!("dupr: {}", err);
                continue;
            }
        };

        if !entry.file_type().is_file() {
            continue;
        }

        let metadata = match entry.metadata() {
            Ok(e) => e,
            Err(err) => {
                eprintln!("dupr: {}", err);
                continue;
            }
        };

        if noempty && metadata.len() == 0 {
            continue;
        }

        stats.file_count += 1;
        stats.total_size += metadata.len();

        let path = entry.path().to_path_buf();

        length_paths
            .entry(metadata.len())
            .or_insert(Vec::new())
            .push(path);
    }
    eprint!("\r{:40}", " ");

    length_paths
}

fn main() {
    let matches = parse_args();

    let mut stats: Stats = Default::default();

    let files = collect_paths(
        matches.value_of("DIR").unwrap(),
        matches.is_present("noempty"),
        &mut stats,
    );

    let file_count = files.len();

    let mut len_hash_path = HashMap::new();

    for (idx, (len, paths)) in files.iter().enumerate() {

        eprint!(
            "\rProgress [{}/{}] {:.0}%",
            idx,
            file_count,
            100.0 * idx as f64 / file_count as f64
        );

        if paths.len() < 2 {
            continue;
        }

        let mut inode_paths = HashMap::new();

        for path in paths {
            let metadata = match path.metadata() {
                Ok(m) => m,
                Err(err) => {
                    eprintln!("dupr: {}", err);
                    continue;
                }
            };

            let dev_inode = (metadata.st_dev(), metadata.st_ino());

            inode_paths.entry(dev_inode).or_insert(Vec::new()).push(
                path,
            );
        }

        if inode_paths.len() > 1 {
            for paths in inode_paths.values() {
                len_hash_path
                    .entry((len, hash_file(paths[0])))
                    .or_insert(BTreeSet::new())
                    .insert(paths[0]);
            }
        }
    }
    eprint!("\r{:40}\r", " ");

    let mut keys:Vec<_> = len_hash_path.iter().filter(|&(_,v)| v.len() > 1).collect();
    keys.sort();
    stats.duplicate_count = keys.len() as u64;

    for (_, paths) in keys {
        for path in paths {
            println!("{}", path.display());
        }
        println!();
    }

    if matches.is_present("summary") {
        println!(
            "Processed {} files with a total size of {} bytes. {} duplicates found.",
            stats.file_count,
            stats.total_size,
            stats.duplicate_count
        );
    }
}

fn hash_file<P: AsRef<Path>>(path: P) -> u64 {
    let mut file = File::open(path).unwrap();

    let mut hash = XxHash::with_seed(0);

    let mut buffer = [0; 32 * 1024];

    while let Ok(n) = file.read(&mut buffer) {
        if n == 0 {
            break;
        }
        hash.write(&buffer[0..n]);
    }

    hash.finish()
}
<|endoftext|>


<commit_before>use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::io::BufRead;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod run;
mod util;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!("");
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!("");
    }

    if let Some(matches) = matches.subcommand_matches("run") {
        run(matches.clone());
    }

    if let Some(_) = matches.subcommand_matches("verify") {
        match verify() {
            Ok(_) => {}
            Err(_) => std::process::exit(1),
        }
    }

    if let Some(_) = matches.subcommand_matches("watch") {
        watch().unwrap();
    }

    if let None = matches.subcommand_name() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch() -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch("./exercises", RecursiveMode::Recursive)?;

    let _ignored = verify();

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
                    let _ignored = verify();
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<commit_msg>Fix file watching for vim swap files<commit_after>use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::io::BufRead;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod run;
mod util;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!("");
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!("");
    }

    if let Some(matches) = matches.subcommand_matches("run") {
        run(matches.clone());
    }

    if let Some(_) = matches.subcommand_matches("verify") {
        match verify() {
            Ok(_) => {}
            Err(_) => std::process::exit(1),
        }
    }

    if let Some(_) = matches.subcommand_matches("watch") {
        watch().unwrap();
    }

    if let None = matches.subcommand_name() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch() -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch("./exercises", RecursiveMode::Recursive)?;

    let _ignored = verify();

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
                    if b.extension() == Some(OsStr::new("rs")) {
                        let _ignored = verify();
                    }
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(path)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("some json output");

}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {
	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));
	// State. TODO: Don't just use a u64.
	let moved = 0;
	let mut current_hunk: Vec<String> = Vec::new();
	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {
		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.
		match line.origin() {
			// Context
			' ' | '=' => true,
			// Headers
			'F' | 'H' => true,
			// Additions
			'+' | '>' => {
				println!("+ {}", str::from_utf8(line.content()).unwrap());
				true
			},
			// Deletions
			'-' | '<' => {
				println!("- {}", str::from_utf8(line.content()).unwrap());
				true
			},
			// Other (We don't care about these.)
			_         => true,
		}
			// Look at that match statement, what a hunk. So hunky.
			// match maybe_hunk {
			//     Some(hunk) => unimplemented!(),
			//     None => unimplemented!(),
			// }
	});
	Ok(vec![Output {
		old_commit: old.id(),
		new_commit: new.id(),
		origin_line: 0,
		destination_line: 0,
		num_lines: 0
	}])
}

#[derive(Show)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<commit_msg>Print components of diff.<commit_after>#![feature(core)]
#![feature(path)]

extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType, DiffLine,
    Commit, Diff, DiffFormat, DiffDelta, DiffHunk, Error, Oid};
use docopt::Docopt;
use std::old_io as io;
use std::old_io::BufferedReader;
use std::old_io::File;
use std::str;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit <repo> [<old> <new>]

If no commits are given, transit will revwalk from latest to oldest.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_repo: String,
    arg_old: Option<String>,
    arg_new: Option<String>,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    // Pull up the revwalk.
    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Unable to find repo.");
    // If we can destructures the two optional args into real things.
    if let (Some(old_string), Some(new_string)) = (args.arg_old, args.arg_new) {
        // Compare a specific commit pair.
        // Fist, get the commits. (Error checked)
        let old = Oid::from_str(&old_string[]).and_then(|oid| repo.find_commit(oid));
        let new = Oid::from_str(&new_string[]).and_then(|oid| repo.find_commit(oid));
        if old.is_ok() && new.is_ok() {
            let output = find_moves(&repo, &old.unwrap(), &new.unwrap()).unwrap();
            make_output(output);
        } else {
            panic!("Commit ids were not valid.");
        }
    } else {
        // Revwalk.
        let mut revwalk = repo.revwalk()
            .ok().expect("Unable to get revwalk.");
        // Setup some options.
        revwalk.simplify_first_parent(); // TODO: Maybe remove?
        let mut flags = git2::Sort::empty();
        flags.insert(git2::SORT_TIME);
        flags.insert(git2::SORT_TOPOLOGICAL);
        revwalk.set_sorting(flags);
        // Push HEAD to the revwalk.
        revwalk.push_head()
            .ok().expect("Unable to push HEAD.");
        // We sadly must collect here to use `.windows()`
        let history = revwalk.filter_map(|id| repo.find_commit(id).ok())
            .collect::<Vec<Commit>>();
        // Walk through each pair of commits.
        for pair in history.windows(2) {let (old, new) = (&pair[1], &pair[0]);
			let output = find_moves(&repo, old.clone(), new.clone()).unwrap();
			// mangle the vectors here to make pretty output
			make_output(output);
		}
	}
}

fn make_output(output: Vec<Output>) {
	println!("make_output:");
    println!("\toutput.len()={}", output.len());
    for i in range(0, output.len()) {
            println!("\told_commit={}",         output[i].old_commit);
            println!("\tnew_commit={}",         output[i].new_commit);
            println!("\torigin_line={}",        output[i].origin_line);
            println!("\tdestintation_line={}",  output[i].destination_line);
            println!("\tnum_lines={}",          output[i].num_lines);
    }
}

fn print_or_none(s: &str, opt: Option<u32>) {
    print!("{}=", s);
    match opt {
        Some(value) => println!("{}", value),
        None => println!("NONE"),
    }
}

fn find_moves(repo: &Repository, old: &Commit, new: &Commit) -> Result<Vec<Output>, Error> {

    println!("\nFIND MOVES---------------------");

	let old_tree = try!(old.tree());
	let new_tree = try!(new.tree());
	// Build up a diff of the two trees.
	let diff = try!(Diff::tree_to_tree(repo, Some(&old_tree), Some(&new_tree), None));
	// State. TODO: Don't just use a u64.
	//let moved = 0;

    //let mut results: Vec<Output> = Vec::new();

    let mut has_addition = false;
    let mut has_deletion = false;

	//let mut current_hunk: Vec<String> = Vec::new();
	// Read about this function in http://alexcrichton.com/git2-rs/git2/struct.Diff.html#method.print
	// It's a bit weird, but I think it will provide the necessary information.
	diff.print(DiffFormat::Patch, |delta, maybe_hunk, line| -> bool {
		// Thinking:
		//  * If is not a hunk, keep going.
		//  * If it's a hunk, do regex magic.
		//  * Stick regex output into a hashmap as a hash.
		//  * Later, we will iterate through and output pased on the values.
		// Filter out all the boring context lines.
		// If we're not interested in this line just return since it will iterate to the next.
		if maybe_hunk.is_none() { return true }; // Return early.

        println!("");
        print_or_none("line.old_lineno()", line.old_lineno());
        print_or_none("line.new_lineno()", line.new_lineno());
        println!("line.num_lines()={}",  line.num_lines());
        println!("line.content_offset={}", line.content_offset());
        println!("|line.origin()|=|{}|", line.origin());  // Wrap in |'s to detect space characters.
        print!("line.content()={}", str::from_utf8(line.content()).unwrap());

        println!("delta.nfiles()={}", delta.nfiles());
        println!("delta.status()={:?}", delta.status());    // :? is for debug trait.
        println!("delta.old_file():\n\tid={}\n\tpath_bytes=TODO\n\tpath=TODO\n\tsize={}", delta.old_file().id(), delta.old_file().size());
        println!("delta.new_file():\n\tid={}\n\tpath_bytes=TODO\n\tpath=TODO\n\tsize={}", delta.new_file().id(), delta.new_file().size());

		match line.origin() {
			// Context
			' ' | '=' => {
                print!("= {}", str::from_utf8(line.content()).unwrap());
                true
            },
			// Headers
			'F' | 'H' => {
                print!("F {}", str::from_utf8(line.content()).unwrap());
                true
            },
			// Additions
			'+' | '>' => {
				print!("+ {}", str::from_utf8(line.content()).unwrap());
                has_addition = true;
				true
			},
			// Deletions
			'-' | '<' => {
				print!("- {}", str::from_utf8(line.content()).unwrap());
                has_deletion = true;
				true
			},
			// Other (We don't care about these.)
			_         => {
                print!("_ {}", str::from_utf8(line.content()).unwrap());
                true
            }
		}
			// Look at that match statement, what a hunk. So hunky.
			// match maybe_hunk {
			//     Some(hunk) => unimplemented!(),
			//     None => unimplemented!(),
			// }
	});

    println!("\nhas_addition={}, has_deletion={}", has_addition, has_deletion);

   // if has_addition && has_deletion {
/*
        results.push(Output {
		    old_commit: old.id(),
		    new_commit: new.id(),
		    origin_line: 0,
		    destination_line: 0,
		    num_lines: 0
        });
*/
    //}

    if !has_addition || !has_deletion {
        println!("Does not have addition or deletion.");
        Ok(vec![])  // Return empty vector.
    } else {

	    Ok(vec![Output {
		    old_commit: old.id(),
		    new_commit: new.id(),
		    origin_line: 0,
		    destination_line: 0,
		    num_lines: 0
	    }])
    }

   // Ok(results)
}

#[derive(Show)]
struct Output {
    old_commit: Oid,
    new_commit: Oid,
    origin_line: u32,
    destination_line: u32,
    num_lines: u32,
}
<|endoftext|>


<commit_before>extern crate rand;

use std::{fmt, iter, thread, time};

use rand::Rng;

#[derive(Debug, Clone, Copy, PartialEq)]
enum Cell {
    Dead,
    Alive,
}

impl fmt::Display for Cell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ch = match *self {
            Cell::Dead => ' ',
            Cell::Alive => '█',
        };
        write!(f, "{}", ch)
    }
}

struct Grid {
    width: usize,
    height: usize,
    buf: Box<[Cell]>,
}

impl Grid {
    /// width, height and percentage
    pub fn new(w: usize, h: usize, p: f32) -> Self {
        let mut rng = rand::thread_rng();
        let buf_size = h * w;
        let live_cnt = ((buf_size as f32) * (p / 100.0)) as usize;
        let dead_cnt = buf_size - live_cnt;

        let mut buf = iter::repeat(Cell::Alive)
            .take(live_cnt)
            .chain(iter::repeat(Cell::Dead).take(dead_cnt))
            .collect::<Vec<Cell>>()
            .into_boxed_slice();

        rng.shuffle(&mut buf);

        Self {
            buf,
            width: w,
            height: h,
        }
    }

    pub fn display(&self) {
        (0..self.width).for_each(|_| print!("-"));
        println!("");

        self.buf.chunks(self.width).for_each(|l| {
            l.iter().for_each(|c| print!("{}", c));
            println!("");
        });

        (0..self.width).for_each(|_| print!("-"));
        println!("");
    }

    fn get_neigh(&self, idx: usize) -> [Cell; 8] {
        let l_edge = idx % self.width == 0;
        let r_edge = idx % self.width == self.width - 1;
        let t_edge = idx / self.width == 0;
        let b_edge = idx / self.width == self.height - 1;

        let l = if !l_edge {
            idx - 1
        } else {
            idx + self.width - 1
        };

        let r = if !r_edge {
            idx + 1
        } else {
            idx + 1 - self.width
        };

        let u = if !t_edge {
            idx - self.width
        } else {
            idx + (self.width * (self.height - 1))
        };

        let d = if !b_edge {
            idx + self.width
        } else {
            idx % self.width
        };

        let ru = if !t_edge {
            r - self.width
        } else {
            r + (self.width * (self.height - 1))
        };

        let rd = if !b_edge {
            r + self.width
        } else {
            r % self.width
        };

        let lu = if !t_edge {
            l - self.width
        } else {
            l + (self.width * (self.height - 1))
        };

        let ld = if !b_edge {
            l + self.width
        } else {
            l % self.width
        };

        //println!("{} {:?}", idx,  [l, r, u, d, ru, rd, lu, ld]);
        [
            self.buf[l],
            self.buf[r],
            self.buf[u],
            self.buf[d],
            self.buf[ru],
            self.buf[rd],
            self.buf[lu],
            self.buf[ld],
        ]
    }

    fn step(&mut self) {
        let counts: Vec<_> = (0..self.buf.len())
            .map(|idx| {
                self.get_neigh(idx)
                    .iter()
                    .filter(|&c| *c == Cell::Alive)
                    .count()
            })
            .collect();

        for (c, cnt) in self.buf.iter_mut().zip(counts) {
            *c = match (*c, cnt) {
                (Cell::Alive, cnt) if cnt < 2 => Cell::Dead,
                (Cell::Alive, cnt) if cnt < 4 => Cell::Alive,
                (Cell::Alive, cnt) if cnt >= 4 => Cell::Dead,
                (Cell::Dead, cnt) if cnt == 3 => Cell::Alive,
                _ => *c,
            }
        }
    }
}

fn main() {
    let mut g = Grid::new(50, 15, 15.0);

    g.display();
    for _ in 0..30 {
        thread::sleep(time::Duration::from_millis(200));
        g.step();
        g.display();
    }
}
<commit_msg>Change defaults<commit_after>extern crate rand;

use std::{fmt, iter, thread, time};

use rand::Rng;

#[derive(Debug, Clone, Copy, PartialEq)]
enum Cell {
    Dead,
    Alive,
}

impl fmt::Display for Cell {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ch = match *self {
            Cell::Dead => ' ',
            Cell::Alive => '█',
        };
        write!(f, "{}", ch)
    }
}

struct Grid {
    width: usize,
    height: usize,
    buf: Box<[Cell]>,
}

impl Grid {
    /// width, height and percentage
    pub fn new(w: usize, h: usize, p: f32) -> Self {
        let mut rng = rand::thread_rng();
        let buf_size = h * w;
        let live_cnt = ((buf_size as f32) * (p / 100.0)) as usize;
        let dead_cnt = buf_size - live_cnt;

        let mut buf = iter::repeat(Cell::Alive)
            .take(live_cnt)
            .chain(iter::repeat(Cell::Dead).take(dead_cnt))
            .collect::<Vec<Cell>>()
            .into_boxed_slice();

        rng.shuffle(&mut buf);

        Self {
            buf,
            width: w,
            height: h,
        }
    }

    pub fn display(&self) {
        (0..self.width).for_each(|_| print!("-"));
        println!("");

        self.buf.chunks(self.width).for_each(|l| {
            l.iter().for_each(|c| print!("{}", c));
            println!("");
        });

        (0..self.width).for_each(|_| print!("-"));
        println!("");
    }

    fn get_neigh(&self, idx: usize) -> [Cell; 8] {
        let l_edge = idx % self.width == 0;
        let r_edge = idx % self.width == self.width - 1;
        let t_edge = idx / self.width == 0;
        let b_edge = idx / self.width == self.height - 1;

        let l = if !l_edge {
            idx - 1
        } else {
            idx + self.width - 1
        };

        let r = if !r_edge {
            idx + 1
        } else {
            idx + 1 - self.width
        };

        let u = if !t_edge {
            idx - self.width
        } else {
            idx + (self.width * (self.height - 1))
        };

        let d = if !b_edge {
            idx + self.width
        } else {
            idx % self.width
        };

        let ru = if !t_edge {
            r - self.width
        } else {
            r + (self.width * (self.height - 1))
        };

        let rd = if !b_edge {
            r + self.width
        } else {
            r % self.width
        };

        let lu = if !t_edge {
            l - self.width
        } else {
            l + (self.width * (self.height - 1))
        };

        let ld = if !b_edge {
            l + self.width
        } else {
            l % self.width
        };

        //println!("{} {:?}", idx,  [l, r, u, d, ru, rd, lu, ld]);
        [
            self.buf[l],
            self.buf[r],
            self.buf[u],
            self.buf[d],
            self.buf[ru],
            self.buf[rd],
            self.buf[lu],
            self.buf[ld],
        ]
    }

    fn step(&mut self) {
        let counts: Vec<_> = (0..self.buf.len())
            .map(|idx| {
                self.get_neigh(idx)
                    .iter()
                    .filter(|&c| *c == Cell::Alive)
                    .count()
            })
            .collect();

        for (c, cnt) in self.buf.iter_mut().zip(counts) {
            *c = match (*c, cnt) {
                (Cell::Alive, cnt) if cnt < 2 => Cell::Dead,
                (Cell::Alive, cnt) if cnt < 4 => Cell::Alive,
                (Cell::Alive, cnt) if cnt >= 4 => Cell::Dead,
                (Cell::Dead, cnt) if cnt == 3 => Cell::Alive,
                _ => *c,
            }
        }
    }
}

fn main() {
    let mut g = Grid::new(100, 50, 15.0);

    g.display();
    loop {
        thread::sleep(time::Duration::from_millis(100));
        g.step();
        g.display();
    }
}
<|endoftext|>