<commit_before>//!
//! WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost

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

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

extern crate serial_support;

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

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::{Rng, thread_rng};

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

// Max number of failures we allow when trying to send
// data to client before exiting
// TODO: Make configurable
const MAX_SEND_ERROR_COUNT: u32 = 5;

fn main() {

  // Init logger
  env_logger::init().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 = include_str!("websockets.html").replace(
    "__WS_PORT__ = 8081",
    &format!("__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::<(String, 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
    ),
  );

  // Continuously iterate over connections,
  // spawning handlers
  for connection in ws_server.filter_map(Result::ok) {
    // 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.", sub_id);

    // 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_id, sub_tx_clone, sreq_tx_clone, connection);
  }
}

/// Spawn a websocket handler into its own thread
fn spawn_ws_handler(
  sub_id: String,
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(sub_id, &sub_tx_clone, &sreq_tx_clone, connection));
}

/// Websocket handler
fn ws_handler(
  sub_id: String,
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  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));

  let mut send_error_count = 0;

  let sleep_dur = Duration::from_millis(33);

  'msg_loop: loop {
    // 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));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            break 'msg_loop;
          }

          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((sub_id.clone(), 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());
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  send_error_count += 1;
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };

    if send_error_count > MAX_SEND_ERROR_COUNT {
      warn!(
        "{}: Client send error count exceeded! Shutting down msg loop.",
        &sub_id
      );
      break 'msg_loop;
    }

    thread::sleep(sleep_dur);
  }

  info!("{}: Shutting down!", 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>Expand on docs<commit_after>//!
//! # WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost
//!
//! ## Running
//!
//! ```./wsss```
//!
//! You can also specift a port:
//!
//! ```./wsss -p PORT_NUM``` or ```./wsss --port PORT_NUM```
//!
//! When you specify a port, a simple http server will
//! be bound at "/" on PORT_NUM, and a websocket bound at "/"
//! on PORT_NUM + 1
//!
//! The webpage served at "/" on PORT_NUM provides a convenient
//! way for testing serial port connectivity
//!
//! You can open/close ports, read and write data, and see the
//! responses. All messages are in JSON format

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

extern crate serial_support;

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

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::{Rng, thread_rng};

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

/// Max number of failures we allow when trying to send
/// data to client before exiting
/// TODO: Make configurable
pub const MAX_SEND_ERROR_COUNT: u32 = 5;

/// Launches wsss
pub fn main() {

  // Init logger
  env_logger::init().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 = include_str!("websockets.html").replace(
    "__WS_PORT__ = 8081",
    &format!("__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::<(String, 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
    ),
  );

  // Continuously iterate over connections,
  // spawning handlers
  for connection in ws_server.filter_map(Result::ok) {
    // 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.", sub_id);

    // 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_id, sub_tx_clone, sreq_tx_clone, connection);
  }
}

/// Spawn a websocket handler into its own thread
fn spawn_ws_handler(
  sub_id: String,
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(sub_id, &sub_tx_clone, &sreq_tx_clone, connection));
}

/// Websocket handler
fn ws_handler(
  sub_id: String,
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  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));

  let mut send_error_count = 0;

  let sleep_dur = Duration::from_millis(33);

  'msg_loop: loop {
    // 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));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            break 'msg_loop;
          }

          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((sub_id.clone(), 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());
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  send_error_count += 1;
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };

    if send_error_count > MAX_SEND_ERROR_COUNT {
      warn!(
        "{}: Client send error count exceeded! Shutting down msg loop.",
        &sub_id
      );
      break 'msg_loop;
    }

    thread::sleep(sleep_dur);
  }

  info!("{}: Shutting down!", sub_id);

}

/// Send an error to the given subscriber
/// Log a warning if the message can't be sent
/// This is usually ok as it means the client
/// has simply disconnected
pub 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 thread_scoped;
extern crate tray_rust;

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

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

use tray_rust::film;
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>,
}

/// A struct containing results of an image sample where a ray was fired through
/// continuous pixel coordinates [x, y] and color `color` was computed
struct ImageSample {
    x: f32,
    y: f32,
    color: film::Colorf,
}

impl ImageSample {
    pub fn new(x: f32, y: f32, color: film::Colorf) -> ImageSample {
        ImageSample { x: x, y: y, color: color }
    }
}

/// 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, 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 rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            let mut samples = Vec::with_capacity(sampler.max_spp());
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(scene, light_list, &ray,
                                                          &hit, &mut sampler, &mut rng).clamp();
                    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;
            }
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers<'a>(n: u32, spp: usize, scene: &'a scene::Scene,
                     queue: &'a sampler::BlockQueue, light_list: &'a Vec<&Emitter>)
                 -> (Receiver<Vec<ImageSample>>, Vec<thread_scoped::JoinGuard<'a, ()>>) {
    let (tx, rx) = mpsc::channel();
    let mut guards = Vec::new();
    for _ in 0..n {
        let t = tx.clone();
        unsafe {
            guards.push(thread_scoped::scoped(move || {
                thread_work(t, spp, queue, scene, light_list);
            }));
        }
    }
    (rx, guards)
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, scene: &scene::Scene, n: u32, spp: usize){
    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");
    {
        println!("Rendering using {} threads", n);
        let (rx, guards) = spawn_workers(n, spp, &scene, &block_queue, &light_list);
        for mut v in rx.iter() {
            for s in v.drain(..) {
                rt.write(s.x, s.y, &s.color);
            }
        }
        for g in guards {
            g.join();
        }
    }
}

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

    let (scene, spp, (width, height)) = scene::Scene::load_file(&args.arg_scenefile[..]);
    let mut rt = film::RenderTarget::new(width, height);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get() as u32,
    };

    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(f) => f,
        None => "out.png".to_string(),
    };

    match image::save_buffer(&Path::new(&out_file), &img[..], width as u32, height as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<commit_msg>Add note to self so I don't forget<commit_after>#![feature(duration_span, drain)]

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

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

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

use tray_rust::film;
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>,
}

/// A struct containing results of an image sample where a ray was fired through
/// continuous pixel coordinates [x, y] and color `color` was computed
struct ImageSample {
    x: f32,
    y: f32,
    color: film::Colorf,
}

impl ImageSample {
    pub fn new(x: f32, y: f32, color: film::Colorf) -> ImageSample {
        ImageSample { x: x, y: y, color: color }
    }
}

/// 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, 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 rng = match StdRng::new() {
        Ok(r) => r,
        Err(e) => { println!("Failed to get StdRng, {}", e); return }
    };
    // Grab a block from the queue and start working on it, submitting samples
    // to the render target thread after each pixel
    for b in queue.iter() {
        sampler.select_block(b);
        while sampler.has_samples() {
            // Get samples for a pixel and render them
            sampler.get_samples(&mut sample_pos, &mut rng);
            let mut samples = Vec::with_capacity(sampler.max_spp());
            for s in sample_pos.iter() {
                let mut ray = scene.camera.generate_ray(s);
                if let Some(hit) = scene.intersect(&mut ray) {
                    let c = scene.integrator.illumination(scene, light_list, &ray,
                                                          &hit, &mut sampler, &mut rng).clamp();
                    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;
            }
        }
    }
}

/// Spawn `n` worker threads to render the scene in parallel. Returns the receive end
/// of the channel where the threads will write their samples so that the receiver
/// can write these samples to the render target
fn spawn_workers<'a>(n: u32, spp: usize, scene: &'a scene::Scene,
                     queue: &'a sampler::BlockQueue, light_list: &'a Vec<&Emitter>)
                 -> (Receiver<Vec<ImageSample>>, Vec<thread_scoped::JoinGuard<'a, ()>>) {
    let (tx, rx) = mpsc::channel();
    let mut guards = Vec::new();
    for _ in 0..n {
        let t = tx.clone();
        // TODO: This is bad! However since the broken/deprecated thread::scoped API was
        // removed along with threadpool's ScopedPool we don't really have many options
        // for keeping the (albeit buggy) scoped thread behavior. I'd rather not re-write
        // the code back to how it was using ThreadPool only to re-write again when
        // thread::scoped returns in some form so this semi-nasty alternative is all
        // that's left to do.
        unsafe {
            guards.push(thread_scoped::scoped(move || {
                thread_work(t, spp, queue, scene, light_list);
            }));
        }
    }
    (rx, guards)
}

/// Render the scene in parallel to the render target
fn render_parallel(rt: &mut film::RenderTarget, scene: &scene::Scene, n: u32, spp: usize){
    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");
    {
        println!("Rendering using {} threads", n);
        let (rx, guards) = spawn_workers(n, spp, &scene, &block_queue, &light_list);
        for mut v in rx.iter() {
            for s in v.drain(..) {
                rt.write(s.x, s.y, &s.color);
            }
        }
        for g in guards {
            g.join();
        }
    }
}

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

    let (scene, spp, (width, height)) = scene::Scene::load_file(&args.arg_scenefile[..]);
    let mut rt = film::RenderTarget::new(width, height);
    let n = match args.flag_n {
        Some(n) => n,
        None => num_cpus::get() as u32,
    };

    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(f) => f,
        None => "out.png".to_string(),
    };

    match image::save_buffer(&Path::new(&out_file), &img[..], width as u32, height as u32, image::RGB(8)) {
        Ok(_) => {},
        Err(e) => println!("Error saving image, {}", e),
    };
}

<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
//#![allow(dead_code)]

#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{ Path, PathBuf };

lazy_static! {
    static ref HOME: PathBuf = std::env::home_dir().unwrap();

    static ref build_props: PathBuf = PathBuf::from("project/build.properties");

    static ref sbt_launch_dir: PathBuf = { let mut p = PathBuf::from(&*HOME); p.push(".sbt/launchers"); p };
}

const sbt_launch_ivy_release_repo: &'static str = "http://repo.typesafe.com/typesafe/ivy-releases";
const sbt_launch_mvn_release_repo: &'static str = "http://repo.scala-sbt.org/scalasbt/maven-releases";

macro_rules! echoerr(($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap();));

fn build_props_sbt() -> String {
    if let Ok(f) = File::open(&*build_props) {
        let f = BufReader::new(f);
        for line in f.lines() {
            let line = line.unwrap();
            if line.starts_with("sbt.version") {
                let line = line.replace("=", " ");
                let line = line.replace("\r", " ");
                return line.split_whitespace().nth(1).unwrap().to_owned();
            }
        }
    }
    "".to_owned()
}

fn jar_file(version: &str) -> PathBuf {
    let mut p = PathBuf::from(&*sbt_launch_dir);
    p.push(version);
    p.push("sbt-launch.jar");
    p
}

fn url_base(version: &str) -> &'static str { match version {
    s if s.starts_with("0.7.")  => "http://simple-build-tool.googlecode.com",
    s if s.starts_with("0.10.") => sbt_launch_ivy_release_repo,
    "0.11.1" | "0.11.2"         => sbt_launch_ivy_release_repo,
 // "0.*-yyyymmdd-hhMMss"       => sbt_launch_ivy_snapshot_repo, // https://repo.scala-sbt.org/scalasbt/ivy-snapshots
    s if s.starts_with("0.")    => sbt_launch_ivy_release_repo,
 // "*-yyyymmdd-hhMMss"         => sbt_launch_mvn_snapshot_repo, // http://repo.scala-sbt.org/scalasbt/maven-snapshots
    _                           => sbt_launch_mvn_release_repo,
} }

fn make_url(version: &str) -> String {
    let base = url_base(version);
    match version {
        s if s.starts_with("0.7.")  => format!("{}/files/sbt-launch-0.7.7.jar", base),
        s if s.starts_with("0.10.") => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        "0.11.1" | "0.11.2"         => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        s if s.starts_with("0.")    => format!("{}/org.scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        _                           => format!("{}/org/scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
    }
}

fn download_url(sbt_version: &str, url: &str, jar: &Path) {
    echoerr!("Downloading sbt launcher for {}:", sbt_version);
    echoerr!("  From  {}", url);
    echoerr!("    To  {}", jar.display());

    std::fs::create_dir_all(jar.parent().unwrap()).unwrap();

    extern crate hyper;
    let mut r = BufReader::new(hyper::client::Client::new().get(url).send().unwrap());
    let mut buf = [0; 16384];
    let mut jar = std::io::BufWriter::new(File::create(jar).unwrap());
    while {
        let bc = r.read(&mut buf).unwrap();
        jar.write(&buf[0..bc]).unwrap();
        bc > 0
    } {}
    jar.flush().unwrap();
}

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    let sbt_version = build_props_sbt();
    let sbt_jar = {
        let mut sbt_jar = jar_file(&sbt_version);
        if !sbt_jar.exists() {
            sbt_jar = PathBuf::from(&*HOME);
            sbt_jar.push(format!(".ivy2/local/org.scala-sbt/sbt-launch/{}/jars/sbt-launch.jar", sbt_version));
        }
        if !sbt_jar.exists() {
            sbt_jar = jar_file(&sbt_version);
            download_url(&sbt_version, &make_url(&sbt_version), &sbt_jar);
        }
        sbt_jar
    };

    let java_cmd = "java";
    let extra_jvm_opts = ["-Xms512m", "-Xmx1536m", "-Xss2m"];
    let java_args: [&str; 0] = [];
    let sbt_commands: [&str; 0] = [];
    let residual_args = ["shell"];

    let exec_args: Vec<&OsStr> = {
        let mut exec_args = Vec::new();
        exec_args.push(java_cmd.as_ref());
        exec_args.extend_from_slice(&extra_jvm_opts.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
        exec_args.extend_from_slice(&java_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
        exec_args.extend_from_slice(&["-jar".as_ref(), sbt_jar.as_ref()]);
        exec_args.extend_from_slice(&sbt_commands.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
        exec_args.extend_from_slice(&residual_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
        exec_args
    };

    exec_runner(&exec_args)
}
<commit_msg>4 for 8 trade on loc<commit_after>#![allow(non_upper_case_globals)]
//#![allow(dead_code)]

#[macro_use] extern crate lazy_static;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{ Path, PathBuf };

lazy_static! {
    static ref HOME: PathBuf = std::env::home_dir().unwrap();

    static ref build_props: PathBuf = PathBuf::from("project/build.properties");

    static ref sbt_launch_dir: PathBuf = { let mut p = PathBuf::from(&*HOME); p.push(".sbt/launchers"); p };
}

const sbt_launch_ivy_release_repo: &'static str = "http://repo.typesafe.com/typesafe/ivy-releases";
const sbt_launch_mvn_release_repo: &'static str = "http://repo.scala-sbt.org/scalasbt/maven-releases";

macro_rules! echoerr(($($arg:tt)*) => (writeln!(&mut ::std::io::stderr(), $($arg)*).unwrap();));

fn build_props_sbt() -> String {
    if let Ok(f) = File::open(&*build_props) {
        let f = BufReader::new(f);
        for line in f.lines() {
            let line = line.unwrap();
            if line.starts_with("sbt.version") {
                let line = line.replace("=", " ");
                let line = line.replace("\r", " ");
                return line.split_whitespace().nth(1).unwrap().to_owned();
            }
        }
    }
    "".to_owned()
}

fn jar_file(version: &str) -> PathBuf {
    let mut p = PathBuf::from(&*sbt_launch_dir);
    p.push(version);
    p.push("sbt-launch.jar");
    p
}

fn url_base(version: &str) -> &'static str { match version {
    s if s.starts_with("0.7.")  => "http://simple-build-tool.googlecode.com",
    s if s.starts_with("0.10.") => sbt_launch_ivy_release_repo,
    "0.11.1" | "0.11.2"         => sbt_launch_ivy_release_repo,
 // "0.*-yyyymmdd-hhMMss"       => sbt_launch_ivy_snapshot_repo, // https://repo.scala-sbt.org/scalasbt/ivy-snapshots
    s if s.starts_with("0.")    => sbt_launch_ivy_release_repo,
 // "*-yyyymmdd-hhMMss"         => sbt_launch_mvn_snapshot_repo, // http://repo.scala-sbt.org/scalasbt/maven-snapshots
    _                           => sbt_launch_mvn_release_repo,
} }

fn make_url(version: &str) -> String {
    let base = url_base(version);
    match version {
        s if s.starts_with("0.7.")  => format!("{}/files/sbt-launch-0.7.7.jar", base),
        s if s.starts_with("0.10.") => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        "0.11.1" | "0.11.2"         => format!("{}/org.scala-tools.sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        s if s.starts_with("0.")    => format!("{}/org.scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
        _                           => format!("{}/org/scala-sbt/sbt-launch/{}/sbt-launch.jar", base, version),
    }
}

fn download_url(sbt_version: &str, url: &str, jar: &Path) {
    echoerr!("Downloading sbt launcher for {}:", sbt_version);
    echoerr!("  From  {}", url);
    echoerr!("    To  {}", jar.display());

    std::fs::create_dir_all(jar.parent().unwrap()).unwrap();

    extern crate hyper;
    let mut r = BufReader::new(hyper::client::Client::new().get(url).send().unwrap());
    let mut buf = [0; 16384];
    let mut jar = std::io::BufWriter::new(File::create(jar).unwrap());
    while {
        let bc = r.read(&mut buf).unwrap();
        jar.write(&buf[0..bc]).unwrap();
        bc > 0
    } {}
    jar.flush().unwrap();
}

fn exec_runner<S: AsRef<OsStr>>(args: &[S]) {
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new(&args[0]).args(&args[1..]).exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}

fn main() {
    let sbt_version = build_props_sbt();
    let mut sbt_jar = jar_file(&sbt_version);
    if !sbt_jar.exists() {
        sbt_jar = PathBuf::from(&*HOME);
        sbt_jar.push(format!(".ivy2/local/org.scala-sbt/sbt-launch/{}/jars/sbt-launch.jar", sbt_version));
    }
    if !sbt_jar.exists() {
        sbt_jar = jar_file(&sbt_version);
        download_url(&sbt_version, &make_url(&sbt_version), &sbt_jar);
    }
    let sbt_jar = sbt_jar.as_path();

    let java_cmd = "java";
    let extra_jvm_opts = ["-Xms512m", "-Xmx1536m", "-Xss2m"];
    let java_args: [&str; 0] = [];
    let sbt_commands: [&str; 0] = [];
    let residual_args = ["shell"];

    let mut exec_args: Vec<&OsStr> = Vec::new();
    exec_args.push(java_cmd.as_ref());
    exec_args.extend_from_slice(&extra_jvm_opts.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&java_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&["-jar".as_ref(), sbt_jar.as_ref()]);
    exec_args.extend_from_slice(&sbt_commands.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    exec_args.extend_from_slice(&residual_args.iter().map(|x| x.as_ref()).collect::<Vec<_>>());
    let exec_args = &exec_args;

    exec_runner(exec_args)
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter, Write};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;
use std::error::Error;

use getopts::Options;

use tempdir::TempDir;

/// Create an InvalidData io::Error with the description being a
/// formatted string
macro_rules! io_error {
    ($fmtstr:tt) => { io_error!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData,
                                  format!($fmtstr, $( $args ),* )));
    };
}

/// Alternative to println! that prints to stderr instead of stdout
macro_rules! printerrln {
    ($fmtstr:tt) => { printerrln!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        writeln!(&mut io::stderr(), $fmtstr, $( $args ),* ).silent_unwrap();
    }
}

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

/// Trait used in place of unwrap for printing to stdout/stderr, since if that
/// errors the program should simply exit with no further output
trait SilentUnwrap<T> {
    fn silent_unwrap(self) -> T;
}
impl<T> SilentUnwrap<T> for io::Result<T> {
    fn silent_unwrap(self) -> T {
        match self {
            Ok(t) => t,
            Err(_) => std::process::exit(1),
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = match opts.parse(&args[1..]) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error parsing options: {:?}", e.description()))
        },
    };

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

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return;
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = match matches.opt_str("input") {
        Some(x) => x,
        None => {
            match matches.opts_str(&["edit".to_string(),
                                     "print".to_string(),
                                     "reverse".to_string()]) {

                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    /* Analogous to the input */
    let output = match matches.opt_str("output") {
        Some(x) => x,
        None => {
            match matches.opt_str("edit") {
                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    if matches.opt_present("print") {
        print(&input, &output);
        return;
    }

    if matches.opt_present("reverse") {
        reverse(&input, &output);
        return;
    }

    /* Default to --edit */
    edit(&input, &output);
}

/// When the user wants to edit a specific file in place
fn edit(input: &str, output: &str) {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = match TempDir::new("nbted") {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to create temporary directory: {:?}",
                          e.description()))
        },
    };

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => error(&format!("Error reading file name")),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = match File::create(&tmp_path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to create temporary file: {:?}",
                              e.description()))
            },
        };

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to write temporary file: {:?}",
                              e.description()))
            },
        };

        match f.sync_all() {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to synchronize file: {:?}",
                              e.description()))
            },
        }
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            printerrln!("Unable to parse edited file: {}.\n\
            Do you want to open the file for editing again? (y/N)",
                        e.description());

            let mut line = String::new();
            match io::stdin().read_line(&mut line) {
                Ok(_) => (),
                Err(e) => {
                    error(&format!("Error reading from stdin: {}\n\
                                   Nothing was changed.",
                                  e.description()))
                },
            }

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                printerrln!("Exiting ... File is unchanged.");
                std::process::exit(1);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        printerrln!("No changes, will do nothing.");
        return;
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        write::write_file(&mut f, &new_nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }

    printerrln!("File edited successfully.");
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> io::Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => error("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = match cmd.spawn() {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error opening editor: {:?}", e.description()))
        },
    };

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Err(e) => {
            error(&format!("Error executing editor: {:?}", e.description()))
        },
        _ => error("Editor did not exit correctly"),
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = match File::open(&tmp_path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read temporary file: {:?}.\n\
        Nothing was changed",
                          e.description()))
        },
    };

    string_read::read_file(&mut f)
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        string_write::write_file(&mut f, &nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }
}

/// When the user wants to convert a text format file into an NBT file
fn reverse(input: &str, output: &str) {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = match File::open(&path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read text file {}: {:?}",
                          input,
                          e.description()))
        },
    };

    let nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse text file {}: {:?}",
                          input,
                          e.description()))
        },
    };

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        write::write_file(&mut f, &nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }
}

/// Print the given message and exit with status code 1
fn error(message: &str) -> ! {
    printerrln!("Error: {}", message);
    printerrln!("Run with --help for help, or read the manpage.");
    exit(1);
}

fn print_usage(opts: Options) {
    let brief = "Usage: nbted [options] FILE";
    print!("{}", opts.usage(&brief));
    println!("\nFor detailed usage information, read the manpage.");
}
<commit_msg>Use eprintln! instead of custom printerrln!<commit_after>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;
use std::error::Error;

use getopts::Options;

use tempdir::TempDir;

/// Create an InvalidData io::Error with the description being a
/// formatted string
macro_rules! io_error {
    ($fmtstr:tt) => { io_error!($fmtstr,) };
    ($fmtstr:tt, $( $args:expr ),* ) => {
        Err(::std::io::Error::new(::std::io::ErrorKind::InvalidData,
                                  format!($fmtstr, $( $args ),* )));
    };
}

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

/// Trait used in place of unwrap for printing to stdout/stderr, since if that
/// errors the program should simply exit with no further output
trait SilentUnwrap<T> {
    fn silent_unwrap(self) -> T;
}
impl<T> SilentUnwrap<T> for io::Result<T> {
    fn silent_unwrap(self) -> T {
        match self {
            Ok(t) => t,
            Err(_) => std::process::exit(1),
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = match opts.parse(&args[1..]) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error parsing options: {:?}", e.description()))
        },
    };

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

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return;
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = match matches.opt_str("input") {
        Some(x) => x,
        None => {
            match matches.opts_str(&["edit".to_string(),
                                     "print".to_string(),
                                     "reverse".to_string()]) {

                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    /* Analogous to the input */
    let output = match matches.opt_str("output") {
        Some(x) => x,
        None => {
            match matches.opt_str("edit") {
                Some(x) => x,
                None if matches.free.len() > 0 => matches.free[0].clone(),
                None => "-".to_string(),
            }
        },
    };

    if matches.opt_present("print") {
        print(&input, &output);
        return;
    }

    if matches.opt_present("reverse") {
        reverse(&input, &output);
        return;
    }

    /* Default to --edit */
    edit(&input, &output);
}

/// When the user wants to edit a specific file in place
fn edit(input: &str, output: &str) {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = match TempDir::new("nbted") {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to create temporary directory: {:?}",
                          e.description()))
        },
    };

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => error(&format!("Error reading file name")),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = match File::create(&tmp_path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to create temporary file: {:?}",
                              e.description()))
            },
        };

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to write temporary file: {:?}",
                              e.description()))
            },
        };

        match f.sync_all() {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Unable to synchronize file: {:?}",
                              e.description()))
            },
        }
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            eprintln!("Unable to parse edited file: {}.\n\
            Do you want to open the file for editing again? (y/N)",
                        e.description());

            let mut line = String::new();
            match io::stdin().read_line(&mut line) {
                Ok(_) => (),
                Err(e) => {
                    error(&format!("Error reading from stdin: {}\n\
                                   Nothing was changed.",
                                  e.description()))
                },
            }

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                eprintln!("Exiting ... File is unchanged.");
                std::process::exit(1);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        eprintln!("No changes, will do nothing.");
        return;
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        write::write_file(&mut f, &new_nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }

    eprintln!("File edited successfully.");
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> io::Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => error("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = match cmd.spawn() {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Error opening editor: {:?}", e.description()))
        },
    };

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Err(e) => {
            error(&format!("Error executing editor: {:?}", e.description()))
        },
        _ => error("Editor did not exit correctly"),
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = match File::open(&tmp_path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read temporary file: {:?}.\n\
        Nothing was changed",
                          e.description()))
        },
    };

    string_read::read_file(&mut f)
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    } else {
        let path: &Path = Path::new(input);
        let f = match File::open(path) {
            Ok(f) => f,
            Err(_) => error(&format!("Unable to open file {}", input)),
        };
        let mut f = BufReader::new(f);

        match read::read_file(&mut f) {
            Ok(x) => x,
            Err(_) => {
                error(&format!("Unable to parse {}, are you sure it's an NBT file?",
                              input))
            },
        }
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        string_write::write_file(&mut f, &nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }
}

/// When the user wants to convert a text format file into an NBT file
fn reverse(input: &str, output: &str) {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = match File::open(&path) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to read text file {}: {:?}",
                          input,
                          e.description()))
        },
    };

    let nbt = match string_read::read_file(&mut f) {
        Ok(x) => x,
        Err(e) => {
            error(&format!("Unable to parse text file {}: {:?}",
                          input,
                          e.description()))
        },
    };

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        write::write_file(&mut f, &nbt).silent_unwrap();
    } else {
        let path: &Path = Path::new(output);
        let f = match File::create(&path) {
            Ok(x) => x,
            Err(e) => {
                error(&format!("Unable to write to output NBT file {}: {:?}.\n\
            Nothing was changed",
                              output,
                              e.description()))
            },
        };
        let mut f = BufWriter::new(f);

        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(e) => {
                error(&format!("Error writing NBT file {}: {:?}.\n\
            State of NBT file is unknown, consider restoring it from a backup.",
                              output,
                              e.description()))
            },
        }
    }
}

/// Print the given message and exit with status code 1
fn error(message: &str) -> ! {
    eprintln!("Error: {}", message);
    eprintln!("Run with --help for help, or read the manpage.");
    exit(1);
}

fn print_usage(opts: Options) {
    let brief = "Usage: nbted [options] FILE";
    print!("{}", opts.usage(&brief));
    println!("\nFor detailed usage information, read the manpage.");
}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::io;
use std::io::prelude::*;
use std::thread;
use std::str;

const COMMAND_BUF_SIZE: usize = 4096;

struct IrcMessage {
	msg: [u8; COMMAND_BUF_SIZE],
	length: usize,
}

struct IrcReader {
	stream: TcpStream,

}

impl IrcReader {
	pub fn new(base_stream: &TcpStream) -> std::io::Result<IrcReader> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcReader {
			stream: stream,
		})
	}
}

impl Iterator for IrcReader {
	type Item = IrcMessage;
	fn next(&mut self) -> Option<IrcMessage> {
		let mut command_buf: [u8; COMMAND_BUF_SIZE] = [0; COMMAND_BUF_SIZE];
		let mut buf_ind = 0;
		let mut command_end = false;
		let stream = &self.stream;
		let bytes = stream.bytes();
		for x in bytes {
			if x.is_err() {
				return None;
			}
			let next_char = x.unwrap();
			command_buf[buf_ind] = next_char;
			buf_ind = buf_ind + 1;
			if command_end && next_char == 10 {
				return Some(IrcMessage { msg: command_buf, length: buf_ind - 2 });
			} else if next_char == 13 {
				command_end = true;
			} else {
				command_end = false;
			}

			if buf_ind >= COMMAND_BUF_SIZE {
				buf_ind = 0;
			}
		}
		None
	}
}

struct IrcWriter {
	stream: TcpStream,
}

impl IrcWriter {
	pub fn new(base_stream: &TcpStream) -> std::io::Result<IrcWriter> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcWriter {
			stream: stream,
		})
	}

	pub fn write(&mut self, bytes: &[u8]) {
		let _ = &self.stream.write(&bytes);
	}
}

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

	let connection = connection_result.unwrap();
	let reader = IrcReader::new(&connection).unwrap();
	let mut writer = IrcWriter::new(&connection).unwrap();

	thread::spawn(move || {
		let mut stdin = io::stdin();
		let mut buf = String::new();
		loop {
			let _= stdin.read_line(&mut buf).unwrap();
			writer.write(&buf.as_bytes());
		}
	});

	for irc_msg in reader {
		parse_command(&irc_msg.msg[0..irc_msg.length]);
	}
}

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

const COMMAND_BUF_SIZE: usize = 4096;

struct IrcMessage {
	msg: [u8; COMMAND_BUF_SIZE],
	length: usize,
}

struct IrcReader {
	stream: TcpStream,

}

impl IrcReader {
	pub fn new(base_stream: &TcpStream) -> std::io::Result<IrcReader> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcReader {
			stream: stream,
		})
	}
}

impl Iterator for IrcReader {
	type Item = IrcMessage;
	fn next(&mut self) -> Option<IrcMessage> {
		let mut command_buf: [u8; COMMAND_BUF_SIZE] = [0; COMMAND_BUF_SIZE];
		let mut buf_ind = 0;
		let mut command_end = false;
		let stream = &self.stream;
		let bytes = stream.bytes();
		for x in bytes {
			if x.is_err() {
				return None;
			}
			let next_char = x.unwrap();
			command_buf[buf_ind] = next_char;
			buf_ind = buf_ind + 1;
			if command_end && next_char == 10 {
				return Some(IrcMessage { msg: command_buf, length: buf_ind - 2 });
			} else if next_char == 13 {
				command_end = true;
			} else {
				command_end = false;
			}

			if buf_ind >= COMMAND_BUF_SIZE {
				buf_ind = 0;
			}
		}
		None
	}
}

struct IrcWriter {
	stream: TcpStream,
}

impl IrcWriter {
	pub fn new(base_stream: &TcpStream) -> std::io::Result<IrcWriter> {
		let stream = try!(base_stream.try_clone());
		Ok(IrcWriter {
			stream: stream,
		})
	}

	pub fn write(&mut self, bytes: &[u8]) {
		let _ = &self.stream.write(&bytes);
	}
}

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

	let connection = connection_result.unwrap();
	let reader = IrcReader::new(&connection).unwrap();
	let mut writer = IrcWriter::new(&connection).unwrap();

	thread::spawn(move || {
		let stdin = io::stdin();
        let stdin_lock = stdin.lock();
        for in_line in stdin_lock.lines() {
            writer.write(in_line.unwrap().as_bytes());
            writer.write(b"\n");
        }
	});

	for irc_msg in reader {
		parse_command(&irc_msg.msg[0..irc_msg.length]);
	}
}

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


<commit_before>#[macro_use] extern crate glium;
extern crate ocl;
extern crate cgl;

use glium::{DisplayBuild, Surface, VertexBuffer, IndexBuffer, Program, GlObject};
use glium::index::{NoIndices, PrimitiveType};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

const VERTEX_SRC: &'static str = include_str!("shaders/default.vert");
const FRAGMENT_SRC: &'static str = include_str!("shaders/default.frag");

use ocl::{util, core, ProQue, Buffer, Device, Platform, Queue, Context, Program as ProgramCl};
use ocl::core::{ContextProperties, DeviceType, DeviceInfo};
use ocl::builders::DeviceSpecifier;
use ocl::cl_h::CL_DEVICE_TYPE_GPU;

const KERNEL_SRC: &'static str = include_str!("kernels/test.cl");

use cgl::{CGLGetCurrentContext, CGLGetShareGroup};

// Number of results to print out:
const RESULTS_TO_PRINT: usize = 20;

// Our arbitrary data set size and coefficent:
const DATA_SET_SIZE: usize = 2 << 20;
const COEFF: f32 = 5432.1;

#[derive(Copy, Clone, PartialEq, PartialOrd)]
struct Particle {
    position: [f32; 2],
    color: [f32; 3], // to delete
}

// struct ParticlePosition
// struct ParticleVelocity

implement_vertex!(Particle, position, color);

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1024, 768)
        .with_title(String::from("Hello world"))
        .build_glium()
        .unwrap();

    let vertex_buffer = VertexBuffer::dynamic(&display,
            &[
                Particle { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
                Particle { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
                Particle { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
            ]).unwrap();
    // let indices = NoIndices(PrimitiveType::Points);
    let indices = IndexBuffer::new(&display, PrimitiveType::TrianglesList, &[0u16, 1, 2]).unwrap();
    let program = Program::from_source(&display, VERTEX_SRC, FRAGMENT_SRC, None).unwrap();
    let uniforms = uniform! {
        matrix: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32]
        ]
    };

    let cgl_current_ctx = unsafe { CGLGetCurrentContext() };
    let cgl_share_grp = unsafe { CGLGetShareGroup(cgl_current_ctx) };
    let properties = ContextProperties::new().cgl_sharegroup(cgl_share_grp);

    let platform_cl = Platform::default();
    let device_type_cl = DeviceType::from_bits_truncate(CL_DEVICE_TYPE_GPU);
    let devices_cl = Device::list(&platform_cl, Some(device_type_cl));
    let device_cl = devices_cl.first().expect("No device with specified types found.");

    println!("device: {:?}", device_cl.info(DeviceInfo::Name));

    let context_cl = Context::builder()
                    .properties(properties)
                    .devices(DeviceSpecifier::Single(*device_cl))
                    .build().unwrap();

    let program_builder_cl = ProgramCl::builder().src(KERNEL_SRC);
    let pq_cl = ProQue::builder()
                .context(context_cl)
                .prog_bldr(program_builder_cl)
                .device(device_cl)
                .dims([5])
                .build().unwrap();

    let vertex_buffer_cl: Buffer<f32> = Buffer::from_gl_buffer(&pq_cl,
                                            Some(core::MEM_READ_WRITE),
                                            [5],
                                            vertex_buffer.get_id()
                                        ).unwrap();

    // Acquire buffer
    vertex_buffer_cl.cmd().gl_acquire().enq().unwrap();

    // let kern = pq_cl.create_kernel("add_to_each").unwrap()
    //             .arg_scl(0.2)
    //             .arg_buf(&vertex_buffer_cl);

    // println!("Kernel global work size: {:?}", kern.get_gws());

    // Enqueue kernel:
    // kern.enq().unwrap();

    // result_buffer.read(&mut vec_result).enq().unwrap();

    // Release buffer
    // vertex_buffer_cl.cmd().gl_release().enq().unwrap();

    for event in display.wait_events() {
        let mut frame = display.draw();
        frame.clear_color(0.17, 0.17, 0.17, 1.0);
        frame.draw(&vertex_buffer, &indices, &program, &uniforms, &Default::default()).unwrap();
        frame.finish().unwrap();

        // println!("{:?}", event);

        match event {
            Event::Closed
            | Event::KeyboardInput(ElementState::Released, _, Some(VirtualKeyCode::Escape)) => break,
            _ => ()
        }
    }
}
<commit_msg>no crash kernel execution<commit_after>#[macro_use] extern crate glium;
extern crate ocl;
extern crate cgl;

use glium::{DisplayBuild, Surface, VertexBuffer, IndexBuffer, Program, GlObject};
use glium::index::{NoIndices, PrimitiveType};
use glium::glutin::{Event, ElementState, VirtualKeyCode};

const VERTEX_SRC: &'static str = include_str!("shaders/default.vert");
const FRAGMENT_SRC: &'static str = include_str!("shaders/default.frag");

use ocl::{util, core, ProQue, Buffer, Device, Platform, Queue, Context, Program as ProgramCl};
use ocl::core::{ContextProperties, DeviceType, DeviceInfo};
use ocl::builders::DeviceSpecifier;
use ocl::cl_h::CL_DEVICE_TYPE_GPU;

const KERNEL_SRC: &'static str = include_str!("kernels/test.cl");

use cgl::{CGLGetCurrentContext, CGLGetShareGroup};

#[derive(Copy, Clone, PartialEq, PartialOrd)]
struct Particle {
    position: [f32; 2],
    color: [f32; 3], // to delete
}

// struct ParticlePosition
// struct ParticleVelocity

implement_vertex!(Particle, position, color);

fn main() {
    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(1024, 768)
        .with_title(String::from("Hello world"))
        .build_glium()
        .unwrap();

    let vertex_buffer = VertexBuffer::dynamic(&display,
            &[
                Particle { position: [-0.5, -0.5], color: [0.0, 1.0, 0.0] },
                Particle { position: [ 0.0,  0.5], color: [0.0, 0.0, 1.0] },
                Particle { position: [ 0.5, -0.5], color: [1.0, 0.0, 0.0] },
            ]).unwrap();
    // let indices = NoIndices(PrimitiveType::Points);
    let indices = IndexBuffer::new(&display, PrimitiveType::TrianglesList, &[0u16, 1, 2]).unwrap();
    let program = Program::from_source(&display, VERTEX_SRC, FRAGMENT_SRC, None).unwrap();
    let uniforms = uniform! {
        matrix: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0f32]
        ]
    };

    let cgl_current_ctx = unsafe { CGLGetCurrentContext() };
    let cgl_share_grp = unsafe { CGLGetShareGroup(cgl_current_ctx) };
    let properties = ContextProperties::new().cgl_sharegroup(cgl_share_grp);

    let platform_cl = Platform::default();
    let device_type_cl = DeviceType::from_bits_truncate(CL_DEVICE_TYPE_GPU);
    let devices_cl = Device::list(&platform_cl, Some(device_type_cl));
    let device_cl = devices_cl.first().expect("No device with specified types found.");

    println!("device: {:?}", device_cl.info(DeviceInfo::Name));

    let context_cl = Context::builder()
                    .properties(properties)
                    .devices(DeviceSpecifier::Single(*device_cl))
                    .build().unwrap();

    let program_builder_cl = ProgramCl::builder().src(KERNEL_SRC);
    let pq_cl = ProQue::builder()
                .context(context_cl)
                .prog_bldr(program_builder_cl)
                .device(device_cl)
                .dims([5])
                .build().unwrap();

    let vertex_buffer_cl: Buffer<f32> = Buffer::from_gl_buffer(&pq_cl,
                                            Some(core::MEM_READ_WRITE),
                                            [5],
                                            vertex_buffer.get_id()
                                        ).unwrap();

    // Acquire buffer
    vertex_buffer_cl.cmd().gl_acquire().enq().unwrap();

    let kern = pq_cl.create_kernel("add_to_each").unwrap()
                .arg_buf(&vertex_buffer_cl)
                .arg_scl(2.0);

    println!("Kernel global work size: {:?}", kern.get_gws());

    // Enqueue kernel:
    kern.enq().unwrap();

    // Release buffer
    vertex_buffer_cl.cmd().gl_release().enq().unwrap();

    for event in display.wait_events() {
        let mut frame = display.draw();
        frame.clear_color(0.17, 0.17, 0.17, 1.0);
        frame.draw(&vertex_buffer, &indices, &program, &uniforms, &Default::default()).unwrap();
        frame.finish().unwrap();

        // println!("{:?}", event);

        match event {
            Event::Closed
            | Event::KeyboardInput(ElementState::Released, _, Some(VirtualKeyCode::Escape)) => break,
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>

fn main() {
    println!("Hello, world!");

}

pub enum Direction {
    Right,
    Left,
    Up,
    Down
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Board {
    rows: usize,
    cols: usize
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Position{ x: usize, y: usize }

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Snake {
    body: Vec<Position>
}

impl Snake {

    pub fn move_directions(&self, direction: Direction) -> Self {
        match direction {
            Direction::Left => {

                Snake {body: self.body.clone()}
            }
            Direction::Right => {
                let new_vec : Vec<Position> = self.body.clone();
                new_vec.last().cloned();

                Snake {body: new_vec}
            }
            Direction::Up => {
                let new_vec : Vec<Position> = self.body.clone();
                Snake {body: new_vec}
            }
            Direction::Down => {
                let new_vec : Vec<Position> = self.body.clone();
                Snake {body: new_vec}
            }

        }
    }

    fn new() -> Self {
        Snake { body: vec!(Position{ x:0, y: 0}) }
    }

}

<commit_msg>Apply Rustfmt<commit_after>

fn main() {
    println!("Hello, world!");

}

pub enum Direction {
    Right,
    Left,
    Up,
    Down,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Board {
    rows: usize,
    cols: usize,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Position {
    x: usize,
    y: usize,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Snake {
    body: Vec<Position>,
}

impl Snake {
    pub fn move_directions(&self, direction: Direction) -> Self {
        match direction {
            Direction::Left => Snake { body: self.body.clone() },
            Direction::Right => {
                let new_vec: Vec<Position> = self.body.clone();
                new_vec.last().cloned();

                Snake { body: new_vec }
            }
            Direction::Up => {
                let new_vec: Vec<Position> = self.body.clone();
                Snake { body: new_vec }
            }
            Direction::Down => {
                let new_vec: Vec<Position> = self.body.clone();
                Snake { body: new_vec }
            }

        }
    }

    fn new() -> Self {
        Snake { body: vec![Position { x: 0, y: 0 }] }
    }
}
<|endoftext|>


<commit_before>#![feature(old_io)]
use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("First, please answer to some questions...");
	println!("Please give us grid size :");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);
	println!("Your grid have now a size of {size}", size = grid_size);

	//game loop
	let mut turn : u32 = 0;

	loop {
		print_grid(&grid);
		if has_winner_path(&grid, 1) {
			println!("Congratulations, Player 1, you've won.");
			break;
		} else if has_winner_path(&grid, 2) {
			println!("Congratulations, Player 2, you've won.");
			break;
		}
		let player : u8 = (turn % 2) as u8 + 1;
		println!("It's your turn (turn {turn}), player {player}", turn = turn + 1, player = player);
		let position_x: u8;
		loop {
			println!("Give us X position");
			let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
			match grid_input.trim().parse::<u8>() {
					Ok(x) if x < grid_size => { position_x = x; break; },
					Ok(_) => {continue;},
					Err(_) => {continue;}
				};
		};
		let position_y: u8;
		loop {
			println!("Give us Y position");
			let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
			match grid_input.trim().parse::<u8>() {
					Ok(y) if y < grid_size => { position_y = y; break; },
					Ok(_) => {continue;},
					Err(_) => {continue;}
				};
		};
		if is_free_cell(&grid, position_x, position_y) {
			edit_grid(&mut grid, player, position_x, position_y);
			turn = turn + 1;
		} else {
			println!("This cell is not free");
		}
	}
}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::with_capacity(side_length as usize);
	for _ in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::with_capacity(side_length as usize);
		for _ in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn edit_grid(grid: &mut Vec<Vec<u8>>, new_value: u8, x: u8, y: u8) {
	grid[x as usize][y as usize] = new_value;
}

fn print_grid(grid: &Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {} ", match *y {
				0u8 => "-",
				1u8 => "B",
				2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}

fn is_free_cell(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> bool {
	if grid[x as usize][y as usize] == 0u8 { true } else { false }
}

fn has_winner_path(grid: &Vec<Vec<u8>>, player: u8) -> bool {
	for i in 0u8..grid.len() as u8 {
		let vector: Vec<[u8; 2]> = Vec::new();
		let is_win: bool = match player {
			1u8 => go_to_goal(&grid, player, 0, i, &vector),
			2u8 => go_to_goal(&grid, player, i, 0, &vector),
			_ => { panic!("Incorrect player for has_winner_path"); }
		};
		if is_win {
			return true;
		}
	}
	return false;
}

fn go_to_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, to_ignore: &Vec<[u8; 2]>) -> bool {
	if is_a_goal(&grid, player, x, y) {
		return true;
	}
	let mut to_ignore_cell = to_ignore.clone();
	to_ignore_cell.push([x, y]);

	let available_cells_close = not_visited_cells_close(&grid, player, x, y, &to_ignore_cell, true);

	for cell in available_cells_close.iter() {
		if go_to_goal(&grid, player, cell[0], cell[1], &to_ignore_cell) {
			return true;
		}
	}
	return false;
}

fn is_a_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8) -> bool{
	let max_index: u8 = grid.len() as u8 - 1;
	(player == 1 && x == max_index) || (player == 2 && y == max_index)
}

fn not_visited_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, visited: &Vec<[u8; 2]>, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = available_cells_close(&grid, player, x, y, focus_on_player);
	let mut not_visited_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	for cell in cells_close.iter() {
		if !has_pos_in_vector(&visited, *cell) {
			not_visited_cells_close.push(*cell);
		}
	}
	return not_visited_cells_close;
}

fn has_pos_in_vector(positions: &Vec<[u8; 2]>, search: [u8; 2]) -> bool {
	for pos in positions.iter() {
		if search == *pos {
			return true;
		}
	}
	return false;
}

fn revert_player(player: u8) -> u8 {
	if player == 1 { 2 } else if player == 2 { 1 } else { 0 }
}

fn available_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = cells_close(&grid, x, y);
	let mut available_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	let opp_player = revert_player(player);

	for cell in cells_close.iter() {
		let grid_value: u8 = grid[cell[0] as usize][cell[1] as usize];
		if (grid_value != opp_player && !focus_on_player) || (grid_value != opp_player && grid_value != 0)  {
			available_cells_close.push(*cell);
		}
	}
	return available_cells_close;
}

fn cells_close(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> Vec<[u8; 2]> {
	let mut cells_values: Vec<[u8; 2]> = Vec::with_capacity(8);
	let grid_length: u8 = grid.len() as u8;
	let relative_positions: [[i8; 2]; 8] = [
		[-1, -1],	[-1, 0],	[-1, 1],
		[0, -1], 	/*0,0*/		[0, 1],
		[1, -1],	[1, 0],		[1, 1]];
	for relative_position in relative_positions.iter() {
		let new_i_x = x as i8 + relative_position[0];
		if new_i_x < 0 || new_i_x >= grid_length as i8 {
			continue;
		}
		let new_x = new_i_x as u8;

		let new_i_y = y as i8 + relative_position[1];
		if new_i_y < 0 || new_i_y >= grid_length as i8 {
			continue;
		}
		let new_y = new_i_y as u8;
		cells_values.push([new_x, new_y]);
	}
	return cells_values;
}

/*************************/
#[test]
#[should_fail]
fn test_two_grids_shuffled_must_not_be_equals() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	assert_eq!(get_shuffled_free_cells(&grid), get_shuffled_free_cells(&grid));
}

#[test]
fn test_winned_game() {
	let mut grid1: Vec<Vec<u8>> = generate_grid(10u8);
	let mut grid2: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..10 {
		edit_grid(&mut grid1, 1, i, 0);
		edit_grid(&mut grid2, 2, 0, i);
	}
	assert!(has_winner_path(&grid1, 1));
	assert!(has_winner_path(&grid2, 2));
}

#[test]
#[should_fail]
fn test_not_winned_game() {
	let mut grid: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..grid.len() as u8 {
		edit_grid(&mut grid, i % 2 + 1, 0, i);
	}
	assert!(has_winner_path(&grid, 1));
	assert!(has_winner_path(&grid, 2));
}

#[test]
fn test_cells_close() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	//Corner left top, only 3 cells are available
	assert_eq!(cells_close(&grid, 0, 0).len(), 3);
	//Corner right bottom, only 3 cells are available
	assert_eq!(cells_close(&grid, 9, 9).len(), 3);
	//Corner close to center, 8 cells are available
	assert_eq!(cells_close(&grid, 4, 4).len(), 8);
}
<commit_msg>useful refactoring<commit_after>#![feature(old_io)]
use std::old_io;
//static ITERATIONS: u16 = 5000;
static DEFAULT_GRID: u8 = 10;

enum PlayerType {
	AI,
	Human
}

struct Player {
	name: String,
	num: u8,
	player_type: PlayerType
}

fn main() {
	let mut stdin = old_io::stdin();
	//Choose the grid size
	println!("First, please answer to some questions...");
	println!("Please give us grid size :");
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let grid_size: u8 = match grid_input.trim().parse::<u8>() {
			Ok(0) => DEFAULT_GRID,
			Ok(x) => x,
			Err(_) => DEFAULT_GRID
		};
	//Build the grid
	let mut grid: Vec<Vec<u8>> = generate_grid(grid_size);
	println!("Your grid have now a size of {size}", size = grid_size);

	let players: [Player; 2] = [get_a_player(&mut stdin, 1), get_a_player(&mut stdin, 2)];
	//game loop
	let mut turn : u32 = 0;

	loop {
		print_grid(&grid);
		if has_winner_path(&grid, 1) {
			println!("Congratulations, {}, you've won.", players[0].name);
			break;
		} else if has_winner_path(&grid, 2) {
			println!("Congratulations, {}, you've won.", players[1].name);
			break;
		}
		let player : &Player = &players[(turn % 2)  as usize];
		let player_status = match player.player_type {
			PlayerType::AI => "AI",
			PlayerType::Human => "Human"
		};
		println!("It's your turn (turn {turn}), {player} ({status})", turn = turn + 1, player = player.name, status = player_status);
		match player.player_type {
			PlayerType::AI => {
//				let position: [u8; 2] =
			},
			PlayerType::Human => {
				let position_x: u8 = get_a_position(&mut stdin, grid_size, "X".to_string());
				let position_y: u8 = get_a_position(&mut stdin, grid_size, "Y".to_string());
				if is_free_cell(&grid, position_x, position_y) {
					edit_grid(&mut grid, player.num, position_x, position_y);
					turn = turn + 1;
				} else {
					println!("This cell is not free");
				}
			}
		};
	}
}

fn get_a_player(stdin: &mut std::old_io::stdio::StdinReader, player_num: u8) -> Player {
	println!("Please, give us a name for player {}", player_num);
	let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
	let name = grid_input.trim();
	let player_type: PlayerType;
	loop {
		println!("{} will be human ? (yes/no)", name);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim() {
				"yes" => { player_type = PlayerType::Human; break; },
				"no" => { player_type = PlayerType::AI; break;},
				_ => {continue;}
			};
	};
	return Player { num: player_num, name: name.to_string(), player_type: player_type};
}

fn get_a_position(stdin: &mut std::old_io::stdio::StdinReader, max_value_plus_one: u8, axe: String) -> u8 {
	let position: u8;
	loop {
		println!("Give us {} position", axe);
		let grid_input = stdin.lock().lines().next().unwrap().ok().unwrap();
		match grid_input.trim().parse::<u8>() {
			Ok(x) if x < max_value_plus_one => { position = x; break; },
			Ok(_) => {continue;},
			Err(_) => {continue;}
		};
	};
	return position;
}

//For performances considerations, sides can't be > to 255.
fn generate_grid(side_length: u8) -> Vec<Vec<u8>> {
	let mut vector: Vec<Vec<u8>> = Vec::with_capacity(side_length as usize);
	for _ in 0..side_length {
		let mut vector_internal: Vec<u8> = Vec::with_capacity(side_length as usize);
		for _ in 0..side_length {
			vector_internal.push(0);
		}
		vector.push(vector_internal);
	}
	return vector;
}

fn edit_grid(grid: &mut Vec<Vec<u8>>, new_value: u8, x: u8, y: u8) {
	grid[x as usize][y as usize] = new_value;
}

fn print_grid(grid: &Vec<Vec<u8>>) {
	for x in grid.iter() {
		for y in x.iter() {
			print!(" {} ", match *y {
				0u8 => "-",
				1u8 => "B",
				2u8 => "W",
				_ => "E"
			});
		}
		print!("\n");
	}
}

fn is_free_cell(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> bool {
	if grid[x as usize][y as usize] == 0u8 { true } else { false }
}

fn has_winner_path(grid: &Vec<Vec<u8>>, player: u8) -> bool {
	for i in 0u8..grid.len() as u8 {
		let vector: Vec<[u8; 2]> = Vec::new();
		let is_win: bool = match player {
			1u8 => go_to_goal(&grid, player, 0, i, &vector),
			2u8 => go_to_goal(&grid, player, i, 0, &vector),
			_ => { panic!("Incorrect player for has_winner_path"); }
		};
		if is_win {
			return true;
		}
	}
	return false;
}

fn go_to_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, to_ignore: &Vec<[u8; 2]>) -> bool {
	if is_a_goal(&grid, player, x, y) {
		return true;
	}
	let mut to_ignore_cell = to_ignore.clone();
	to_ignore_cell.push([x, y]);

	let available_cells_close = not_visited_cells_close(&grid, player, x, y, &to_ignore_cell, true);

	for cell in available_cells_close.iter() {
		if go_to_goal(&grid, player, cell[0], cell[1], &to_ignore_cell) {
			return true;
		}
	}
	return false;
}

fn is_a_goal(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8) -> bool{
	let max_index: u8 = grid.len() as u8 - 1;
	(player == 1 && x == max_index) || (player == 2 && y == max_index)
}

fn not_visited_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, visited: &Vec<[u8; 2]>, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = available_cells_close(&grid, player, x, y, focus_on_player);
	let mut not_visited_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	for cell in cells_close.iter() {
		if !has_pos_in_vector(&visited, *cell) {
			not_visited_cells_close.push(*cell);
		}
	}
	return not_visited_cells_close;
}

fn has_pos_in_vector(positions: &Vec<[u8; 2]>, search: [u8; 2]) -> bool {
	for pos in positions.iter() {
		if search == *pos {
			return true;
		}
	}
	return false;
}

fn revert_player(player: u8) -> u8 {
	if player == 1 { 2 } else if player == 2 { 1 } else { 0 }
}

fn available_cells_close(grid: &Vec<Vec<u8>>, player: u8, x: u8, y: u8, focus_on_player: bool) -> Vec<[u8; 2]> {
	let cells_close: Vec<[u8; 2]> = cells_close(&grid, x, y);
	let mut available_cells_close: Vec<[u8; 2]> = Vec::with_capacity(cells_close.len());

	let opp_player = revert_player(player);

	for cell in cells_close.iter() {
		let grid_value: u8 = grid[cell[0] as usize][cell[1] as usize];
		if (grid_value != opp_player && !focus_on_player) || (grid_value != opp_player && grid_value != 0)  {
			available_cells_close.push(*cell);
		}
	}
	return available_cells_close;
}

fn cells_close(grid: &Vec<Vec<u8>>, x: u8, y: u8) -> Vec<[u8; 2]> {
	let mut cells_values: Vec<[u8; 2]> = Vec::with_capacity(8);
	let grid_length: u8 = grid.len() as u8;
	let relative_positions: [[i8; 2]; 8] = [
		[-1, -1],	[-1, 0],	[-1, 1],
		[0, -1], 	/*0,0*/		[0, 1],
		[1, -1],	[1, 0],		[1, 1]];
	for relative_position in relative_positions.iter() {
		let new_i_x = x as i8 + relative_position[0];
		if new_i_x < 0 || new_i_x >= grid_length as i8 {
			continue;
		}
		let new_x = new_i_x as u8;

		let new_i_y = y as i8 + relative_position[1];
		if new_i_y < 0 || new_i_y >= grid_length as i8 {
			continue;
		}
		let new_y = new_i_y as u8;
		cells_values.push([new_x, new_y]);
	}
	return cells_values;
}

/*************************/
#[test]
#[should_fail]
fn test_two_grids_shuffled_must_not_be_equals() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	assert_eq!(get_shuffled_free_cells(&grid), get_shuffled_free_cells(&grid));
}

#[test]
fn test_winned_game() {
	let mut grid1: Vec<Vec<u8>> = generate_grid(10u8);
	let mut grid2: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..10 {
		edit_grid(&mut grid1, 1, i, 0);
		edit_grid(&mut grid2, 2, 0, i);
	}
	assert!(has_winner_path(&grid1, 1));
	assert!(has_winner_path(&grid2, 2));
}

#[test]
#[should_fail]
fn test_not_winned_game() {
	let mut grid: Vec<Vec<u8>> = generate_grid(10u8);
	for i in 0u8..grid.len() as u8 {
		edit_grid(&mut grid, i % 2 + 1, 0, i);
	}
	assert!(has_winner_path(&grid, 1));
	assert!(has_winner_path(&grid, 2));
}

#[test]
fn test_cells_close() {
	let grid: Vec<Vec<u8>> = generate_grid(10u8);
	//Corner left top, only 3 cells are available
	assert_eq!(cells_close(&grid, 0, 0).len(), 3);
	//Corner right bottom, only 3 cells are available
	assert_eq!(cells_close(&grid, 9, 9).len(), 3);
	//Corner close to center, 8 cells are available
	assert_eq!(cells_close(&grid, 4, 4).len(), 8);
}
<|endoftext|>