<commit_before>// Copyright(C) 2016 Chris Liebert
#![crate_type = "dylib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;
use std::os::raw::c_char;

use glium::glutin;
use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

use common::Camera;
use loader::DBLoader;
use renderer::Renderer;

#[no_mangle]
pub extern "C" fn camera_aim(camera: &Camera, x: libc::c_double, y: libc::c_double) {
	camera.aim(x as f64, y as f64);
}

#[no_mangle]
pub extern "C" fn camera_move_forward(camera: &Camera, amount: libc::c_float) {
	camera.move_forward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_backward(camera: &Camera, amount: libc::c_float) {
	camera.move_backward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_left(camera: &Camera, amount: libc::c_float) {
	camera.move_left(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_right(camera: &Camera, amount: libc::c_float) {
	camera.move_right(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_update(camera: &Camera) {
	camera.update();
}

#[no_mangle]
pub extern "C" fn create_camera(screen_width: f32, screen_height: f32) -> Box<Camera> {
    Box::new(Camera::new(screen_width, screen_height))
}

#[no_mangle]
pub extern "C" fn create_db_loader(filename_cstr: *const c_char) -> Box<DBLoader> {
    unsafe {
        let filename: String = CStr::from_ptr(filename_cstr).to_string_lossy().into_owned();
        let dbloader: DBLoader = DBLoader::new(&filename);
        println!("Loaded {}", &filename);
        Box::new(dbloader)
    }
}

#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {
        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
	        //.resizable()
	        //.with_vsync()
	        .with_gl_debug_flag(true)
	        .with_title(window_title)
	        .with_visibility(true)
	        .with_dimensions(w, h)
	        .build_glium()
	        .unwrap();
        return Box::new(display);
    }
}

#[no_mangle]
pub extern "C" fn create_renderer_from_db_loader(dbloader: &DBLoader,
                                                 display: &GlutinFacade)
                                                 -> Box<Renderer> {
    Box::new(renderer::Renderer::new(display, dbloader.load_scene()))
}

#[no_mangle]
pub extern "C" fn free_camera(ptr: *mut Camera) {
    let box_ptr: Box<Camera> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_db_loader(ptr: *mut DBLoader) {
    let box_ptr: Box<DBLoader> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_renderer(ptr: *mut Renderer) {
    let box_ptr: Box<Renderer> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn get_shader_from_db_loader(shader_name_cstr: *const c_char,
                                            dbloader: &DBLoader,
                                            renderer: &Renderer,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = renderer.create_shader_program(&shader_name, dbloader, display);
        return Box::new(shader_program);
    }
}

#[repr(C)]
pub struct Mouse {
    pub dx: i32,
    pub dy: i32,
    pub last_x: i32,
    pub last_y: i32,
    pub left_button_pressed: bool,
    pub right_button_pressed: bool,
}

#[repr(C)]
pub struct Input {
    pub mouse: Mouse,
    pub closed: bool,
}

#[no_mangle]
pub unsafe extern "C" fn poll_event(display: &GlutinFacade) -> Input {
	static mut mouse_last_x: i32 = 0;
	static mut mouse_last_y: i32 = 0;
	static mut _mouse_dx: i32 = 0;
	static mut _mouse_dy: i32 = 0;
	static mut left_button_pressed: bool = false;
	static mut right_button_pressed: bool = false;

    // Get the screen width and height in pixels
    let pixel_dimensions: (u32, u32) = match display.get_window() {
        Some(window) => window.get_inner_size_pixels().unwrap(),
        None => {
            panic!("Error retrieving window when querying display size.");
        }
    };
    let screen_width: u32 = pixel_dimensions.0;
    let screen_height: u32 = pixel_dimensions.1;
    let screen_center_x: i32 = (screen_width / 2) as i32;
    let screen_center_y: i32 = (screen_height / 2) as i32;

    // The margin from the edge of the screen to allow before
	// mouse cursor is moved to center

    let mouse_grab_margin: i32 = screen_center_y / 2;

    let mut closed = false;

    for event in display.poll_events() {
        match event {
        	Event::Closed => closed = true,
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => {
                closed = true
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                left_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                left_button_pressed = false;
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Right) => {
                right_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Right) => {
                right_button_pressed = false;
            }
            Event::MouseMoved(x, y) => {
                _mouse_dx = mouse_last_x - x;
                _mouse_dy = mouse_last_y - y;
                mouse_last_x = x;
		        mouse_last_y = y;
                if left_button_pressed {
                    if x + mouse_grab_margin >= screen_width as i32 || x <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(screen_center_x, y);
                            _mouse_dx = 0;
                            mouse_last_x = screen_center_x;
                    } else if y + mouse_grab_margin >= screen_height as i32 || y <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(x, screen_center_y);
                            _mouse_dy = 0;
                            mouse_last_y = screen_center_y;
                    }
                }
            }
            _ => ()
        }
    }
    Input {
	    mouse: Mouse {
	        dx: _mouse_dx,
	        dy: _mouse_dy,
	        last_x: mouse_last_x,
	        last_y: mouse_last_y,
	        left_button_pressed: left_button_pressed,
	        right_button_pressed: right_button_pressed,
	    },
	    closed: closed,
    }
}

#[no_mangle]
pub extern "C" fn render(renderer: &Renderer,
                         shader_program: &glium::program::Program,
                         camera: &Camera,
                         display: &GlutinFacade) {
    renderer.render(display, shader_program, camera);
}

use std::sync::{Arc, Mutex};

#[repr(C)]
pub struct ConsoleInput {
    pub thread_handle: std::thread::JoinHandle<i32>,
    pub buffer: Arc<Mutex<String>>,
    pub finished: Arc<Mutex<bool>>,
}

#[cfg(target_os = "windows")]
fn get_ffi_str_size() -> usize {
    2
}

#[cfg(not(target_os = "windows"))]
fn get_ffi_str_size() -> usize {
    1
}

#[no_mangle]
pub extern "C" fn create_console_reader() -> Box<ConsoleInput> {
	use std::thread;
	let buffer_arc: Arc<Mutex<String>> = Arc::new(Mutex::new(String::new()));
	let buffer_arc_copy = buffer_arc.clone();
	let finished_arc: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
	let finished_arc_copy = finished_arc.clone();
	{
		// Initialize the finished value
		let finished = finished_arc.clone();
		let mut finished_lock = finished.lock().unwrap();
		*finished_lock = false;
	}

	let child = thread::spawn(move || {
		println!("Enter command, or return to close console");
		'console: loop {
			let mut buffer = String::new();
			match std::io::stdin().read_line(&mut buffer) {
				Ok(_) => {
					if get_ffi_str_size() == buffer.len() { break 'console };
					let arc = buffer_arc.clone();
					let mut writer = arc.lock().unwrap();
					let mut new_string: String = (*writer).clone();
					new_string.push_str(&buffer);
					*writer = new_string;
					std::thread::yield_now();
				},
				Err(e) => println!("Error: {:?}", e),
			}
		}
		println!("Console closed");
		let finished = finished_arc.clone();
		let mut finished_lock = finished.lock().unwrap();
		*finished_lock = true;
	    return 0;
	});

	std::thread::yield_now();
	Box::new(ConsoleInput{thread_handle: child, buffer: buffer_arc_copy, finished: finished_arc_copy})
}

#[no_mangle]
pub extern "C" fn console_is_closed(console: &ConsoleInput) -> bool {
	let arc = console.finished.clone();
	let mutex = arc.lock().unwrap();
	let retval: bool = mutex.clone();
	retval
}

#[cfg(target_os = "windows")]
#[no_mangle]
pub extern "C" fn read_console_buffer(console: &ConsoleInput) -> *const u8 {
	let mut retval: String;
	let arc = console.buffer.clone();
	let mut mutex = arc.lock().unwrap();
	retval = (*mutex).clone();
	retval.push('\0');
	*mutex = String::new();
	retval.as_ptr()
}

use std::ffi::CString;

#[cfg(not(target_os = "windows"))]
#[no_mangle]
pub extern "C" fn read_console_buffer(console: &ConsoleInput) -> CString {
	let mut retval: String;
	let arc = console.buffer.clone();
	let mut mutex = arc.lock().unwrap();
	retval = (*mutex).clone();
	*mutex = String::new();
	CString::new(retval).unwrap()
}

#[no_mangle]
pub extern "C" fn wait_console_quit(handle: *mut ConsoleInput) {
	let child: Box<ConsoleInput> = unsafe { Box::from_raw(handle) };
	match child.thread_handle.join() {
		Ok(_) => {},
		Err(e) => println!("Console thread did not return: {:?}", e),
	}
}

#[no_mangle]
pub extern "C" fn hide_window(display: &GlutinFacade) {
	 match display.get_window() {
        Some(w) => {
            w.hide();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        let dbloader: loader::DBLoader = loader::DBLoader::new("test.db");
        return dbloader.load_scene();
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

}
<commit_msg>Improved win32 compatibility for msys and cmd shells<commit_after>// Copyright(C) 2016 Chris Liebert
#![crate_type = "dylib"]
#![crate_name = "quick3d"]
#![allow(dead_code)]
#[macro_use]
extern crate glium;

pub mod common;

pub mod loader;
#[macro_use]
pub mod renderer;

extern crate nalgebra;
extern crate libc;

use std::ffi::CStr;
use std::os::raw::c_char;

use glium::glutin;
use glium::glutin::{ElementState, Event, MouseButton, VirtualKeyCode};
use glium::DisplayBuild;
use glium::backend::glutin_backend::GlutinFacade;

use common::Camera;
use loader::DBLoader;
use renderer::Renderer;

#[no_mangle]
pub extern "C" fn camera_aim(camera: &Camera, x: libc::c_double, y: libc::c_double) {
	camera.aim(x as f64, y as f64);
}

#[no_mangle]
pub extern "C" fn camera_move_forward(camera: &Camera, amount: libc::c_float) {
	camera.move_forward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_backward(camera: &Camera, amount: libc::c_float) {
	camera.move_backward(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_left(camera: &Camera, amount: libc::c_float) {
	camera.move_left(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_move_right(camera: &Camera, amount: libc::c_float) {
	camera.move_right(amount as f32);
}

#[no_mangle]
pub extern "C" fn camera_update(camera: &Camera) {
	camera.update();
}

#[no_mangle]
pub extern "C" fn create_camera(screen_width: f32, screen_height: f32) -> Box<Camera> {
    Box::new(Camera::new(screen_width, screen_height))
}

#[no_mangle]
pub extern "C" fn create_db_loader(filename_cstr: *const c_char) -> Box<DBLoader> {
    unsafe {
        let filename: String = CStr::from_ptr(filename_cstr).to_string_lossy().into_owned();
        let dbloader: DBLoader = DBLoader::new(&filename);
        println!("Loaded {}", &filename);
        Box::new(dbloader)
    }
}

#[no_mangle]
pub extern "C" fn create_display(screen_width: libc::int32_t,
                                 screen_height: libc::int32_t,
                                 title: *const c_char)
                                 -> Box<GlutinFacade> {
    let w: u32 = screen_width as u32;
    let h: u32 = screen_height as u32;
    let window_title: String;

    unsafe {
        window_title = CStr::from_ptr(title).to_string_lossy().into_owned();
        let display: GlutinFacade = glutin::WindowBuilder::new()
	        //.resizable()
	        //.with_vsync()
	        .with_gl_debug_flag(true)
	        .with_title(window_title)
	        .with_visibility(true)
	        .with_dimensions(w, h)
	        .build_glium()
	        .unwrap();
        return Box::new(display);
    }
}

#[no_mangle]
pub extern "C" fn create_renderer_from_db_loader(dbloader: &DBLoader,
                                                 display: &GlutinFacade)
                                                 -> Box<Renderer> {
    Box::new(renderer::Renderer::new(display, dbloader.load_scene()))
}

#[no_mangle]
pub extern "C" fn free_camera(ptr: *mut Camera) {
    let box_ptr: Box<Camera> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_db_loader(ptr: *mut DBLoader) {
    let box_ptr: Box<DBLoader> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_display(ptr: *mut GlutinFacade) {
    let box_ptr: Box<GlutinFacade> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_renderer(ptr: *mut Renderer) {
    let box_ptr: Box<Renderer> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    Box::into_raw(box_ptr);
}

#[no_mangle]
pub extern "C" fn get_shader_from_db_loader(shader_name_cstr: *const c_char,
                                            dbloader: &DBLoader,
                                            renderer: &Renderer,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = renderer.create_shader_program(&shader_name, dbloader, display);
        return Box::new(shader_program);
    }
}

#[repr(C)]
pub struct Mouse {
    pub dx: i32,
    pub dy: i32,
    pub last_x: i32,
    pub last_y: i32,
    pub left_button_pressed: bool,
    pub right_button_pressed: bool,
}

#[repr(C)]
pub struct Input {
    pub mouse: Mouse,
    pub closed: bool,
}

#[no_mangle]
pub unsafe extern "C" fn poll_event(display: &GlutinFacade) -> Input {
	static mut mouse_last_x: i32 = 0;
	static mut mouse_last_y: i32 = 0;
	static mut _mouse_dx: i32 = 0;
	static mut _mouse_dy: i32 = 0;
	static mut left_button_pressed: bool = false;
	static mut right_button_pressed: bool = false;

    // Get the screen width and height in pixels
    let pixel_dimensions: (u32, u32) = match display.get_window() {
        Some(window) => window.get_inner_size_pixels().unwrap(),
        None => {
            panic!("Error retrieving window when querying display size.");
        }
    };
    let screen_width: u32 = pixel_dimensions.0;
    let screen_height: u32 = pixel_dimensions.1;
    let screen_center_x: i32 = (screen_width / 2) as i32;
    let screen_center_y: i32 = (screen_height / 2) as i32;

    // The margin from the edge of the screen to allow before
	// mouse cursor is moved to center

    let mouse_grab_margin: i32 = screen_center_y / 2;

    let mut closed = false;

    for event in display.poll_events() {
        match event {
        	Event::Closed => closed = true,
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Escape)) => {
                closed = true
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                left_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Left) => {
                left_button_pressed = false;
            }
            Event::MouseInput(ElementState::Pressed, MouseButton::Right) => {
                right_button_pressed = true;
            }
            Event::MouseInput(ElementState::Released, MouseButton::Right) => {
                right_button_pressed = false;
            }
            Event::MouseMoved(x, y) => {
                _mouse_dx = mouse_last_x - x;
                _mouse_dy = mouse_last_y - y;
                mouse_last_x = x;
		        mouse_last_y = y;
                if left_button_pressed {
                    if x + mouse_grab_margin >= screen_width as i32 || x <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(screen_center_x, y);
                            _mouse_dx = 0;
                            mouse_last_x = screen_center_x;
                    } else if y + mouse_grab_margin >= screen_height as i32 || y <= mouse_grab_margin {
                        let _ =
                            display.get_window().unwrap().set_cursor_position(x, screen_center_y);
                            _mouse_dy = 0;
                            mouse_last_y = screen_center_y;
                    }
                }
            }
            _ => ()
        }
    }
    Input {
	    mouse: Mouse {
	        dx: _mouse_dx,
	        dy: _mouse_dy,
	        last_x: mouse_last_x,
	        last_y: mouse_last_y,
	        left_button_pressed: left_button_pressed,
	        right_button_pressed: right_button_pressed,
	    },
	    closed: closed,
    }
}

#[no_mangle]
pub extern "C" fn render(renderer: &Renderer,
                         shader_program: &glium::program::Program,
                         camera: &Camera,
                         display: &GlutinFacade) {
    renderer.render(display, shader_program, camera);
}

use std::sync::{Arc, Mutex};

#[repr(C)]
pub struct ConsoleInput {
    pub thread_handle: std::thread::JoinHandle<i32>,
    pub buffer: Arc<Mutex<String>>,
    pub finished: Arc<Mutex<bool>>,
}

#[no_mangle]
pub extern "C" fn create_console_reader() -> Box<ConsoleInput> {
	use std::thread;
	let buffer_arc: Arc<Mutex<String>> = Arc::new(Mutex::new(String::new()));
	let buffer_arc_copy = buffer_arc.clone();
	let finished_arc: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
	let finished_arc_copy = finished_arc.clone();
	{
		// Initialize the finished value
		let finished = finished_arc.clone();
		let mut finished_lock = finished.lock().unwrap();
		*finished_lock = false;
	}

	let child = thread::spawn(move || {
		println!("Enter command, or return to close console");
		'console: loop {
			let mut buffer = String::new();
			match std::io::stdin().read_line(&mut buffer) {
				Ok(_) => {
					buffer = buffer
						.replace("\r", "")
						.replace("\n", " ");
					if 1 == buffer.len() { break 'console };
					let arc = buffer_arc.clone();
					let mut writer = arc.lock().unwrap();
					let mut new_string: String = (*writer).clone();
					new_string.push_str(&buffer);
					*writer = new_string;
					std::thread::yield_now();
				},
				Err(e) => println!("Error: {:?}", e),
			}
		}
		println!("Console closed");
		let finished = finished_arc.clone();
		let mut finished_lock = finished.lock().unwrap();
		*finished_lock = true;
	    return 0;
	});

	std::thread::yield_now();
	Box::new(ConsoleInput{thread_handle: child, buffer: buffer_arc_copy, finished: finished_arc_copy})
}

#[no_mangle]
pub extern "C" fn console_is_closed(console: &ConsoleInput) -> bool {
	let arc = console.finished.clone();
	let mutex = arc.lock().unwrap();
	let retval: bool = mutex.clone();
	retval
}

#[cfg(target_os = "windows")]
#[no_mangle]
pub extern "C" fn read_console_buffer(console: &ConsoleInput) -> *const u8 {
	let mut retval: String;
	let arc = console.buffer.clone();
	let mut mutex = arc.lock().unwrap();
	retval = (*mutex).clone();
	retval.push('\0');
	*mutex = String::new();
	retval.as_ptr()
}

use std::ffi::CString;

#[cfg(not(target_os = "windows"))]
#[no_mangle]
pub extern "C" fn read_console_buffer(console: &ConsoleInput) -> CString {
	let mut retval: String;
	let arc = console.buffer.clone();
	let mut mutex = arc.lock().unwrap();
	retval = (*mutex).clone();
	*mutex = String::new();
	CString::new(retval).unwrap()
}

#[no_mangle]
pub extern "C" fn wait_console_quit(handle: *mut ConsoleInput) {
	let child: Box<ConsoleInput> = unsafe { Box::from_raw(handle) };
	match child.thread_handle.join() {
		Ok(_) => {},
		Err(e) => println!("Console thread did not return: {:?}", e),
	}
}

#[no_mangle]
pub extern "C" fn hide_window(display: &GlutinFacade) {
	 match display.get_window() {
        Some(w) => {
            w.hide();
        }
        None => {
            panic!("Error retrieving window");
        }
    };
}

#[cfg(test)]
mod tests {
    use glium::glutin;
    use glium::backend::glutin_backend::GlutinFacade;
    use glium::DisplayBuild;
    use loader;
    use common::Scene;

    fn create_test_display() -> GlutinFacade {
        let display = glutin::WindowBuilder::new()
            .with_visibility(false)
            .with_gl_debug_flag(true)
            .build_glium()
            .unwrap();
        return display;
    }

    fn load_test_scene() -> Scene {
        let dbloader: loader::DBLoader = loader::DBLoader::new("test.db");
        return dbloader.load_scene();
    }

    #[test]
    fn loader_load_db_not_empty() {
        println!("Running loader_load_db_not_empty test");
        let scene: Scene = load_test_scene();
        assert!(scene.meshes.len() > 0);
        assert!(scene.materials.len() > 0);
    }

}
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;

mod js_types;
mod alloc;

use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use alloc::AllocBox;
use alloc::scope::Scope;
use js_types::js_type::{JsPtrEnum, JsVar};

pub struct ScopeManager {
    curr_scope: Rc<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>
}

impl ScopeManager {
    pub fn new<F>(alloc_box: Rc<RefCell<AllocBox>>, callback: F) -> ScopeManager
        where F: Fn() -> HashSet<Uuid> + 'static {
        ScopeManager {
            curr_scope: Rc::new(Scope::new(&alloc_box, callback)),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        self.curr_scope = Rc::new(Scope::as_child(&self.curr_scope, &self.alloc_box, callback));
    }

    pub fn pop_scope(&mut self) {
        if let Some(parent) = self.curr_scope.parent.clone() {
            // Set curr_scope to old scope's parent
            self.curr_scope = parent;
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Uuid {
        Rc::get_mut(&mut self.curr_scope).unwrap().push(var, ptr)
    }

    pub fn load(&self, uuid: &Uuid) -> Result<(JsVar, Option<JsPtrEnum>), String> {
        if let (Some(v), ptr) = self.curr_scope.get_var_copy(uuid) {
            Ok((v, ptr))
        } else { Err(format!("Lookup of uuid {} failed!", uuid)) }
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> bool {
        //Rc::get_mut(&mut self.curr_scope).unwrap().update_ptr(uuid, ptr)
        Rc::get_mut(&mut self.curr_scope).unwrap().update_var(var, ptr)
    }

    fn mark_vars(&mut self) {
        self.alloc_box.borrow_mut().mark_roots((self.curr_scope.get_roots)());
        self.alloc_box.borrow_mut().mark_ptrs();
    }

    fn sweep_ptrs(&mut self) {
        self.alloc_box.borrow_mut().sweep_ptrs();
    }
}

pub fn init_gc<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box, callback)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use std::ptr::null_mut;
    use std::rc::Rc;
    use uuid::Uuid;

    fn dummy_callback() -> HashSet<Uuid> {
        HashSet::new()
    }
    // TODO
}
<commit_msg>Remove GC mark/sweep fns from ScopeManager (only scopes know about these now)<commit_after>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;

mod js_types;
mod alloc;

use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use alloc::AllocBox;
use alloc::scope::Scope;
use js_types::js_type::{JsPtrEnum, JsVar};

pub struct ScopeManager {
    curr_scope: Rc<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>
}

impl ScopeManager {
    pub fn new<F>(alloc_box: Rc<RefCell<AllocBox>>, callback: F) -> ScopeManager
        where F: Fn() -> HashSet<Uuid> + 'static {
        ScopeManager {
            curr_scope: Rc::new(Scope::new(&alloc_box, callback)),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        self.curr_scope = Rc::new(Scope::as_child(&self.curr_scope, &self.alloc_box, callback));
    }

    pub fn pop_scope(&mut self) {
        if let Some(parent) = self.curr_scope.parent.clone() {
            self.curr_scope = parent;
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Uuid {
        Rc::get_mut(&mut self.curr_scope).unwrap().push(var, ptr)
    }

    pub fn load(&self, uuid: &Uuid) -> Result<(JsVar, Option<JsPtrEnum>), String> {
        if let (Some(v), ptr) = self.curr_scope.get_var_copy(uuid) {
            Ok((v, ptr))
        } else { Err(format!("Lookup of uuid {} failed!", uuid)) }
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> bool {
        Rc::get_mut(&mut self.curr_scope).unwrap().update_var(var, ptr)
    }
}

pub fn init_gc<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box, callback)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use std::ptr::null_mut;
    use std::rc::Rc;
    use uuid::Uuid;

    fn dummy_callback() -> HashSet<Uuid> {
        HashSet::new()
    }
    // TODO
}
<|endoftext|>


<commit_before>
pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    fn map_in_place<F>(self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        use std::mem;
        use std::ptr;
        use std::cmp::{Ord, Ordering};

        macro_rules! map_loop {
            () => {{
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;
                let len = self.len();

                for i in 0..len {
                    unsafe {
                        let ptr_a = ptr_a.offset(i as isize);
                        let ptr_b = ptr_b.offset(i as isize);

                        ptr::write(ptr_b, f(ptr::read(ptr_a)));
                    }
                }

                (ptr_b, len)
            }}
        }

        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                map_loop!();

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    let cap = self.capacity().checked_mul(a_size).map(|x| x / b_size).unwrap();
                    let (ptr_b, len) = map_loop!();

                    mem::forget(self);

                    unsafe { Vec::from_raw_parts(ptr_b, len, cap) }
                }
            }
            Ordering::Less => panic!(),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    #[test]
    fn same_size() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<commit_msg>Add slice impl<commit_after>
pub trait MapInPlace<A, B>: Sized {
    /// Should be of the same base type as the implementor.
    /// E.g. `Vec<B>` when implementing for `Vec<A>`
    type Output;

    /// Apply a mapping function to `self` without allocating.
    /// Makes best effort to maintain the invariant
    ///
    /// `self.as_ptr() as *const () == self.map_in_place(..).as_ptr() as *const ()`
    ///
    /// An example of a case where this isn't possible is for Vec where B is zero-sized but A is not.
    fn map_in_place<F>(self, f: F) -> Self::Output where F: FnMut(A) -> B;
}

impl<A, B> MapInPlace<A, B> for Vec<A> {
    type Output = Vec<B>;

    #[inline]
    fn map_in_place<F>(mut self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        use std::mem;
        use std::ptr;
        use std::cmp::{Ord, Ordering};

        macro_rules! map_loop {
            () => {{
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;
                let len = self.len();

                for i in 0..len {
                    unsafe {
                        let ptr_a = ptr_a.offset(i as isize);
                        let ptr_b = ptr_b.offset(i as isize);

                        ptr::write(ptr_b, f(ptr::read(ptr_a)));
                    }
                }

                (ptr_b, len)
            }}
        }

        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                // map_loop!();
                self.as_mut_slice().map_in_place(f);

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => {
                if b_size == 0 {
                    // doesn't preserve address invariant
                    let mut v = Vec::with_capacity(0);

                    for e in self.into_iter() {
                        v.push(f(e));
                    }

                    v
                } else {
                    let cap = self.capacity().checked_mul(a_size).map(|x| x / b_size).unwrap();
                    let (ptr_b, len) = map_loop!();

                    mem::forget(self);

                    unsafe { Vec::from_raw_parts(ptr_b, len, cap) }
                }
            }
            Ordering::Less => panic!(),
        }
    }
}

impl<'a, A, B: 'a> MapInPlace<A, B> for &'a mut [A] {
    type Output = &'a mut [B];

    #[inline]
    fn map_in_place<F>(self, mut f: F) -> Self::Output
        where F: FnMut(A) -> B
    {
        use std::mem;
        use std::ptr;
        use std::cmp::{Ord, Ordering};

        let a_size = mem::size_of::<A>();
        let b_size = mem::size_of::<B>();

        match a_size.cmp(&b_size) {
            Ordering::Equal => {
                let ptr_a = self.as_ptr();
                let ptr_b = ptr_a as *mut B;

                for i in 0..self.len() {
                    unsafe {
                        let ptr_a = ptr_a.offset(i as isize);
                        let ptr_b = ptr_b.offset(i as isize);

                        ptr::write(ptr_b, f(ptr::read(ptr_a)));
                    }
                }

                unsafe { mem::transmute(self) }
            }
            Ordering::Greater => panic!(),
            Ordering::Less => panic!(),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::MapInPlace;

    #[test]
    fn same_size_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn different_sizes_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_vec() {
        #[derive(Debug)]
        struct Zst;

        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    fn nzst_to_zst_vec() {
        let v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_vec() {
        let v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = v.map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    // //////

    #[test]
    fn same_size_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i32);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    #[should_panic]
    fn different_sizes_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|x: u32| (x * x) as i16);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
        assert_eq!(v, &*vec![0, 1, 4, 9]);
    }

    #[test]
    fn both_zst_slice() {
        #[derive(Debug)]
        struct Zst;

        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| Zst);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }

    #[test]
    #[should_panic]
    fn nzst_to_zst_slice() {
        let mut v = vec![0, 1, 2, 3];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_: u32| ());
        let ap = v.as_ptr() as *const ();

        assert!(bp != ap); // -- NOT -- still at same memory addr
    }

    #[test]
    #[should_panic]
    fn zst_to_nzst_slice() {
        let mut v = vec![(), (), (), ()];

        let bp = v.as_ptr() as *const ();
        let v = (&mut *v).map_in_place(|_| 0usize);
        let ap = v.as_ptr() as *const ();

        assert_eq!(bp, ap); // still at same memory addr
    }
}
<|endoftext|>


<commit_before>use std::old_io as io;
use std::sync::mpsc;

use std::path::Path as StdPath;

//================================================================================
// Misc typedefs:
//================================================================================
pub type Path = StdPath;
pub type NotifyResult<T> = io::IoResult<T>;
pub type R = NotifyResult<()>;

//================================================================================
// Configuration:
//================================================================================
pub type RecursionLimit = Option<usize>;
pub struct Configuration<'a> {
	subscribe: Operations,
	follow_symlinks: bool,
	recursion_limit: RecursionLimit,
	recursion_filter: Fn( &Path ) -> bool + 'a
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

pub struct Event {
	pub path: Option<Path>,
	pub op: NotifyResult<Operations>,
}

pub type EventSender = mpsc::Sender<Event>;

//================================================================================
// Notifier trait:
//================================================================================
pub trait FsNotifier : Drop {
	fn new( sender: EventSender, config: Configuration ) -> NotifyResult<Self>;

	fn add( &self, path: &Path ) -> R;

	fn remove( &self, path: &Path ) -> R;

	fn start( &self ) -> R;

	fn stop( &self ) -> R;
}<commit_msg>typedef RecursionFilter, added lifetimes.<commit_after>use std::old_io as io;
use std::sync::mpsc;

use std::path::Path as StdPath;

//================================================================================
// Misc typedefs:
//================================================================================

pub type Path = StdPath;
pub type NotifyResult<T> = io::IoResult<T>;
pub type R = NotifyResult<()>;

//================================================================================
// Configuration:
//================================================================================

pub type RecursionFilter<'a> = Option<Fn( &Path ) -> bool + 'a>;
pub type RecursionLimit = Option<usize>;
pub struct Configuration<'a> {
	subscribe: Operations,
	follow_symlinks: bool,
	recursion_limit: RecursionLimit,
	recursion_filter: RecursionFilter<'a>,
}

//================================================================================
// Events:
//================================================================================

mod operations;
use self::operations::Operations;

pub struct Event {
	pub path: Option<Path>,
	pub op: NotifyResult<Operations>,
}

pub type EventSender = mpsc::Sender<Event>;

//================================================================================
// Notifier trait:
//================================================================================

pub trait FsNotifier<'a> : Drop {
	fn new( sender: EventSender, config: Configuration<'a> ) -> NotifyResult<Self>;

	fn add( &self, path: &Path ) -> R;

	fn remove( &self, path: &Path ) -> R;

	fn start( &self ) -> R;

	fn stop( &self ) -> R;
}<|endoftext|>


<commit_before>bitflags! {
    struct FunctionSetFlags: u8 {
        const FUNCTION_SET                  = 0b0010_0000;
        const INTERFACE_DATA_LENGTH_8BIT    = 0b0001_0000;
        const DISPLAY_LINES_NUMBER_2        = 0b0000_1000;
        const CHARACTER_FONT_5_10_DOTS      = 0b0000_0100;
        const INTERFACE_DATA_LENGTH_4BIT    = 0;
        const DISPLAY_LINES_NUMBER_1        = 0;
        const CHARACTER_FONT_5_8_DOTS       = 0;
    }
}

/// Enumeration of possible interface data lengths.
#[derive(Clone, Copy)]
pub enum DataLength {
    /// 4-bit mode
    FourBit,
    /// 8-bit mode
    EightBit,
}

impl From<DataLength> for FunctionSetFlags {
    fn from(length: DataLength) -> Self {
        match length {
            DataLength::FourBit => INTERFACE_DATA_LENGTH_4BIT,
            DataLength::EightBit => INTERFACE_DATA_LENGTH_8BIT,
        }
    }
}

/// Enumeration to set display line number.
#[derive(Clone, Copy)]
pub enum LineNumber {
    One,
    Two,
}

impl From<LineNumber> for FunctionSetFlags {
    fn from(number: LineNumber) -> Self {
        match number {
            LineNumber::One => DISPLAY_LINES_NUMBER_1,
            LineNumber::Two => DISPLAY_LINES_NUMBER_2,
        }
    }
}

/// Enumeration to set display character font.
#[derive(Clone, Copy)]
pub enum CharacterFont {
    Dots5By10,
    Dots5By8,
}

impl From<CharacterFont> for FunctionSetFlags {
    fn from(font: CharacterFont) -> Self {
        match font {
            CharacterFont::Dots5By10 => CHARACTER_FONT_5_10_DOTS,
            CharacterFont::Dots5By8 => CHARACTER_FONT_5_8_DOTS,
        }
    }
}

/// A struct for creating display function settings.
pub struct FunctionSetBuilder {
    data_length: DataLength,
    line_number: LineNumber,
    character_font: CharacterFont,
}

impl FunctionSetBuilder {
    pub fn set_data_length(&mut self, data_length: DataLength) -> &mut Self {
        self.data_length = data_length;
        self
    }

    pub fn set_line_number(&mut self, line_number: LineNumber) -> &mut Self {
        self.line_number = line_number;
        self
    }

    pub fn set_character_font(&mut self, character_font: CharacterFont) -> &mut Self {
        self.character_font = character_font;
        self
    }

    pub(crate) fn build_command(&self) -> u8 {
        let mut cmd = FUNCTION_SET;

        cmd |= FunctionSetFlags::from(self.data_length);
        cmd |= FunctionSetFlags::from(self.line_number);
        cmd |= FunctionSetFlags::from(self.character_font);

        cmd.bits()
    }
}

impl Default for FunctionSetBuilder {
    /// Make a new `FunctionSetBuilder` with the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **data_length:**
    ///     - `FourBit` - 4-bit mode
    ///  - **line_number:**
    ///     - `One` - one line mode
    ///  - **character_font:**
    ///     - `Dots5By8` - 5x8 dots character font
    fn default() -> Self {
        Self {
            data_length: DataLength::FourBit,
            line_number: LineNumber::One,
            character_font: CharacterFont::Dots5By8,
        }
    }
}
<commit_msg>Add unit test to function set builder<commit_after>bitflags! {
    struct FunctionSetFlags: u8 {
        const FUNCTION_SET                  = 0b0010_0000;
        const INTERFACE_DATA_LENGTH_8BIT    = 0b0001_0000;
        const DISPLAY_LINES_NUMBER_2        = 0b0000_1000;
        const CHARACTER_FONT_5_10_DOTS      = 0b0000_0100;
        const INTERFACE_DATA_LENGTH_4BIT    = 0;
        const DISPLAY_LINES_NUMBER_1        = 0;
        const CHARACTER_FONT_5_8_DOTS       = 0;
    }
}

/// Enumeration of possible interface data lengths.
#[derive(Clone, Copy)]
pub enum DataLength {
    /// 4-bit mode
    FourBit,
    /// 8-bit mode
    EightBit,
}

impl From<DataLength> for FunctionSetFlags {
    fn from(length: DataLength) -> Self {
        match length {
            DataLength::FourBit => INTERFACE_DATA_LENGTH_4BIT,
            DataLength::EightBit => INTERFACE_DATA_LENGTH_8BIT,
        }
    }
}

/// Enumeration to set display line number.
#[derive(Clone, Copy)]
pub enum LineNumber {
    One,
    Two,
}

impl From<LineNumber> for FunctionSetFlags {
    fn from(number: LineNumber) -> Self {
        match number {
            LineNumber::One => DISPLAY_LINES_NUMBER_1,
            LineNumber::Two => DISPLAY_LINES_NUMBER_2,
        }
    }
}

/// Enumeration to set display character font.
#[derive(Clone, Copy)]
pub enum CharacterFont {
    Dots5By10,
    Dots5By8,
}

impl From<CharacterFont> for FunctionSetFlags {
    fn from(font: CharacterFont) -> Self {
        match font {
            CharacterFont::Dots5By10 => CHARACTER_FONT_5_10_DOTS,
            CharacterFont::Dots5By8 => CHARACTER_FONT_5_8_DOTS,
        }
    }
}

/// A struct for creating display function settings.
pub struct FunctionSetBuilder {
    data_length: DataLength,
    line_number: LineNumber,
    character_font: CharacterFont,
}

impl FunctionSetBuilder {
    pub fn set_data_length(&mut self, data_length: DataLength) -> &mut Self {
        self.data_length = data_length;
        self
    }

    pub fn set_line_number(&mut self, line_number: LineNumber) -> &mut Self {
        self.line_number = line_number;
        self
    }

    pub fn set_character_font(&mut self, character_font: CharacterFont) -> &mut Self {
        self.character_font = character_font;
        self
    }

    pub(crate) fn build_command(&self) -> u8 {
        let mut cmd = FUNCTION_SET;

        cmd |= FunctionSetFlags::from(self.data_length);
        cmd |= FunctionSetFlags::from(self.line_number);
        cmd |= FunctionSetFlags::from(self.character_font);

        cmd.bits()
    }
}

impl Default for FunctionSetBuilder {
    /// Make a new `FunctionSetBuilder` with the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **data_length:**
    ///     - `FourBit` - 4-bit mode
    ///  - **line_number:**
    ///     - `One` - one line mode
    ///  - **character_font:**
    ///     - `Dots5By8` - 5x8 dots character font
    fn default() -> Self {
        Self {
            data_length: DataLength::FourBit,
            line_number: LineNumber::One,
            character_font: CharacterFont::Dots5By8,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const FUNCTION_SET_FLAG:    u8 = 0b0010_0000;
    const DATA_LENGTH_FLAG:     u8 = 0b0001_0000;
    const LINE_NUMBER_FLAG:     u8 = 0b0000_1000;
    const CHARACTER_FONT_FLAG:  u8 = 0b0000_0100;

    fn has_bit(value: u8, bitmask: u8) -> bool {
        value & bitmask == bitmask
    }

    #[test]
    fn function_set_flag() {
        let b = FunctionSetBuilder::default();
        let cmd = b.build_command();

        assert!( has_bit(cmd, FUNCTION_SET_FLAG) );
    }

    #[test]
    fn default_data_length() {
        let b = FunctionSetBuilder::default();
        let cmd = b.build_command();

        assert_eq!( has_bit(cmd, DATA_LENGTH_FLAG), false );
    }

    #[test]
    fn set_data_length() {
        let mut b = FunctionSetBuilder::default();

        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, DATA_LENGTH_FLAG), false);

        b.set_data_length(DataLength::EightBit);

        let cmd = b.build_command();
        assert!( has_bit(cmd, DATA_LENGTH_FLAG) );
    }

    #[test]
    fn default_line_number() {
        let b = FunctionSetBuilder::default();
        let cmd = b.build_command();

        assert_eq!( has_bit(cmd, LINE_NUMBER_FLAG), false );
    }

    #[test]
    fn set_line_number() {
        let mut b = FunctionSetBuilder::default();

        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, LINE_NUMBER_FLAG), false);

        b.set_line_number(LineNumber::Two);

        let cmd = b.build_command();
        assert!( has_bit(cmd, LINE_NUMBER_FLAG) );
    }

    #[test]
    fn default_character_font() {
        let b = FunctionSetBuilder::default();
        let cmd = b.build_command();

        assert_eq!( has_bit(cmd, CHARACTER_FONT_FLAG), false );
    }

    #[test]
    fn set_character_font() {
        let mut b = FunctionSetBuilder::default();

        let cmd = b.build_command();
        assert_eq!( has_bit(cmd, CHARACTER_FONT_FLAG), false);

        b.set_character_font(CharacterFont::Dots5By10);

        let cmd = b.build_command();
        assert!( has_bit(cmd, CHARACTER_FONT_FLAG) );
    }
}
<|endoftext|>


<commit_before>//! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, TypeId};
use std::fmt;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener};
use std::mem;
use std::path::Path;
use std::sync::Arc;

use openssl::ssl::{Ssl, SslStream, SslContext};
use openssl::ssl::SslVerifyMode::SslVerifyNone;
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};
use openssl::x509::X509FileType;

use typeable::Typeable;
use {traitobject};

macro_rules! try_some {
    ($expr:expr) => (match $expr {
        Some(val) => { return Err(val); },
        _ => {}
    })
}

/// The write-status indicating headers have not been written.
pub enum Fresh {}

/// The write-status indicating headers have been written.
pub enum Streaming {}

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener: Clone {
    /// The stream produced for each connection.
    type Stream: NetworkStream + Send + Clone;
    /// Listens on a socket.
    //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>;

    /// Returns an iterator of streams.
    fn accept(&mut self) -> io::Result<Self::Stream>;

    /// Get the address this Listener ended up listening on.
    fn local_addr(&mut self) -> io::Result<SocketAddr>;

    /// Closes the Acceptor, so no more incoming connections will be handled.
//    fn close(&mut self) -> io::Result<()>;

    /// Returns an iterator over incoming connections.
    fn incoming(&mut self) -> NetworkConnections<Self> {
        NetworkConnections(self)
    }
}

/// An iterator wrapper over a NetworkAcceptor.
pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N);

impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> {
    type Item = io::Result<N::Stream>;
    fn next(&mut self) -> Option<io::Result<N::Stream>> {
        Some(self.0.accept())
    }
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Read + Write + Any + StreamClone + Send + Typeable {
    /// Get the remote address of the underlying connection.
    fn peer_addr(&mut self) -> io::Result<SocketAddr>;
}

#[doc(hidden)]
pub trait StreamClone {
    fn clone_box(&self) -> Box<NetworkStream + Send>;
}

impl<T: NetworkStream + Send + Clone> StreamClone for T {
    #[inline]
    fn clone_box(&self) -> Box<NetworkStream + Send> {
        Box::new(self.clone())
    }
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector {
    /// Type of Stream to create
    type Stream: NetworkStream + Send;
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
}

impl fmt::Debug for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl Clone for Box<NetworkStream + Send> {
    #[inline]
    fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
}

impl NetworkStream + Send {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(traitobject::data(self))
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(traitobject::data_mut(self))
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream + Send>) -> Box<T>  {
        let raw: *mut NetworkStream = mem::transmute(self);
        mem::transmute(traitobject::data_mut(raw))
    }
}

impl NetworkStream + Send {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        (*self).get_type() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    pub fn downcast<T: Any>(self: Box<NetworkStream + Send>)
            -> Result<Box<T>, Box<NetworkStream + Send>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub enum HttpListener {
    /// Http variant.
    Http(TcpListener),
    /// Https variant. The two paths point to the certificate and key PEM files, in that order.
    Https(TcpListener, Arc<SslContext>)
}

impl Clone for HttpListener {
    fn clone(&self) -> HttpListener {
        match *self {
            HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()),
            HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()),
        }
    }
}

impl HttpListener {

    /// Start listening to an address over HTTP.
    pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> {
        Ok(HttpListener::Http(try!(TcpListener::bind(addr))))
    }

    /// Start listening to an address over HTTPS.
    pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> {
        let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
        try_some!(ssl_context.set_cipher_list("DEFAULT").map(lift_ssl_error));
        try_some!(ssl_context.set_certificate_file(
                cert, X509FileType::PEM).map(lift_ssl_error));
        try_some!(ssl_context.set_private_key_file(
                key, X509FileType::PEM).map(lift_ssl_error));
        ssl_context.set_verify(SslVerifyNone, None);
        Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
    }
}

impl NetworkListener for HttpListener {
    type Stream = HttpStream;

    #[inline]
    fn accept(&mut self) -> io::Result<HttpStream> {
        Ok(match *self {
            HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)),
            HttpListener::Https(ref mut tcp, ref ssl_context) => {
                let stream = CloneTcpStream(try!(tcp.accept()).0);
                match SslStream::new_server(&**ssl_context, stream) {
                    Ok(ssl_stream) => HttpStream::Https(ssl_stream),
                    Err(StreamError(e)) => {
                        return Err(io::Error::new(io::ErrorKind::ConnectionAborted,
                                                  e));
                    },
                    Err(e) => return Err(lift_ssl_error(e))
                }
            }
        })
    }

    #[inline]
    fn local_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpListener::Http(ref mut tcp) => tcp.local_addr(),
            HttpListener::Https(ref mut tcp, _) => tcp.local_addr(),
        }
    }
}

#[doc(hidden)]
pub struct CloneTcpStream(TcpStream);

impl Clone for CloneTcpStream{
    #[inline]
    fn clone(&self) -> CloneTcpStream {
        CloneTcpStream(self.0.try_clone().unwrap())
    }
}

impl Read for CloneTcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for CloneTcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(CloneTcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<CloneTcpStream>),
}

impl Read for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.read(buf),
            HttpStream::Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Write for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.write(msg),
            HttpStream::Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.flush(),
            HttpStream::Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.0.peer_addr(),
            HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr()
        }
    }
}

/// A connector that will produce HttpStreams.
#[allow(missing_copy_implementations)]
pub struct HttpConnector<'v>(pub Option<ContextVerifier<'v>>);

/// A method that can set verification methods on an SSL context
pub type ContextVerifier<'v> = Box<FnMut(&mut SslContext) -> ()+'v>;

impl<'v> NetworkConnector for HttpConnector<'v> {
    type Stream = HttpStream;

    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {
        let addr = &(host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
            },
            "https" => {
                debug!("https scheme");
                let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                if let Some(ref mut verifier) = self.0 {
                    verifier(&mut context);
                }
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(HttpStream::Https(stream))
            },
            _ => {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                "Invalid scheme for Http"))
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> io::Error {
    debug!("lift_ssl_error: {:?}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted,
                                         "SSL Connection Closed"),
        e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e)
    }
}

#[cfg(test)]
mod tests {
    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = stream.downcast::<MockStream>().ok().unwrap();
        assert_eq!(mock, Box::new(MockStream::new()));

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, Box::new(MockStream::new()));

    }

}
<commit_msg>chore(net): Upgrading to latest rust openssl 0.6.0<commit_after>//! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, TypeId};
use std::fmt;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener};
use std::mem;
use std::path::Path;
use std::sync::Arc;

use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE};
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};
use openssl::x509::X509FileType;

use typeable::Typeable;
use {traitobject};

/// The write-status indicating headers have not been written.
pub enum Fresh {}

/// The write-status indicating headers have been written.
pub enum Streaming {}

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener: Clone {
    /// The stream produced for each connection.
    type Stream: NetworkStream + Send + Clone;
    /// Listens on a socket.
    //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>;

    /// Returns an iterator of streams.
    fn accept(&mut self) -> io::Result<Self::Stream>;

    /// Get the address this Listener ended up listening on.
    fn local_addr(&mut self) -> io::Result<SocketAddr>;

    /// Closes the Acceptor, so no more incoming connections will be handled.
//    fn close(&mut self) -> io::Result<()>;

    /// Returns an iterator over incoming connections.
    fn incoming(&mut self) -> NetworkConnections<Self> {
        NetworkConnections(self)
    }
}

/// An iterator wrapper over a NetworkAcceptor.
pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N);

impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> {
    type Item = io::Result<N::Stream>;
    fn next(&mut self) -> Option<io::Result<N::Stream>> {
        Some(self.0.accept())
    }
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Read + Write + Any + StreamClone + Send + Typeable {
    /// Get the remote address of the underlying connection.
    fn peer_addr(&mut self) -> io::Result<SocketAddr>;
}

#[doc(hidden)]
pub trait StreamClone {
    fn clone_box(&self) -> Box<NetworkStream + Send>;
}

impl<T: NetworkStream + Send + Clone> StreamClone for T {
    #[inline]
    fn clone_box(&self) -> Box<NetworkStream + Send> {
        Box::new(self.clone())
    }
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector {
    /// Type of Stream to create
    type Stream: NetworkStream + Send;
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
}

impl fmt::Debug for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl Clone for Box<NetworkStream + Send> {
    #[inline]
    fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
}

impl NetworkStream + Send {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(traitobject::data(self))
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(traitobject::data_mut(self))
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream + Send>) -> Box<T>  {
        let raw: *mut NetworkStream = mem::transmute(self);
        mem::transmute(traitobject::data_mut(raw))
    }
}

impl NetworkStream + Send {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        (*self).get_type() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    pub fn downcast<T: Any>(self: Box<NetworkStream + Send>)
            -> Result<Box<T>, Box<NetworkStream + Send>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub enum HttpListener {
    /// Http variant.
    Http(TcpListener),
    /// Https variant. The two paths point to the certificate and key PEM files, in that order.
    Https(TcpListener, Arc<SslContext>)
}

impl Clone for HttpListener {
    fn clone(&self) -> HttpListener {
        match *self {
            HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()),
            HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()),
        }
    }
}

impl HttpListener {

    /// Start listening to an address over HTTP.
    pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> {
        Ok(HttpListener::Http(try!(TcpListener::bind(addr))))
    }

    /// Start listening to an address over HTTPS.
    pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> {
        let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
        try!(ssl_context.set_cipher_list("DEFAULT").map_err(lift_ssl_error));
        try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error));
        try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error));
        ssl_context.set_verify(SSL_VERIFY_NONE, None);
        Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
    }
}

impl NetworkListener for HttpListener {
    type Stream = HttpStream;

    #[inline]
    fn accept(&mut self) -> io::Result<HttpStream> {
        Ok(match *self {
            HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)),
            HttpListener::Https(ref mut tcp, ref ssl_context) => {
                let stream = CloneTcpStream(try!(tcp.accept()).0);
                match SslStream::new_server(&**ssl_context, stream) {
                    Ok(ssl_stream) => HttpStream::Https(ssl_stream),
                    Err(StreamError(e)) => {
                        return Err(io::Error::new(io::ErrorKind::ConnectionAborted,
                                                  e));
                    },
                    Err(e) => return Err(lift_ssl_error(e))
                }
            }
        })
    }

    #[inline]
    fn local_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpListener::Http(ref mut tcp) => tcp.local_addr(),
            HttpListener::Https(ref mut tcp, _) => tcp.local_addr(),
        }
    }
}

#[doc(hidden)]
pub struct CloneTcpStream(TcpStream);

impl Clone for CloneTcpStream{
    #[inline]
    fn clone(&self) -> CloneTcpStream {
        CloneTcpStream(self.0.try_clone().unwrap())
    }
}

impl Read for CloneTcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for CloneTcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(CloneTcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<CloneTcpStream>),
}

impl Read for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.read(buf),
            HttpStream::Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Write for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.write(msg),
            HttpStream::Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.flush(),
            HttpStream::Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.0.peer_addr(),
            HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr()
        }
    }
}

/// A connector that will produce HttpStreams.
#[allow(missing_copy_implementations)]
pub struct HttpConnector<'v>(pub Option<ContextVerifier<'v>>);

/// A method that can set verification methods on an SSL context
pub type ContextVerifier<'v> = Box<FnMut(&mut SslContext) -> ()+'v>;

impl<'v> NetworkConnector for HttpConnector<'v> {
    type Stream = HttpStream;

    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {
        let addr = &(host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
            },
            "https" => {
                debug!("https scheme");
                let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                if let Some(ref mut verifier) = self.0 {
                    verifier(&mut context);
                }
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(HttpStream::Https(stream))
            },
            _ => {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                "Invalid scheme for Http"))
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> io::Error {
    debug!("lift_ssl_error: {:?}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted,
                                         "SSL Connection Closed"),
        e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e)
    }
}

#[cfg(test)]
mod tests {
    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = stream.downcast::<MockStream>().ok().unwrap();
        assert_eq!(mock, Box::new(MockStream::new()));

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, Box::new(MockStream::new()));

    }

}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use rand::{CryptoRng, Rng};

use poly::{eval, generate, y_intercept};

/// Split a secret into N shares, of which K are required to re-combine. Returns
/// a map of share IDs to share values.
pub fn split<R>(n: u8, k: u8, secret: &[u8], rng: &mut R) -> HashMap<u8, Vec<u8>>
where
    R: Rng + CryptoRng,
{
    // Generate a random K-degree polynomial for each byte of the secret.
    let polys = secret
        .iter()
        .map(|&b| generate((k - 1) as usize, b, rng))
        .collect::<Vec<Vec<u8>>>();

    // Collect the evaluation of each polynomial with the share ID as the input.
    (1..=n)
        .map(|id| (id, polys.iter().map(|p| eval(p, id)).collect()))
        .collect()
}

/// Combine a map of share IDs into the original secret.
///
/// N.B.: There is no way to know if this is successful or not.
pub fn combine<S: ::std::hash::BuildHasher>(shares: &HashMap<u8, Vec<u8>, S>) -> Vec<u8> {
    let len = shares.values().next().unwrap().len();
    if shares.values().any(|v| v.len() != len) {
        panic!("mismatched share lengths")
    }

    (0..len)
        .map(|i| y_intercept(shares.iter().map(|(&id, v)| (id, v[i])).collect()))
        .collect()
}

#[cfg(test)]
mod test {
    extern crate itertools;
    extern crate proptest;
    extern crate rand_chacha;

    use rand::SeedableRng;

    use super::*;

    use self::itertools::Itertools;
    use self::proptest::prelude::*;
    use self::rand_chacha::ChaChaRng;

    proptest! {
        #[test]
        fn test_split(secret: Vec<u8>, seed: [u8; 32]) {
            let mut rng = ChaChaRng::from_seed(seed);
            let splits = split(5, 3, &secret, &mut rng);

            for i in 5..=3 {
                for keys in splits.keys().combinations(i) {
                    let mut subset = HashMap::new();
                    for &key in keys {
                        subset.insert(key, splits.get(&key).unwrap().to_vec());
                    }
                    assert_eq!(combine(&subset), secret);
                }
            }

            for i in 2..=1 {
                for keys in splits.keys().combinations(i) {
                    let mut subset = HashMap::new();
                    for &key in keys {
                        subset.insert(key, splits.get(&key).unwrap().to_vec());
                    }
                    assert_ne!(combine(&subset), secret);
                }
            }
        }
    }

    #[test]
    fn test_combine() {
        let mut shares = HashMap::new();
        shares.insert(1, vec![64, 163, 216, 189, 193]);
        shares.insert(3, vec![194, 250, 117, 212, 82]);
        shares.insert(5, vec![95, 17, 153, 111, 252]);

        assert_eq!(combine(&shares), vec![1, 2, 3, 4, 5])
    }
}
<commit_msg>Simplify type parameter.<commit_after>use std::collections::HashMap;
use std::hash::BuildHasher;

use rand::{CryptoRng, Rng};

use poly::{eval, generate, y_intercept};

/// Split a secret into N shares, of which K are required to re-combine. Returns
/// a map of share IDs to share values.
pub fn split<R>(n: u8, k: u8, secret: &[u8], rng: &mut R) -> HashMap<u8, Vec<u8>>
where
    R: Rng + CryptoRng,
{
    // Generate a random K-degree polynomial for each byte of the secret.
    let polys = secret
        .iter()
        .map(|&b| generate((k - 1) as usize, b, rng))
        .collect::<Vec<Vec<u8>>>();

    // Collect the evaluation of each polynomial with the share ID as the input.
    (1..=n)
        .map(|id| (id, polys.iter().map(|p| eval(p, id)).collect()))
        .collect()
}

/// Combine a map of share IDs into the original secret.
///
/// N.B.: There is no way to know if this is successful or not.
pub fn combine<S>(shares: &HashMap<u8, Vec<u8>, S>) -> Vec<u8>
where
    S: BuildHasher,
{
    let len = shares.values().next().unwrap().len();
    if shares.values().any(|v| v.len() != len) {
        panic!("mismatched share lengths")
    }

    (0..len)
        .map(|i| y_intercept(shares.iter().map(|(&id, v)| (id, v[i])).collect()))
        .collect()
}

#[cfg(test)]
mod test {
    extern crate itertools;
    extern crate proptest;
    extern crate rand_chacha;

    use rand::SeedableRng;

    use super::*;

    use self::itertools::Itertools;
    use self::proptest::prelude::*;
    use self::rand_chacha::ChaChaRng;

    proptest! {
        #[test]
        fn test_split(secret: Vec<u8>, seed: [u8; 32]) {
            let mut rng = ChaChaRng::from_seed(seed);
            let splits = split(5, 3, &secret, &mut rng);

            for i in 5..=3 {
                for keys in splits.keys().combinations(i) {
                    let mut subset = HashMap::new();
                    for &key in keys {
                        subset.insert(key, splits.get(&key).unwrap().to_vec());
                    }
                    assert_eq!(combine(&subset), secret);
                }
            }

            for i in 2..=1 {
                for keys in splits.keys().combinations(i) {
                    let mut subset = HashMap::new();
                    for &key in keys {
                        subset.insert(key, splits.get(&key).unwrap().to_vec());
                    }
                    assert_ne!(combine(&subset), secret);
                }
            }
        }
    }

    #[test]
    fn test_combine() {
        let mut shares = HashMap::new();
        shares.insert(1, vec![64, 163, 216, 189, 193]);
        shares.insert(3, vec![194, 250, 117, 212, 82]);
        shares.insert(5, vec![95, 17, 153, 111, 252]);

        assert_eq!(combine(&shares), vec![1, 2, 3, 4, 5])
    }
}
<|endoftext|>


<commit_before>//! Raw and high-level instruction abstractions

/// First register in an opcode
///
/// There are 16 registers, `V0`..`VF`
pub type Vx = u8;
/// Second register in an opcode
pub type Vy = u8;
/// Absolute memory address
///
/// Valid addresses are within `0x0` .. `0xFFF`.
pub type Addr = u16;
/// A byte
///
/// Valid values are within `0x0` .. `0xFF`.
pub type Byte = u8;
/// A nibble (hex digit)
///
/// Valid values are within `0x0` .. `0xF`.
pub type Nibble = u8;

/// Raw instruction
///
/// Helper around the raw bits, not necessarily a valid instruction.
#[derive(Copy)]
pub struct RawInstruction {
    bits: u16
}

impl RawInstruction {
    /// Creates a new raw instruction without any checks of the `bits`
    pub fn new(bits: u16) -> RawInstruction {
        RawInstruction{ bits: bits }
    }

    /// The *raw bits*
    #[allow(dead_code)]
    pub fn bits(&self) -> u16 {
        self.bits
    }

    /// The *address bits* part
    pub fn addr(&self) -> Addr {
        self.bits & 0x0FFF
    }

    /// The *index of the `Vx` register* part
    pub fn x(&self) -> Vx {
        ((self.bits & 0x0F00) >> 8) as u8
    }

    /// The *index of the `Vy` register* part
    pub fn y(&self) -> Vy {
        ((self.bits & 0x00F0) >> 4) as u8
    }

    /// The *high nibble* part
    pub fn n_high(&self) -> Nibble {
        ((self.bits & 0xF000) >> 12) as u8
    }

    /// The *low nibble* part
    pub fn n_low(&self) -> Nibble {
        (self.bits & 0x000F) as u8
    }

    /// The *`k` byte* part
    pub fn k(&self) -> Byte {
        (self.bits & 0x00FF) as u8
    }
}

/// High-level instruction
///
/// A valid instruction that can be executed as-is.
#[derive(Copy,Debug)]
pub enum Instruction {
    Sys(Addr),              // 0nnn - SYS addr
    Clear,                  // 00E0 - CLS
    Return,                 // 00EE - RET
    Jump(Addr),             // 1nnn - JP addr
    Call(Addr),             // 2nnn - CALL addr
    SkipEqualK(Vx, Byte),   // 3xkk - SE Vx, byte
    SkipNotEqualK(Vx, Byte),// 4xkk - SNE Vx, byte
    SkipEqual(Vx, Vy),      // 5xy0 - SE Vx, Vy
    SetK(Vx, Byte),         // 6xkk - LD Vx, byte
    AddK(Vx, Byte),         // 7xkk - ADD Vx, byte
    Set(Vx, Vy),            // 8xy0 - LD Vx, Vy
    Or(Vx, Vy),             // 8xy1 - OR Vx, Vy
    And(Vx, Vy),            // 8xy2 - AND Vx, Vy
    XOr(Vx, Vy),            // 8xy3 - XOR Vx, Vy
    Add(Vx, Vy),            // 8xy4 - ADD Vx, Vy
    Sub(Vx, Vy),            // 8xy5 - SUB Vx, Vy
    ShiftRight(Vx, Vy),     // 8xy6 - SHR Vx {, Vy}
    SubInv(Vx, Vy),         // 8xy7 - SUBN Vx, Vy
    ShiftLeft(Vx, Vy),      // 8xyE - SHL Vx {, Vy}
    SkipNotEqual(Vx, Vy),   // 9xy0 - SNE Vx, Vy
    LoadI(Addr),            // Annn - LD I, addr
    LongJump(Addr),         // Bnnn - JP V0, addr
    Rand(Vx, Byte),         // Cxkk - RND Vx, byte
    Draw(Vx, Vy, Nibble),   // Dxyn - DRW Vx, Vy, nibble
    SkipPressed(Vx),        // Ex9E - SKP Vx
    SkipNotPressed(Vx),     // ExA1 - SKNP Vx
    GetTimer(Vx),           // Fx07 - LD Vx, DT
    WaitKey(Vx),            // Fx0A - LD Vx, K
    SetTimer(Vx),           // Fx15 - LD DT, Vx
    SetSoundTimer(Vx),      // Fx18 - LD ST, Vx
    AddToI(Vx),             // Fx1E - ADD I, Vx
    LoadHexGlyph(Vx),       // Fx29 - LD F, Vx
    StoreBCD(Vx),           // Fx33 - LD B, Vx
    StoreRegisters(Vx),     // Fx55 - LD [I], Vx
    LoadRegisters(Vx),      // Fx65 - LD Vx, [I]
    Unknown,
}

impl Instruction {
    /// Creates a new instruction from raw bits,
    /// or `Instruction::Unknown` if no valid match could be found
    pub fn from_raw(raw: &RawInstruction) -> Instruction {
        use self::Instruction::*;

        match raw.n_high() {
            0x0 => {
                match raw.k() {
                    0xE0 => Clear,
                    0xEE => Return,
                    _ => Sys(raw.addr())
                }
            },
            0x1 => Jump(raw.addr()),
            0x2 => Call(raw.addr()),
            0x3 => SkipEqualK(raw.x(), raw.k()),
            0x4 => SkipNotEqualK(raw.x(), raw.k()),
            0x5 => SkipEqual(raw.x(), raw.y()),
            0x6 => SetK(raw.x(), raw.k()),
            0x7 => AddK(raw.x(), raw.k()),
            0x8 => {
                match raw.n_low() {
                    0x0 => Set(raw.x(), raw.y()),
                    0x1 => Or(raw.x(), raw.y()),
                    0x2 => And(raw.x(), raw.y()),
                    0x3 => XOr(raw.x(), raw.y()),
                    0x4 => Add(raw.x(), raw.y()),
                    0x5 => Sub(raw.x(), raw.y()),
                    0x6 => ShiftRight(raw.x(), raw.y()),
                    0x7 => SubInv(raw.x(), raw.y()),
                    0xE => ShiftLeft(raw.x(), raw.y()),
                    _ => Unknown
                }
            },
            0x9 => SkipNotEqual(raw.x(), raw.y()),
            0xA => LoadI(raw.addr()),
            0xB => LongJump(raw.addr()),
            0xC => Rand(raw.x(), raw.k()),
            0xD => Draw(raw.x(), raw.y(), raw.n_low()),
            0xE => {
                match raw.k() {
                    0x9E => SkipPressed(raw.x()),
                    0xA1 => SkipNotPressed(raw.x()),
                    _ => Unknown,
                }
            },
            0xF => {
                match raw.k() {
                    0x07 => GetTimer(raw.x()),
                    0x0A => WaitKey(raw.x()),
                    0x15 => SetTimer(raw.x()),
                    0x18 => SetSoundTimer(raw.x()),
                    0x1E => AddToI(raw.x()),
                    0x29 => LoadHexGlyph(raw.x()),
                    0x33 => StoreBCD(raw.x()),
                    0x55 => StoreRegisters(raw.x()),
                    0x65 => LoadRegisters(raw.x()),
                    _ => Unknown,
                }
            }
            _ => Unknown
        }
    }
}
<commit_msg>Clarify rustdoc of `RawInstruction::x()` and `::y()`<commit_after>//! Raw and high-level instruction abstractions

/// First register in an opcode
///
/// There are 16 registers, `V0`..`VF`
pub type Vx = u8;
/// Second register in an opcode
pub type Vy = u8;
/// Absolute memory address
///
/// Valid addresses are within `0x0` .. `0xFFF`.
pub type Addr = u16;
/// A byte
///
/// Valid values are within `0x0` .. `0xFF`.
pub type Byte = u8;
/// A nibble (hex digit)
///
/// Valid values are within `0x0` .. `0xF`.
pub type Nibble = u8;

/// Raw instruction
///
/// Helper around the raw bits, not necessarily a valid instruction.
#[derive(Copy)]
pub struct RawInstruction {
    bits: u16
}

impl RawInstruction {
    /// Creates a new raw instruction without any checks of the `bits`
    pub fn new(bits: u16) -> RawInstruction {
        RawInstruction{ bits: bits }
    }

    /// The *raw bits*
    #[allow(dead_code)]
    pub fn bits(&self) -> u16 {
        self.bits
    }

    /// The *address bits* part
    pub fn addr(&self) -> Addr {
        self.bits & 0x0FFF
    }

    /// The *`Vx` register-index* part, i.e. `0xE` is `VE`
    pub fn x(&self) -> Vx {
        ((self.bits & 0x0F00) >> 8) as u8
    }

    /// The *`Vy` register-index* part, i.e. `0xE` is `VE`
    pub fn y(&self) -> Vy {
        ((self.bits & 0x00F0) >> 4) as u8
    }

    /// The *high nibble* part
    pub fn n_high(&self) -> Nibble {
        ((self.bits & 0xF000) >> 12) as u8
    }

    /// The *low nibble* part
    pub fn n_low(&self) -> Nibble {
        (self.bits & 0x000F) as u8
    }

    /// The *`k` byte* part
    pub fn k(&self) -> Byte {
        (self.bits & 0x00FF) as u8
    }
}

/// High-level instruction
///
/// A valid instruction that can be executed as-is.
#[derive(Copy,Debug)]
pub enum Instruction {
    Sys(Addr),              // 0nnn - SYS addr
    Clear,                  // 00E0 - CLS
    Return,                 // 00EE - RET
    Jump(Addr),             // 1nnn - JP addr
    Call(Addr),             // 2nnn - CALL addr
    SkipEqualK(Vx, Byte),   // 3xkk - SE Vx, byte
    SkipNotEqualK(Vx, Byte),// 4xkk - SNE Vx, byte
    SkipEqual(Vx, Vy),      // 5xy0 - SE Vx, Vy
    SetK(Vx, Byte),         // 6xkk - LD Vx, byte
    AddK(Vx, Byte),         // 7xkk - ADD Vx, byte
    Set(Vx, Vy),            // 8xy0 - LD Vx, Vy
    Or(Vx, Vy),             // 8xy1 - OR Vx, Vy
    And(Vx, Vy),            // 8xy2 - AND Vx, Vy
    XOr(Vx, Vy),            // 8xy3 - XOR Vx, Vy
    Add(Vx, Vy),            // 8xy4 - ADD Vx, Vy
    Sub(Vx, Vy),            // 8xy5 - SUB Vx, Vy
    ShiftRight(Vx, Vy),     // 8xy6 - SHR Vx {, Vy}
    SubInv(Vx, Vy),         // 8xy7 - SUBN Vx, Vy
    ShiftLeft(Vx, Vy),      // 8xyE - SHL Vx {, Vy}
    SkipNotEqual(Vx, Vy),   // 9xy0 - SNE Vx, Vy
    LoadI(Addr),            // Annn - LD I, addr
    LongJump(Addr),         // Bnnn - JP V0, addr
    Rand(Vx, Byte),         // Cxkk - RND Vx, byte
    Draw(Vx, Vy, Nibble),   // Dxyn - DRW Vx, Vy, nibble
    SkipPressed(Vx),        // Ex9E - SKP Vx
    SkipNotPressed(Vx),     // ExA1 - SKNP Vx
    GetTimer(Vx),           // Fx07 - LD Vx, DT
    WaitKey(Vx),            // Fx0A - LD Vx, K
    SetTimer(Vx),           // Fx15 - LD DT, Vx
    SetSoundTimer(Vx),      // Fx18 - LD ST, Vx
    AddToI(Vx),             // Fx1E - ADD I, Vx
    LoadHexGlyph(Vx),       // Fx29 - LD F, Vx
    StoreBCD(Vx),           // Fx33 - LD B, Vx
    StoreRegisters(Vx),     // Fx55 - LD [I], Vx
    LoadRegisters(Vx),      // Fx65 - LD Vx, [I]
    Unknown,
}

impl Instruction {
    /// Creates a new instruction from raw bits,
    /// or `Instruction::Unknown` if no valid match could be found
    pub fn from_raw(raw: &RawInstruction) -> Instruction {
        use self::Instruction::*;

        match raw.n_high() {
            0x0 => {
                match raw.k() {
                    0xE0 => Clear,
                    0xEE => Return,
                    _ => Sys(raw.addr())
                }
            },
            0x1 => Jump(raw.addr()),
            0x2 => Call(raw.addr()),
            0x3 => SkipEqualK(raw.x(), raw.k()),
            0x4 => SkipNotEqualK(raw.x(), raw.k()),
            0x5 => SkipEqual(raw.x(), raw.y()),
            0x6 => SetK(raw.x(), raw.k()),
            0x7 => AddK(raw.x(), raw.k()),
            0x8 => {
                match raw.n_low() {
                    0x0 => Set(raw.x(), raw.y()),
                    0x1 => Or(raw.x(), raw.y()),
                    0x2 => And(raw.x(), raw.y()),
                    0x3 => XOr(raw.x(), raw.y()),
                    0x4 => Add(raw.x(), raw.y()),
                    0x5 => Sub(raw.x(), raw.y()),
                    0x6 => ShiftRight(raw.x(), raw.y()),
                    0x7 => SubInv(raw.x(), raw.y()),
                    0xE => ShiftLeft(raw.x(), raw.y()),
                    _ => Unknown
                }
            },
            0x9 => SkipNotEqual(raw.x(), raw.y()),
            0xA => LoadI(raw.addr()),
            0xB => LongJump(raw.addr()),
            0xC => Rand(raw.x(), raw.k()),
            0xD => Draw(raw.x(), raw.y(), raw.n_low()),
            0xE => {
                match raw.k() {
                    0x9E => SkipPressed(raw.x()),
                    0xA1 => SkipNotPressed(raw.x()),
                    _ => Unknown,
                }
            },
            0xF => {
                match raw.k() {
                    0x07 => GetTimer(raw.x()),
                    0x0A => WaitKey(raw.x()),
                    0x15 => SetTimer(raw.x()),
                    0x18 => SetSoundTimer(raw.x()),
                    0x1E => AddToI(raw.x()),
                    0x29 => LoadHexGlyph(raw.x()),
                    0x33 => StoreBCD(raw.x()),
                    0x55 => StoreRegisters(raw.x()),
                    0x65 => LoadRegisters(raw.x()),
                    _ => Unknown,
                }
            }
            _ => Unknown
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "protobuf", vers = "0.1.0")];
#[crate_type = "lib"];
#[feature(globs)];
#[feature(managed_boxes)];

#[desc = "protobuf implementation for rust"];
#[license = "BSD"];
#[author = "Stepan Koltsov"];

pub use core::*;

mod core;
pub mod descriptor;
pub mod codegen;
pub mod rt;
mod misc;
mod zigzag;
mod hex;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test;

// so `use protobuf::*` could work in descriptor mod
pub mod protobuf {
    pub use core::*;
    pub use rt;
}
<commit_msg>Export modules<commit_after>#[link(name = "protobuf", vers = "0.1.0")];
#[crate_type = "lib"];
#[feature(globs)];
#[feature(managed_boxes)];

#[desc = "protobuf implementation for rust"];
#[license = "BSD"];
#[author = "Stepan Koltsov"];

pub use core::*;

mod core;
pub mod descriptor;
pub mod codegen;
pub mod rt;
mod misc;
mod zigzag;
mod hex;

#[cfg(test)]
mod shrug;
#[cfg(test)]
mod test;

// so `use protobuf::*` could work in descriptor mod
pub mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use core::*;
    pub use rt;
}
<|endoftext|>