<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate gnuplot;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::hash::Hash;
use rustc_serialize::*;

use std::env;

use std::path::Path;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::io::Result;

use std::fs::DirEntry;
use std::u64;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn write_stats<K: Hash + Eq + Encodable, V: Encodable>(name : &'static str, counts : &HashMap<K,V>) -> std::io::Result<()> {
  let mut f = try!(File::create(name));
  try!(f.write_all(json::encode(&counts).unwrap().as_bytes()));
  Ok(())
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_size_frequencies: HashMap<u64, u64> = HashMap::new();
  let mut arxiv_monthly_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    println!("-- Measuring {:?}", month_dir.file_name().to_str().unwrap());
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir) / 1024; // In KB
      if paper_size > max_size {
        max_size = paper_size;
      }
      if paper_size < min_size {
        min_size = paper_size;
      }
      monthly_size += paper_size;

      let size_frequency = arxiv_size_frequencies.entry(paper_size).or_insert(0);
      *size_frequency += 1;
    }
    arxiv_monthly_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats
  match write_stats("arxiv_submission_counts.json", &arxiv_counts) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_monthly_sizes.json", &arxiv_monthly_sizes) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_size_frequencies.json", &arxiv_size_frequencies) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission counts by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_monthly_sizes.get(&m.to_string()) {
        Some(&counts) => counts,
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes by month", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

  // Plot average paper size in KB
  // Plot of submission size by month:

  let freq_keys = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.0);
  let freq_values = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.1);

  fg = Figure::new();
  fg.axes2d()
  .points(freq_keys, freq_values, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("Paper size in KB", &[Rotate(45.0)])
  .set_y_label("Paper count", &[Rotate(90.0)])
  .set_title("arXiv TeX paper sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_paper_sizes.png");
  fg.show();

}<commit_msg>mercury tweaks to arxiv_stats<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate gnuplot;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::hash::Hash;
use rustc_serialize::*;

use std::env;

use std::path::Path;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::io::Result;

use std::fs::DirEntry;
use std::u64;

use gnuplot::*;

fn get_dir_size(direntry: &DirEntry) -> u64 {
  // Initialize with the size of the current directory
  let mut size = direntry.metadata().unwrap().len();
  // Sum up the current file children
  for subfile in get_subfiles(direntry).iter() {
    let subfile_size = subfile.metadata().unwrap().len();
    size += subfile_size;
  }
  // And recurse into subdirectories
  for subdir in get_subdirs(direntry).iter() {
    size += get_dir_size(subdir); }
  size
}

fn is_dir(direntry : &DirEntry) -> bool {
  let metadata = direntry.metadata();
  return match metadata {
    Err(_) => false,
    Ok(metadata) => metadata.is_dir()
  }
}

fn get_subdirs(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subdirs(direntry.path().as_path())
}
fn get_subfiles(direntry : &DirEntry) -> Vec<DirEntry> {
  get_path_subfiles(direntry.path().as_path())
}

fn get_path_subdirs(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| is_dir(c)).collect::<Vec<_>>()
}
fn get_path_subfiles(path : &Path) -> Vec<DirEntry> {
  let children = fs::read_dir(path).unwrap();
  let children_entries = children.map(|c| c.unwrap()).collect::<Vec<_>>();
  children_entries.into_iter().filter(|c| !is_dir(c)).collect::<Vec<_>>()
}

fn write_stats<K: Hash + Eq + Encodable, V: Encodable>(name : &'static str, counts : &HashMap<K,V>) -> std::io::Result<()> {
  let mut f = try!(File::create(name));
  try!(f.write_all(json::encode(&counts).unwrap().as_bytes()));
  Ok(())
}

fn main() {
  let args: Vec<_> = env::args().collect();
  let mut min_size = u64::MAX;
  let mut max_size = 0;
  let mut max_path : String = "".to_string();
  let mut min_path : String = "".to_string();

  let arxiv_root = &Path::new(&args[1]);
  let mut arxiv_size_frequencies: HashMap<u64, u64> = HashMap::new();
  let mut arxiv_monthly_sizes: HashMap<String, u64> = HashMap::new();
  let mut arxiv_counts: HashMap<String, u64> = HashMap::new();
  let arxiv_month_dirs = get_path_subdirs(arxiv_root);

  for month_dir in arxiv_month_dirs.iter() {
    println!("-- Measuring {:?}", month_dir.file_name().to_str().unwrap());
    let mut monthly_size = 0;
    let month_papers = get_subdirs(month_dir);
    // Record how many papers were submitted in that month
    arxiv_counts.insert(month_dir.file_name().to_str().unwrap().to_string(), month_papers.len() as u64);

    for paper_dir in month_papers.iter() {
      // Record the size of each paper directory
      let paper_size = get_dir_size(paper_dir) / 1024; // In KB
      if paper_size > max_size {
        max_size = paper_size;
	max_path = paper_dir.path().to_str().unwrap().to_string();
      }
      if paper_size < min_size {
        min_size = paper_size;
        min_path = paper_dir.path().to_str().unwrap().to_string();
      }
      monthly_size += paper_size;

      let size_frequency = arxiv_size_frequencies.entry(paper_size).or_insert(0);
      *size_frequency += 1;
    }
    arxiv_monthly_sizes.insert(month_dir.file_name().to_str().unwrap().to_string(), monthly_size);
  }

  // Print the recorded stats
  match write_stats("arxiv_submission_counts.json", &arxiv_counts) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_monthly_sizes.json", &arxiv_monthly_sizes) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  match write_stats("arxiv_size_frequencies.json", &arxiv_size_frequencies) {
    Ok(_) => {},
    Err(e) => println!("{:?}", e)
  };

  let mut f4 = File::create("arxiv_stats.txt").unwrap();
  f4.write_all(b"Min size: \n");
  f4.write_all(min_size.to_string().as_bytes());
  f4.write_all(b"\nMin path: \n");
  f4.write_all(min_path.as_bytes());
  f4.write_all(b"\nMax size: \n");
  f4.write_all(max_size.to_string().as_bytes());
  f4.write_all(b"\nMax path: \n");
  f4.write_all(max_path.as_bytes());

  // arXiv months in order
  // TODO: Only current as of 1505, you'll have to extend manually next time this is run
  let ordered_months = [
    "9107", "9108", "9109", "9110", "9111", "9112", "9201", "9202", "9203", "9204", "9205", "9206", "9207", "9208", "9209",
    "9210", "9211", "9212", "9301", "9302", "9303", "9304", "9305", "9306", "9307", "9308", "9309", "9310", "9311", "9312",
    "9401", "9402", "9403", "9404", "9405", "9406", "9407", "9408", "9409", "9410", "9411", "9412", "9501", "9502", "9503",
    "9504", "9505", "9506", "9507", "9508", "9509", "9510", "9511", "9512", "9601", "9602", "9603", "9604", "9605", "9606",
    "9607", "9608", "9609", "9610", "9611", "9612", "9701", "9702", "9703", "9704", "9705", "9706", "9707", "9708", "9709",
    "9710", "9711", "9712", "9801", "9802", "9803", "9804", "9805", "9806", "9807", "9808", "9809", "9810", "9811", "9812",
    "9901", "9902", "9903", "9904", "9905", "9906", "9907", "9908", "9909", "9910", "9911", "9912", "0001", "0002", "0003",
    "0004", "0005", "0006", "0007", "0008", "0009", "0010", "0011", "0012", "0101", "0102", "0103", "0104", "0105", "0106",
    "0107", "0108", "0109", "0110", "0111", "0112", "0201", "0202", "0203", "0204", "0205", "0206", "0207", "0208", "0209",
    "0210", "0211", "0212", "0301", "0302", "0303", "0304", "0305", "0306", "0307", "0308", "0309", "0310", "0311", "0312",
    "0401", "0402", "0403", "0404", "0405", "0406", "0407", "0408", "0409", "0410", "0411", "0412", "0501", "0502", "0503",
    "0504", "0505", "0506", "0507", "0508", "0509", "0510", "0511", "0512", "0601", "0602", "0603", "0604", "0605", "0606",
    "0607", "0608", "0609", "0610", "0611", "0612", "0701", "0702", "0703", "0704", "0705", "0706", "0707", "0708", "0709",
    "0710", "0711", "0712", "0801", "0802", "0803", "0804", "0805", "0806", "0807", "0808", "0809", "0810", "0811", "0812",
    "0901", "0902", "0903", "0904", "0905", "0906", "0907", "0908", "0909", "0910", "0911", "0912", "1001", "1002", "1003",
    "1004", "1005", "1006", "1007", "1008", "1009", "1010", "1011", "1012", "1101", "1102", "1103", "1104", "1105", "1106",
    "1107", "1108", "1109", "1110", "1111", "1112", "1201", "1202", "1203", "1204", "1205", "1206", "1207", "1208", "1209",
    "1210", "1211", "1212", "1301", "1302", "1303", "1304", "1305", "1306", "1307", "1308", "1309", "1310", "1311", "1312",
    "1401", "1402", "1403", "1404", "1405", "1406", "1407", "1408", "1409", "1410", "1411", "1412", "1501", "1502", "1503",
    "1504", "1505"];

  // Plot of paper counts by month:
  let zero = 0 as u64;
  let ordered_counts = ordered_months.iter().map(|m|
    match arxiv_counts.get(&m.to_string()) {
        Some(counts) => counts,
        None => &zero
    });
  let ordered_month_xcoords = 1..ordered_months.len()+1;

  let mut fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_counts, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submitted papers", &[Rotate(90.0)])
  .set_title("arXiv TeX submission counts", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_counts.png");
  fg.show();

  // Plot of submission counts by month:
  let ordered_sizes = ordered_months.iter().map(|m|
    match arxiv_monthly_sizes.get(&m.to_string()) {
        Some(&counts) => counts,
        None => zero
    });
  fg = Figure::new();
  fg.axes2d()
  .points(ordered_month_xcoords.clone(), ordered_sizes, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("arXiv month", &[Rotate(45.0)])
  .set_y_label("Submission size in MB", &[Rotate(90.0)])
  .set_title("arXiv TeX submission sizes by month", &[]);

  fg.set_terminal("pngcairo", "arxiv_submission_sizes.png");
  fg.show();

  // Plot average paper size in KB
  // Plot of submission size by month:

  let freq_keys = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.0);
  let freq_values = arxiv_size_frequencies.clone().into_iter().map(|entry| entry.1);

  fg = Figure::new();
  fg.axes2d()
  .points(freq_keys, freq_values, &[PointSymbol('D'), Color("#ffaa77"), PointSize(0.5)])
  .set_x_label("Paper size in KB", &[Rotate(45.0)])
  .set_y_label("Paper count", &[Rotate(90.0)])
  .set_title("arXiv TeX paper sizes", &[]);

  fg.set_terminal("pngcairo", "arxiv_paper_sizes.png");
  fg.show();

}<|endoftext|>


<commit_before>//! A window implemented by SDL2 back-end.

// External crates.
use std::mem::transmute;
use gl;
use gfx;
use device;
use sdl2;
use piston::{
    GameWindow,
    GameWindowSettings,
    game_window,
    keyboard,
    mouse,
};
use shader_version::opengl::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct GameWindowSDL2 {
    /// SDL window handle
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    settings: GameWindowSettings,
    should_close: bool,
    last_pressed_key: Option<sdl2::keycode::KeyCode>,
}

impl GameWindowSDL2 {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: GameWindowSettings) -> GameWindowSDL2 {
        sdl2::init(sdl2::InitEverything);
        let (major, minor) = opengl.get_major_minor();
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, major);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, minor);
        sdl2::video::gl_set_attribute(
            sdl2::video::GLContextProfileMask,
            sdl2::video::ll::SDL_GL_CONTEXT_PROFILE_CORE as int
        );

        let window = sdl2::video::Window::new(
            settings.title.as_slice(),
            sdl2::video::PosCentered,
            sdl2::video::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OpenGL | sdl2::video::Resizable
        ).unwrap();
        if settings.fullscreen {
            window.set_fullscreen(sdl2::video::FTTrue);
        }

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });

        GameWindowSDL2 {
            settings: settings,
            should_close: false,
            last_pressed_key: None,
            window: window,
            context: context,
        }
    }

    /// Creates a gfx devince and front end.
    pub fn gfx(&self) -> (device::GlDevice, gfx::Frame) {
        let device = device::GlDevice::new(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl GameWindow for GameWindowSDL2 {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_drawable_size();
        (w as u32, h as u32)
    }

    fn close(&mut self) {
        self.should_close = true;
    }

    fn swap_buffers(&self) {
        self.window.gl_swap_window();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        sdl2::mouse::set_relative_mouse_mode(enabled)
    }

    fn poll_event(&mut self) -> game_window::Event {
        match sdl2::event::poll_event() {
            sdl2::event::QuitEvent(_) => { self.should_close = true; },
            sdl2::event::KeyDownEvent(_, _, key, _, _) => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                match self.last_pressed_key {
                    Some(x) if x == key => return self.poll_event(),
                    _ => {},
                };
                self.last_pressed_key = Some(key);

                if self.settings.exit_on_esc
                && key == sdl2::keycode::EscapeKey {
                    self.should_close = true;
                } else {
                    return game_window::KeyPressed(sdl2_map_key(key));
                }
            },
            sdl2::event::KeyUpEvent(_, _, key, _, _) => {
                // Reset the last pressed key.
                self.last_pressed_key = match self.last_pressed_key {
                    Some(x) if x == key => None,
                    x => x,
                };

                return game_window::KeyReleased(sdl2_map_key(key));
            },
            sdl2::event::MouseButtonDownEvent(_, _, _, button, _, _) => {
                return game_window::MouseButtonPressed(sdl2_map_mouse(button));
            },
            sdl2::event::MouseButtonUpEvent(_, _, _, button, _, _) => {
                return game_window::MouseButtonReleased(sdl2_map_mouse(button));
            },
            sdl2::event::MouseMotionEvent(_, _, _, _, x, y, dx, dy) => {
                return game_window::MouseMoved(
                    x as f64,
                    y as f64,
                    Some((dx as f64, dy as f64))
                );
            },
            sdl2::event::MouseWheelEvent(_, _, _, x, y) => {
                return game_window::MouseScrolled(x as f64, y as f64);
            },
            _ => {},
        }
        game_window::NoEvent
    }
}

pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode.code() as u64).unwrap()
}

pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> mouse::Button {
    match button {
        sdl2::mouse::LeftMouse => mouse::Left,
        sdl2::mouse::RightMouse => mouse::Right,
        sdl2::mouse::MiddleMouse => mouse::Middle,
        sdl2::mouse::X1Mouse => mouse::X1,
        sdl2::mouse::X2Mouse => mouse::X2,
        sdl2::mouse::UnknownMouse(_) => mouse::Unknown,
    }
}

<commit_msg>Release captured cursor<commit_after>//! A window implemented by SDL2 back-end.

// External crates.
use std::mem::transmute;
use gl;
use gfx;
use device;
use sdl2;
use piston::{
    GameWindow,
    GameWindowSettings,
    game_window,
    keyboard,
    mouse,
};
use shader_version::opengl::OpenGL;

/// A widow implemented by SDL2 back-end.
pub struct GameWindowSDL2 {
    /// SDL window handle
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    settings: GameWindowSettings,
    should_close: bool,
    last_pressed_key: Option<sdl2::keycode::KeyCode>,
}

impl GameWindowSDL2 {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: GameWindowSettings) -> GameWindowSDL2 {
        sdl2::init(sdl2::InitEverything);
        let (major, minor) = opengl.get_major_minor();
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, major);
        sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, minor);
        sdl2::video::gl_set_attribute(
            sdl2::video::GLContextProfileMask,
            sdl2::video::ll::SDL_GL_CONTEXT_PROFILE_CORE as int
        );

        let window = sdl2::video::Window::new(
            settings.title.as_slice(),
            sdl2::video::PosCentered,
            sdl2::video::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OpenGL | sdl2::video::Resizable
        ).unwrap();
        if settings.fullscreen {
            window.set_fullscreen(sdl2::video::FTTrue);
        }

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });

        GameWindowSDL2 {
            settings: settings,
            should_close: false,
            last_pressed_key: None,
            window: window,
            context: context,
        }
    }

    /// Creates a gfx devince and front end.
    pub fn gfx(&self) -> (device::GlDevice, gfx::Frame) {
        let device = device::GlDevice::new(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl Drop for GameWindowSDL2 {
    fn drop(&mut self) {
        self.capture_cursor(false);
    }
}

impl GameWindow for GameWindowSDL2 {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.should_close
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_drawable_size();
        (w as u32, h as u32)
    }

    fn close(&mut self) {
        self.should_close = true;
    }

    fn swap_buffers(&self) {
        self.window.gl_swap_window();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        sdl2::mouse::set_relative_mouse_mode(enabled)
    }

    fn poll_event(&mut self) -> game_window::Event {
        match sdl2::event::poll_event() {
            sdl2::event::QuitEvent(_) => { self.should_close = true; },
            sdl2::event::KeyDownEvent(_, _, key, _, _) => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                match self.last_pressed_key {
                    Some(x) if x == key => return self.poll_event(),
                    _ => {},
                };
                self.last_pressed_key = Some(key);

                if self.settings.exit_on_esc
                && key == sdl2::keycode::EscapeKey {
                    self.should_close = true;
                } else {
                    return game_window::KeyPressed(sdl2_map_key(key));
                }
            },
            sdl2::event::KeyUpEvent(_, _, key, _, _) => {
                // Reset the last pressed key.
                self.last_pressed_key = match self.last_pressed_key {
                    Some(x) if x == key => None,
                    x => x,
                };

                return game_window::KeyReleased(sdl2_map_key(key));
            },
            sdl2::event::MouseButtonDownEvent(_, _, _, button, _, _) => {
                return game_window::MouseButtonPressed(sdl2_map_mouse(button));
            },
            sdl2::event::MouseButtonUpEvent(_, _, _, button, _, _) => {
                return game_window::MouseButtonReleased(sdl2_map_mouse(button));
            },
            sdl2::event::MouseMotionEvent(_, _, _, _, x, y, dx, dy) => {
                return game_window::MouseMoved(
                    x as f64,
                    y as f64,
                    Some((dx as f64, dy as f64))
                );
            },
            sdl2::event::MouseWheelEvent(_, _, _, x, y) => {
                return game_window::MouseScrolled(x as f64, y as f64);
            },
            _ => {},
        }
        game_window::NoEvent
    }
}

pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode.code() as u64).unwrap()
}

pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> mouse::Button {
    match button {
        sdl2::mouse::LeftMouse => mouse::Left,
        sdl2::mouse::RightMouse => mouse::Right,
        sdl2::mouse::MiddleMouse => mouse::Middle,
        sdl2::mouse::X1Mouse => mouse::X1,
        sdl2::mouse::X2Mouse => mouse::X2,
        sdl2::mouse::UnknownMouse(_) => mouse::Unknown,
    }
}

<|endoftext|>


<commit_before>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::io;
use std::sync::mpsc;
use std::thread;

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event),
    ScheduleMessageDelivery(Address, TextMessage)
}

#[derive(Debug)]
pub enum ScheduledTask {
    DeliverMessage(Address, TextMessage),
}

pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new()
        }
    }

    pub fn run(mut self, mut network: network::Network, headless: bool) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();
        let sender = self.address;

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        thread::spawn(move || event_loop.run(&mut self).unwrap());

        info!("Running client at {}", sender);

        if headless {
            loop { thread::park(); }
        } else {
            loop {
                let mut line = String::new();
                io::stdin().read_line(&mut line).unwrap();
                let parts: Vec<&str> = line.splitn(2, ' ').collect();
                let recipient = Address::from_str(parts[0]);
                let message_text = parts[1].trim().to_string();

                let text_message = TextMessage::new(sender, message_text);
                notify_channel
                    .send(Task::ScheduleMessageDelivery(recipient, text_message))
                    .unwrap_or_else(|err| info!("Couldn't schedule message delivery: {:?}", err));
            }
        }
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope.clone();

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if !self.received.contains(&text_message.id) {
                            self.received.insert(text_message.id);
                            if recipient == self.address {
                                println!("{}: {}", text_message.sender, text_message.text);
                                let ack = MessageAcknowledgement::new(text_message.id);
                                self.deliver_acknowledgement(text_message.sender, ack, event_loop);
                            } else {
                                if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                    self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                    self.acknowledgements.insert(text_message.id, ack);
                                } else {
                                    self.schedule_message_delivery(recipient, text_message, event_loop);
                                }
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                            if recipient == self.address {
                                debug!("ack {}", ack.message_id);
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<commit_msg>Always cancel pending delivers upon recv ack<commit_after>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::io;
use std::sync::mpsc;
use std::thread;

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event),
    ScheduleMessageDelivery(Address, TextMessage)
}

#[derive(Debug)]
pub enum ScheduledTask {
    DeliverMessage(Address, TextMessage),
}

pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new()
        }
    }

    pub fn run(mut self, mut network: network::Network, headless: bool) {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();
        let sender = self.address;

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        thread::spawn(move || event_loop.run(&mut self).unwrap());

        info!("Running client at {}", sender);

        if headless {
            loop { thread::park(); }
        } else {
            loop {
                let mut line = String::new();
                io::stdin().read_line(&mut line).unwrap();
                let parts: Vec<&str> = line.splitn(2, ' ').collect();
                let recipient = Address::from_str(parts[0]);
                let message_text = parts[1].trim().to_string();

                let text_message = TextMessage::new(sender, message_text);
                notify_channel
                    .send(Task::ScheduleMessageDelivery(recipient, text_message))
                    .unwrap_or_else(|err| info!("Couldn't schedule message delivery: {:?}", err));
            }
        }
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope.clone();

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if !self.received.contains(&text_message.id) {
                            self.received.insert(text_message.id);
                            if recipient == self.address {
                                println!("{}: {}", text_message.sender, text_message.text);
                                let ack = MessageAcknowledgement::new(text_message.id);
                                self.deliver_acknowledgement(text_message.sender, ack, event_loop);
                            } else {
                                if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                    self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                    self.acknowledgements.insert(text_message.id, ack);
                                } else {
                                    self.schedule_message_delivery(recipient, text_message, event_loop);
                                }
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            if recipient == self.address {
                                debug!("ack {}", ack.message_id);
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<|endoftext|>


<commit_before>//! A simple, thread-safe, and async-friendly IRC client library.

pub mod conn;
pub mod data;
pub mod server;
pub mod transport;

pub mod prelude {
    //! A client-side IRC prelude, re-exporting all the necessary basics.
    pub use client::data::Config;
    pub use client::server::{EachIncomingExt, IrcServer, Server};
    pub use client::server::utils::ServerExt;
    pub use proto::{Capability, ChannelExt, Command, Message, NegotiationVersion, Response};
    pub use proto::{ChannelMode, Mode, UserMode};

    pub use futures::{Future, Stream};
}
<commit_msg>Added a bunch of detail about the high-level client API to the prelude.<commit_after>//! A simple, thread-safe, and async-friendly IRC client library.

pub mod conn;
pub mod data;
pub mod server;
pub mod transport;

pub mod prelude {
    //! A client-side IRC prelude, re-exporting the complete high-level IRC client API.
    //!
    //! # Structure
    //! A connection to an IRC server is represented by an `IrcServer` which is configured using a
    //! `Config` struct that defines data such as which server to connect to, on what port, and
    //! using what nickname. The `Server` trait provides an API for actually interacting with the
    //! server once a connection has been established. This API intentionally offers only a single
    //! method to send `Commands` because it makes it easy to see the whole set of possible
    //! interactions with a server. The `ServerExt` trait addresses this deficiency by defining a
    //! number of methods that provide a more clear and succinct interface for sending various
    //! common IRC commands to the server.
    //!
    //! The various `proto` types capture details of the IRC protocol that are used throughout the
    //! client API. `Message`, `Command`, and `Response` are used to send and receive messages along
    //! the connection, and are naturally at the heart of communication in the IRC protocol.
    //! `Capability` and `NegotiationVersion` are used to determine (with the server) what IRCv3
    //! functionality to enable for the connection. Certain parts of the API offer suggestions for
    //! extensions that will improve the user experience, and give examples of how to enable them
    //! using `Capability`. `Mode`, `ChannelMode`, and `UserMode` are used in a high-level API for
    //! dealing with IRC channel and user modes. They appear in methods for sending mode commands,
    //! as well as in the parsed form of received mode commands.

    pub use client::data::Config;
    pub use client::server::{EachIncomingExt, IrcServer, Server};
    pub use client::server::utils::ServerExt;
    pub use proto::{Capability, ChannelExt, Command, Message, NegotiationVersion, Response};
    pub use proto::{ChannelMode, Mode, UserMode};

    pub use futures::{Future, Stream};
}
<|endoftext|>


<commit_before>/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
/// that only the name of the flag value has to be given.
///
/// The `libc` crate must be in scope with the name `libc`.
///
/// # Example
/// ```
/// libc_bitflags!{
///     pub struct ProtFlags: libc::c_int {
///         PROT_NONE;
///         PROT_READ;
///         /// PROT_WRITE enables write protect
///         PROT_WRITE;
///         PROT_EXEC;
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSDOWN;
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSUP;
///     }
/// }
/// ```
///
/// Example with casting, due to a mistake in libc. In this example, the
/// various flags have different types, so we cast the broken ones to the right
/// type.
///
/// ```
/// libc_bitflags!{
///     pub struct SaFlags: libc::c_ulong {
///         SA_NOCLDSTOP as libc::c_ulong;
///         SA_NOCLDWAIT;
///         SA_NODEFER as libc::c_ulong;
///         SA_ONSTACK;
///         SA_RESETHAND as libc::c_ulong;
///         SA_RESTART as libc::c_ulong;
///         SA_SIGINFO;
///     }
/// }
/// ```
macro_rules! libc_bitflags {
    (
        $(#[$outer:meta])*
        pub struct $BitFlags:ident: $T:ty {
            $(
                $(#[$inner:ident $($args:tt)*])*
                $Flag:ident $(as $cast:ty)*;
            )+
        }
    ) => {
        bitflags! {
            $(#[$outer])*
            pub struct $BitFlags: $T {
                $(
                    $(#[$inner $($args)*])*
                    const $Flag = libc::$Flag $(as $cast)*;
                )+
            }
        }
    };
}

/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
/// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
///
/// The `libc` crate must be in scope with the name `libc`.
///
/// # Example
/// ```
/// libc_enum!{
///     pub enum ProtFlags {
///         PROT_NONE,
///         PROT_READ,
///         PROT_WRITE,
///         PROT_EXEC,
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSDOWN,
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSUP,
///     }
/// }
/// ```
macro_rules! libc_enum {
    // (non-pub) Exit rule.
    (@make_enum
        {
            name: $BitFlags:ident,
            attrs: [$($attrs:tt)*],
            entries: [$($entries:tt)*],
        }
    ) => {
        $($attrs)*
        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        enum $BitFlags {
            $($entries)*
        }
    };

    // (pub) Exit rule.
    (@make_enum
        {
            pub,
            name: $BitFlags:ident,
            attrs: [$($attrs:tt)*],
            entries: [$($entries:tt)*],
        }
    ) => {
        $($attrs)*
        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        pub enum $BitFlags {
            $($entries)*
        }
    };

    // (non-pub) Done accumulating.
    (@accumulate_entries
        {
            name: $BitFlags:ident,
            attrs: $attrs:tt,
        },
        $entries:tt;
    ) => {
        libc_enum! {
            @make_enum
            {
                name: $BitFlags,
                attrs: $attrs,
                entries: $entries,
            }
        }
    };

    // (pub) Done accumulating.
    (@accumulate_entries
        {
            pub,
            name: $BitFlags:ident,
            attrs: $attrs:tt,
        },
        $entries:tt;
    ) => {
        libc_enum! {
            @make_enum
            {
                pub,
                name: $BitFlags,
                attrs: $attrs,
                entries: $entries,
            }
        }
    };

    // Munch an attr.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        #[$attr:meta] $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                #[$attr]
            ];
            $($tail)*
        }
    };

    // Munch last ident if not followed by a comma.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry,
            ];
        }
    };

    // Munch an ident; covers terminating comma case.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident, $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry,
            ];
            $($tail)*
        }
    };

    // Munch an ident and cast it to the given type; covers terminating comma.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident as $ty:ty, $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry as $ty,
            ];
            $($tail)*
        }
    };

    // (non-pub) Entry rule.
    (
        $(#[$attr:meta])*
        enum $BitFlags:ident {
            $($vals:tt)*
        }
    ) => {
        libc_enum! {
            @accumulate_entries
            {
                name: $BitFlags,
                attrs: [$(#[$attr])*],
            },
            [];
            $($vals)*
        }
    };

    // (pub) Entry rule.
    (
        $(#[$attr:meta])*
        pub enum $BitFlags:ident {
            $($vals:tt)*
        }
    ) => {
        libc_enum! {
            @accumulate_entries
            {
                pub,
                name: $BitFlags,
                attrs: [$(#[$attr])*],
            },
            [];
            $($vals)*
        }
    };
}

/// A Rust version of the familiar C `offset_of` macro.  It returns the byte
/// offset of `field` within struct `ty`
macro_rules! offset_of {
    ($ty:ty, $field:ident) => {
        &(*(ptr::null() as *const $ty)).$field as *const _ as usize
    }
}
<commit_msg>Simplify implementation of libc_enum! with vis metavariables<commit_after>/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
/// that only the name of the flag value has to be given.
///
/// The `libc` crate must be in scope with the name `libc`.
///
/// # Example
/// ```
/// libc_bitflags!{
///     pub struct ProtFlags: libc::c_int {
///         PROT_NONE;
///         PROT_READ;
///         /// PROT_WRITE enables write protect
///         PROT_WRITE;
///         PROT_EXEC;
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSDOWN;
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSUP;
///     }
/// }
/// ```
///
/// Example with casting, due to a mistake in libc. In this example, the
/// various flags have different types, so we cast the broken ones to the right
/// type.
///
/// ```
/// libc_bitflags!{
///     pub struct SaFlags: libc::c_ulong {
///         SA_NOCLDSTOP as libc::c_ulong;
///         SA_NOCLDWAIT;
///         SA_NODEFER as libc::c_ulong;
///         SA_ONSTACK;
///         SA_RESETHAND as libc::c_ulong;
///         SA_RESTART as libc::c_ulong;
///         SA_SIGINFO;
///     }
/// }
/// ```
macro_rules! libc_bitflags {
    (
        $(#[$outer:meta])*
        pub struct $BitFlags:ident: $T:ty {
            $(
                $(#[$inner:ident $($args:tt)*])*
                $Flag:ident $(as $cast:ty)*;
            )+
        }
    ) => {
        bitflags! {
            $(#[$outer])*
            pub struct $BitFlags: $T {
                $(
                    $(#[$inner $($args)*])*
                    const $Flag = libc::$Flag $(as $cast)*;
                )+
            }
        }
    };
}

/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
/// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
///
/// The `libc` crate must be in scope with the name `libc`.
///
/// # Example
/// ```
/// libc_enum!{
///     pub enum ProtFlags {
///         PROT_NONE,
///         PROT_READ,
///         PROT_WRITE,
///         PROT_EXEC,
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSDOWN,
///         #[cfg(any(target_os = "linux", target_os = "android"))]
///         PROT_GROWSUP,
///     }
/// }
/// ```
macro_rules! libc_enum {
    // Exit rule.
    (@make_enum
        {
            $v:vis
            name: $BitFlags:ident,
            attrs: [$($attrs:tt)*],
            entries: [$($entries:tt)*],
        }
    ) => {
        $($attrs)*
        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        $v enum $BitFlags {
            $($entries)*
        }
    };

    // Done accumulating.
    (@accumulate_entries
        {
            $v:vis
            name: $BitFlags:ident,
            attrs: $attrs:tt,
        },
        $entries:tt;
    ) => {
        libc_enum! {
            @make_enum
            {
                $v
                name: $BitFlags,
                attrs: $attrs,
                entries: $entries,
            }
        }
    };

    // Munch an attr.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        #[$attr:meta] $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                #[$attr]
            ];
            $($tail)*
        }
    };

    // Munch last ident if not followed by a comma.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry,
            ];
        }
    };

    // Munch an ident; covers terminating comma case.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident, $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry,
            ];
            $($tail)*
        }
    };

    // Munch an ident and cast it to the given type; covers terminating comma.
    (@accumulate_entries
        $prefix:tt,
        [$($entries:tt)*];
        $entry:ident as $ty:ty, $($tail:tt)*
    ) => {
        libc_enum! {
            @accumulate_entries
            $prefix,
            [
                $($entries)*
                $entry = libc::$entry as $ty,
            ];
            $($tail)*
        }
    };

    // Entry rule.
    (
        $(#[$attr:meta])*
        $v:vis enum $BitFlags:ident {
            $($vals:tt)*
        }
    ) => {
        libc_enum! {
            @accumulate_entries
            {
                $v
                name: $BitFlags,
                attrs: [$(#[$attr])*],
            },
            [];
            $($vals)*
        }
    };
}

/// A Rust version of the familiar C `offset_of` macro.  It returns the byte
/// offset of `field` within struct `ty`
macro_rules! offset_of {
    ($ty:ty, $field:ident) => {
        &(*(ptr::null() as *const $ty)).$field as *const _ as usize
    }
}
<|endoftext|>


<commit_before>use hex::FromHex;
use hyper::{
    client::connect::{Connected, Connection},
    service::Service,
    Uri,
};
use pin_project::pin_project;
use std::{
    future::Future,
    io,
    path::{Path, PathBuf},
    pin::Pin,
    task::{Context, Poll},
};

#[pin_project]
#[derive(Debug)]
pub struct UnixStream {
    #[pin]
    unix_stream: tokio::net::UnixStream,
}

impl UnixStream {
    async fn connect<P>(path: P) -> std::io::Result<Self>
    where
        P: AsRef<Path>,
    {
        let unix_stream = tokio::net::UnixStream::connect(path).await?;
        Ok(Self { unix_stream })
    }
}

impl tokio::io::AsyncWrite for UnixStream {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, io::Error>> {
        self.project().unix_stream.poll_write(cx, buf)
    }
    fn poll_flush(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>> {
        self.project().unix_stream.poll_flush(cx)
    }
    fn poll_shutdown(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>> {
        self.project().unix_stream.poll_shutdown(cx)
    }
}

impl tokio::io::AsyncRead for UnixStream {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.project().unix_stream.poll_read(cx, buf)
    }
}

#[derive(Clone, Copy, Debug)]
pub struct UnixConnector;

impl Unpin for UnixConnector {}

impl Service<Uri> for UnixConnector {
    type Response = UnixStream;
    type Error = std::io::Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + Sync>>;
    fn call(
        &mut self,
        req: Uri,
    ) -> Self::Future {
        let fut = async move {
            let path = parse_socket_path(req)?;
            UnixStream::connect(path).await
        };

        Box::pin(fut)
    }
    fn poll_ready(
        &mut self,
        _cx: &mut Context<'_>,
    ) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }
}

impl Connection for UnixStream {
    fn connected(&self) -> Connected {
        Connected::new()
    }
}

fn parse_socket_path(uri: Uri) -> Result<std::path::PathBuf, io::Error> {
    if uri.scheme_str() != Some("unix") {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid URL, scheme must be unix",
        ));
    }

    if let Some(host) = uri.host() {
        let bytes = Vec::from_hex(host).map_err(|_| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid URL, host must be a hex-encoded path",
            )
        })?;

        Ok(PathBuf::from(String::from_utf8_lossy(&bytes).into_owned()))
    } else {
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid URL, host must be present",
        ))
    }
}
<commit_msg>simplify type signature of Service::Future<commit_after>use futures_util::future::BoxFuture;
use hex::FromHex;
use hyper::{
    client::connect::{Connected, Connection},
    service::Service,
    Uri,
};
use pin_project::pin_project;
use std::{
    io,
    path::{Path, PathBuf},
    pin::Pin,
    task::{Context, Poll},
};

#[pin_project]
#[derive(Debug)]
pub struct UnixStream {
    #[pin]
    unix_stream: tokio::net::UnixStream,
}

impl UnixStream {
    async fn connect<P>(path: P) -> std::io::Result<Self>
    where
        P: AsRef<Path>,
    {
        let unix_stream = tokio::net::UnixStream::connect(path).await?;
        Ok(Self { unix_stream })
    }
}

impl tokio::io::AsyncWrite for UnixStream {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, io::Error>> {
        self.project().unix_stream.poll_write(cx, buf)
    }
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        self.project().unix_stream.poll_flush(cx)
    }
    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        self.project().unix_stream.poll_shutdown(cx)
    }
}

impl tokio::io::AsyncRead for UnixStream {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.project().unix_stream.poll_read(cx, buf)
    }
}

#[derive(Clone, Copy, Debug, Default)]
pub struct UnixConnector;

impl Unpin for UnixConnector {}

impl Service<Uri> for UnixConnector {
    type Response = UnixStream;
    type Error = std::io::Error;
    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
    fn call(&mut self, req: Uri) -> Self::Future {
        let fut = async move {
            let path = parse_socket_path(req)?;
            UnixStream::connect(path).await
        };

        Box::pin(fut)
    }
    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }
}

impl Connection for UnixStream {
    fn connected(&self) -> Connected {
        Connected::new()
    }
}

fn parse_socket_path(uri: Uri) -> Result<std::path::PathBuf, io::Error> {
    if uri.scheme_str() != Some("unix") {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid URL, scheme must be unix",
        ));
    }

    if let Some(host) = uri.host() {
        let bytes = Vec::from_hex(host).map_err(|_| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid URL, host must be a hex-encoded path",
            )
        })?;

        Ok(PathBuf::from(String::from_utf8_lossy(&bytes).into_owned()))
    } else {
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            "invalid URL, host must be present",
        ))
    }
}

/* #[cfg(test)]
mod tests {
    use super::*;
    use hyper::Uri as HyperUri;

    #[test]
    fn test_unix_uri_into_hyper_uri() {
        let unix: HyperUri = Uri::new("foo.sock", "/").into();
        let expected: HyperUri = "unix://666f6f2e736f636b:0/".parse().unwrap();
        assert_eq!(unix, expected);
    }

    #[test]
    fn test_hex_encoded_unix_uri() {
        let uri: HyperUri = "unix://666f6f2e736f636b:0/".parse().unwrap();

        let path = Uri::parse_socket_path(uri.scheme_str().unwrap(), uri.host().unwrap()).unwrap();
        assert_eq!(path, PathBuf::from("foo.sock"));
    }

    #[test]
    fn test_hex_encoded_non_unix_uri() {
        let uri: HyperUri = "http://666f6f2e736f636b:0/".parse().unwrap();

        let err =
            Uri::parse_socket_path(uri.scheme_str().unwrap(), uri.host().unwrap()).unwrap_err();
        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
    }

    #[test]
    fn test_non_hex_encoded_non_unix_uri() {
        let uri: HyperUri = "http://example.org".parse().unwrap();

        let err =
            Uri::parse_socket_path(uri.scheme_str().unwrap(), uri.host().unwrap()).unwrap_err();
        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
    }

    #[test]
    fn test_non_hex_encoded_unix_uri() {
        let uri: HyperUri = "unix://example.org".parse().unwrap();

        let err =
            Uri::parse_socket_path(uri.scheme_str().unwrap(), uri.host().unwrap()).unwrap_err();
        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
    }
} */
<|endoftext|>


<commit_before>use std::default::Default;
use std::str::from_str;

use std::io::net::ip::{IpAddr,SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::{BufReader,BufWriter,IoResult};

use client::config::ClientConfig;
use io::DNSWriter;
use message::Message;

pub mod config;

pub struct Client {
    config: ClientConfig,
}

impl Client {
    pub fn exchange(&self, msg: &mut Message) -> IoResult<Message> {
        let saddr: SocketAddr = match self.config.bind {
            None        => {
                // TODO(ekarlso): Support ipv6?
                SocketAddr { ip: from_str::<IpAddr>("0.0.0.0").unwrap(), port: 0 }
            },
            Some(addr)  => { addr }
        };

        let mut buffer: [u8, ..512] = [0, ..512];
        let length: uint = self.write(&mut buffer, msg).unwrap() as uint;

        let mut sock = UdpSocket::bind(saddr).unwrap();

        let dst = self.config.servers[0];

        sock.send_to(buffer.slice_to(length), dst);

        match sock.recv_from(&mut buffer) {
            Ok((length, src)) => {
                self.read(&mut buffer, length)
            },
            Err(e) => return Err(e)
        }
    }

    fn write(&self, buffer: &mut [u8, ..512], message: &mut Message) -> IoResult<u64> {
        let mut writer: BufWriter = BufWriter::new(buffer.as_mut_slice());

        match message.write_to(&mut writer) {
            Err(e) => return Err(e),
            Ok(_) => ()
        };

        return writer.tell();
    }

    fn read(&self, buffer: &mut [u8, ..512], length: uint) -> IoResult<Message> {
        let mut reader = BufReader::new(buffer.slice_to(length));

        Message::from_reader(&mut reader)
    }

    pub fn new() -> Client {
        Client {..Default::default() }
    }
}

impl Default for Client {
    fn default() -> Client {
        let cfg = ClientConfig { ..Default::default() };

        Client {
            config: cfg
        }
    }
}<commit_msg>Make config public<commit_after>use std::default::Default;
use std::str::from_str;

use std::io::net::ip::{IpAddr,SocketAddr};
use std::io::net::udp::UdpSocket;
use std::io::{BufReader,BufWriter,IoResult};

use client::config::ClientConfig;
use io::DNSWriter;
use message::Message;

pub mod config;

pub struct Client {
    pub config: ClientConfig,
}

impl Client {
    pub fn exchange(&self, msg: &mut Message) -> IoResult<Message> {
        let saddr: SocketAddr = match self.config.bind {
            None        => {
                // TODO(ekarlso): Support ipv6?
                SocketAddr { ip: from_str::<IpAddr>("0.0.0.0").unwrap(), port: 0 }
            },
            Some(addr)  => { addr }
        };

        let mut buffer: [u8, ..512] = [0, ..512];
        let length: uint = self.write(&mut buffer, msg).unwrap() as uint;

        let mut sock = UdpSocket::bind(saddr).unwrap();

        let dst = self.config.servers[0];

        sock.send_to(buffer.slice_to(length), dst);

        match sock.recv_from(&mut buffer) {
            Ok((length, src)) => {
                self.read(&mut buffer, length)
            },
            Err(e) => return Err(e)
        }
    }

    fn write(&self, buffer: &mut [u8, ..512], message: &mut Message) -> IoResult<u64> {
        let mut writer: BufWriter = BufWriter::new(buffer.as_mut_slice());

        match message.write_to(&mut writer) {
            Err(e) => return Err(e),
            Ok(_) => ()
        };

        return writer.tell();
    }

    fn read(&self, buffer: &mut [u8, ..512], length: uint) -> IoResult<Message> {
        let mut reader = BufReader::new(buffer.slice_to(length));

        Message::from_reader(&mut reader)
    }

    pub fn new() -> Client {
        Client {..Default::default() }
    }
}

impl Default for Client {
    fn default() -> Client {
        let cfg = ClientConfig { ..Default::default() };

        Client {
            config: cfg
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
/*extern crate http;*/
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	/*println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);*/
	/*println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);*/
	/*println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);*/
}
<commit_msg>enable http demo<commit_after>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	/*println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);*/
	/*println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);*/
	println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);
}
<|endoftext|>