<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<CString>>,
    pub finished: Arc<Mutex<bool>>,
}

#[no_mangle]
pub extern "C" fn create_console_reader() -> Box<ConsoleInput> {
	use std::thread;
	let buffer_arc: Arc<Mutex<CString>> = Arc::new(Mutex::new(CString::new("").unwrap()));
	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();

	//let mut cmds: String = String::new();
	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 1 == buffer.len() { break 'console };
					let arc = buffer_arc.clone();
					let mut writer = arc.lock().unwrap();
					let mut new_string: String = (*writer).clone().into_string().unwrap();
					new_string.push_str(&buffer);
					*writer = CString::new(new_string).unwrap();
					std::thread::yield_now();
				},
				Err(e) => println!("Error: {:?}", e),
			}
		    std::thread::yield_now();
		}
		println!("Console closed");
		let finished = finished_arc.clone();
		let mut finished_lock = finished.lock().unwrap();
		*finished_lock = true;
	    return 0;
	});

	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
}

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

#[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>Added win32 support for console<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(_) => {
					if 2 == 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
}

#[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()
}

#[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>extern crate nalgebra;
extern crate rand;
use rand::*;
use nalgebra::*;

mod csv;
mod koe;
mod central_body;
mod tickable;
use std::f64::consts::PI;
use std::rc::*;
use central_body::*;
use csv::*;
use koe::*;
use tickable::*;

#[test]
fn koe_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut a_ok = 0;
    let mut e_ok = 0;
    let mut inc_ok = 0;
    let mut lan_ok = 0;
    let mut ap_ok = 0;
    let mut m0_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
            a_ok += 1;
        }
        if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
            e_ok += 1;
        }
        if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
            inc_ok += 1;
        }
        if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
            lan_ok += 1;
        }
        if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
            ap_ok += 1;
        }
        if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
            m0_ok += 1;
        }
    }
    let a_ok_f = a_ok as f32 / iterations as f32;
    let e_ok_f = e_ok as f32 / iterations as f32;
    let inc_ok_f = inc_ok as f32 / iterations as f32;
    let lan_ok_f = lan_ok as f32 / iterations as f32;
    let ap_ok_f = ap_ok as f32 / iterations as f32;
    let m0_ok_f = m0_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if a_ok_f < threshold {
        println!("a_ok_f = {}", a_ok_f);
        if !failed {
            failed = true;
        }
    }
    if e_ok_f < threshold {
        println!("e_ok_f = {}", e_ok_f);
        if !failed {
            failed = true;
        }
    }
    if inc_ok_f < threshold {
        println!("inc_ok_f = {}", inc_ok_f);
        if !failed {
            failed = true;
        }
    }
    if ap_ok_f < threshold {
        println!("ap_ok_f = {}", ap_ok_f);
        if !failed {
            failed = true;
        }
    }
    if m0_ok_f < threshold {
        println!("m0_ok_f = {}", m0_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for one of the parameters is below threshold");
    }
}

#[test]
fn csv_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut r_ok = 0;
    let mut v_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        let csv1 = koe1.to_csv();
        if csv0.r.approx_eq_eps(&csv1.r, &eps) {
            r_ok += 1;
        }
        if csv0.v.approx_eq_eps(&csv1.v, &eps) {
            v_ok += 1;
        }
    }
    let r_ok_f = r_ok as f32 / iterations as f32;
    let v_ok_f = v_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if r_ok_f < threshold {
        println!("r_ok_f = {}", r_ok_f);
        if !failed {
            failed = true;
        }
    }
    if v_ok_f < threshold {
        println!("v_ok_f = {}", v_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for some of the parameters is below the threshold");
    }
}

fn get_random_cb() -> CentralBody {
    let mut rng = thread_rng();
    let up = normalize(
            &Vec3::new( // Up vector
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0)
                )
        );
    let x_axis = Vec3::<f64>::new(1.0, 0.0, 0.0);
    let reference = normalize(&cross(&x_axis, &up));
    CentralBody::new(
        rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
        up,
        reference
    )
}

fn get_random_koe(cb: Rc<CentralBody>) -> KOE {
    let mut rng = thread_rng();
    let ecc = rng.gen_range(0.0, 1.0);
    let inc = rng.gen_range(0.0, PI);
    let mut lan = rng.gen_range(0.0, 2.0*PI);
    let mut ap = rng.gen_range(0.0, 2.0*PI);
    if approx_eq(&ecc, &0.0) {
        ap = 0.0;
    }
    if approx_eq(&inc, &0.0) {
        lan = 0.0;
        ap = 0.0;
        if !approx_eq(&ecc, &0.0) {
            ap = rng.gen_range(0.0, 2.0*PI);
        }
    }
    KOE::new(
        rng.gen_range(1.0, 1.0e10), // Semi major axis
        ecc, // Eccentricity
        inc, // Inclination
        lan, // Longitude of Ascending Node
        ap,  // Argument of Periapsis
        rng.gen_range(-PI, PI), // Mean anomaly
        cb
    )
}
<commit_msg>Add tests module<commit_after>extern crate nalgebra;
extern crate rand;

mod csv;
mod koe;
mod central_body;
mod tickable;

#[cfg(test)]
mod tests {
    use std::f64::consts::PI;
    use std::rc::*;
    use central_body::*;
    use csv::*;
    use koe::*;
    use tickable::*;
    use rand::*;
    use nalgebra::*;

    #[test]
    fn koe_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut a_ok = 0;
        let mut e_ok = 0;
        let mut inc_ok = 0;
        let mut lan_ok = 0;
        let mut ap_ok = 0;
        let mut m0_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
            let csv0 = koe0.to_csv();
            let koe1 = csv0.to_koe();
            if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
                a_ok += 1;
            }
            if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
                e_ok += 1;
            }
            if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
                inc_ok += 1;
            }
            if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
                lan_ok += 1;
            }
            if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
                ap_ok += 1;
            }
            if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
                m0_ok += 1;
            }
        }
        let a_ok_f = a_ok as f32 / iterations as f32;
        let e_ok_f = e_ok as f32 / iterations as f32;
        let inc_ok_f = inc_ok as f32 / iterations as f32;
        let lan_ok_f = lan_ok as f32 / iterations as f32;
        let ap_ok_f = ap_ok as f32 / iterations as f32;
        let m0_ok_f = m0_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if a_ok_f < threshold {
            println!("a_ok_f = {}", a_ok_f);
            if !failed {
                failed = true;
            }
        }
        if e_ok_f < threshold {
            println!("e_ok_f = {}", e_ok_f);
            if !failed {
                failed = true;
            }
        }
        if inc_ok_f < threshold {
            println!("inc_ok_f = {}", inc_ok_f);
            if !failed {
                failed = true;
            }
        }
        if lan_ok_f < threshold {
            println!("lan_ok_f = {}", lan_ok_f);
            if !failed {
                failed = true;
            }
        }
        if ap_ok_f < threshold {
            println!("ap_ok_f = {}", ap_ok_f);
            if !failed {
                failed = true;
            }
        }
        if m0_ok_f < threshold {
            println!("m0_ok_f = {}", m0_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for one of the parameters is below threshold");
        }
    }

    #[test]
    fn csv_invariance() {
        let iterations = 10000;
        let eps = 1.0e-3;
        let mut r_ok = 0;
        let mut v_ok = 0;
        for _ in 0..iterations {
            let cb = get_random_cb();
            let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
            let csv0 = koe0.to_csv();
            let koe1 = csv0.to_koe();
            let csv1 = koe1.to_csv();
            if csv0.r.approx_eq_eps(&csv1.r, &eps) {
                r_ok += 1;
            }
            if csv0.v.approx_eq_eps(&csv1.v, &eps) {
                v_ok += 1;
            }
        }
        let r_ok_f = r_ok as f32 / iterations as f32;
        let v_ok_f = v_ok as f32 / iterations as f32;
        let threshold = 0.99;
        let mut failed = false;

        println!("");
        println!("eps = {}", eps);
        println!("threshold = {}", threshold);
        if r_ok_f < threshold {
            println!("r_ok_f = {}", r_ok_f);
            if !failed {
                failed = true;
            }
        }
        if v_ok_f < threshold {
            println!("v_ok_f = {}", v_ok_f);
            if !failed {
                failed = true;
            }
        }
        if failed {
            panic!("success rate for some of the parameters is below the threshold");
        }
    }

    fn get_random_cb() -> CentralBody {
        let mut rng = thread_rng();
        let up = normalize(
                &Vec3::new( // Up vector
                    rng.gen_range(0.1, 1.0),
                    rng.gen_range(0.1, 1.0),
                    rng.gen_range(0.1, 1.0)
                    )
            );
        let x_axis = Vec3::<f64>::new(1.0, 0.0, 0.0);
        let reference = normalize(&cross(&x_axis, &up));
        CentralBody::new(
            rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
            up,
            reference
        )
    }

    fn get_random_koe(cb: Rc<CentralBody>) -> KOE {
        let mut rng = thread_rng();
        let ecc = rng.gen_range(0.0, 1.0);
        let inc = rng.gen_range(0.0, PI);
        let mut lan = rng.gen_range(0.0, 2.0*PI);
        let mut ap = rng.gen_range(0.0, 2.0*PI);
        if approx_eq(&ecc, &0.0) {
            ap = 0.0;
        }
        if approx_eq(&inc, &0.0) {
            lan = 0.0;
            ap = 0.0;
            if !approx_eq(&ecc, &0.0) {
                ap = rng.gen_range(0.0, 2.0*PI);
            }
        }
        KOE::new(
            rng.gen_range(1.0, 1.0e10), // Semi major axis
            ecc, // Eccentricity
            inc, // Inclination
            lan, // Longitude of Ascending Node
            ap,  // Argument of Periapsis
            rng.gen_range(-PI, PI), // Mean anomaly
            cb
        )
    }
}
<|endoftext|>


<commit_before>#[crate_id="wx#0.1"];
#[crate_type="lib"];

#[feature(globs)];
#[feature(managed_boxes)];

pub mod _unavailable;
pub mod _unsafe;
pub mod advanced;
pub mod base;
pub mod core;
pub mod defs;
pub mod gl;
pub mod html;
pub mod media;
pub mod net;
pub mod odbc;
pub mod propertygrid;
pub mod stc;
pub mod xrc;
<commit_msg>Fix build.<commit_after>#[crate_id="wx#0.1"];
#[crate_type="lib"];

#[feature(globs)];
#[feature(managed_boxes)];

extern crate libc;

pub mod _unavailable;
pub mod _unsafe;
pub mod advanced;
pub mod base;
pub mod core;
pub mod defs;
pub mod gl;
pub mod html;
pub mod media;
pub mod net;
pub mod odbc;
pub mod propertygrid;
pub mod stc;
pub mod xrc;
<|endoftext|>


<commit_before>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// * M. J. Beal, “Variational Algorithms for Approximate Bayesian Inference.”
/// The Gatsby Computational Neuroscience Unit, University College London, 2003,
/// pp. 265–266.
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
pub fn digamma(x: f64)-> f64 {
    // Use Horner’s method to evaluate polynomials.
    macro_rules! eval_poly(
        ($x0:expr, $coefs:expr) => (
            $coefs.iter().rev().fold(0.0, |sum, &c| $x0 * sum + c)
        );
    );

    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x * inv_x;
        x.ln() - 0.5*inv_x - inv_x_e2 * eval_poly!(inv_x_e2, [
            // The coefficients are `Bernoulli[2n] / 2n`.
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0,
        ])
    } else {
        // Shift by recurrence.
        digamma(x + 1.0) - x.recip()
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, super::digamma(0.25));
    }
}
<commit_msg>Add a couple of spaces<commit_after>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// * M. J. Beal, “Variational Algorithms for Approximate Bayesian Inference.”
/// The Gatsby Computational Neuroscience Unit, University College London, 2003,
/// pp. 265–266.
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
pub fn digamma(x: f64)-> f64 {
    // Use Horner’s method to evaluate polynomials.
    macro_rules! eval_poly(
        ($x0:expr, $coefs:expr) => (
            $coefs.iter().rev().fold(0.0, |sum, &c| $x0 * sum + c)
        );
    );

    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x * inv_x;
        x.ln() - 0.5 * inv_x - inv_x_e2 * eval_poly!(inv_x_e2, [
            // The coefficients are `Bernoulli[2n] / 2n`.
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0,
        ])
    } else {
        // Shift by recurrence.
        digamma(x + 1.0) - x.recip()
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, super::digamma(0.25));
    }
}
<|endoftext|>


<commit_before>pub fn puzzle(input: u32) -> u32 {
    0
}

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

}
<commit_msg>Abandon ship auuuggghhh<commit_after>pub fn puzzle(input: usize) -> usize {
    let mut circle = vec![1; input];
    let mut current_elf = 0;

    loop {

        let next_elf_with_presents = circle[current_elf + 1..].iter()
            .position(|&num| num != 0);
        match next_elf_with_presents {
            Some(i) => {
                let absolute_next_elf = i + current_elf + 1;
                circle[current_elf] += circle[absolute_next_elf];
                circle[absolute_next_elf] = 0;
            },
            None => {
                let next_elf_with_presents = circle[0..current_elf].iter()
                    .position(|&num| num != 0);

                match next_elf_with_presents {
                    Some(i) => {
                        circle[current_elf] += circle[i];
                        circle[i] = 0;
                    },
                    None => return current_elf + 1,
                }
            },
        }

        match circle[current_elf + 1..].iter().position(|&num| num != 0) {
            Some(i) => current_elf = i,
            None => {
                let next_elf_with_presents = circle[0..current_elf].iter()
                    .position(|&num| num != 0);

                match next_elf_with_presents {
                    Some(i) => current_elf = i,
                    None => panic!("something has gone horribly wrong"),
                }
            },
        }
    }
}

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

    #[test]
    fn two_elves() {
        let winner = puzzle(2);
        assert_eq!(winner, 1);
    }

}
<|endoftext|>


<commit_before>use std::fs::{File};
use std::string::String;
use std::path::Path;
use std::convert::{From, AsRef};
use std::io::{Read, BufReader, Write};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

#[derive(Debug)]
pub enum Error {
    IO,
    Parse,
    DataType,
    FieldType,
    Malformed,
    NotImplemented
}

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

impl From<ParseIntError> for Error {
    fn from(_: ParseIntError) -> Error {
        Error::Parse
    }
}

#[derive(Debug)]
pub enum DataType {
    XDRFloat,
    FloatLE,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
//            "xdr_float" => Ok(DataType::XDRFloat),
            _ => Err(Error::DataType)
        }
    }
}

#[derive(Debug)]
pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldType)
        }
    }
}

pub struct AVSFile {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read>
}

impl AVSFile {
    pub fn write<W: Write, T>(
                writer: &mut W, dims: &[usize], data: &[T])
                    -> Result<(), Error> {
        // header
        let ndim = dims.len();
        try!(writer.write_fmt(format_args!("# AVS FLD file (written by avsfldrs github.com/greyhill/avsfldrs)\n")));
        try!(writer.write_fmt(format_args!("ndim={}\n", ndim)));
        try!(writer.write_fmt(format_args!("veclen=1\n")));
        try!(writer.write_fmt(format_args!("nspace={}\n", ndim)));
        try!(writer.write_fmt(format_args!("field=uniform\n")));
        try!(writer.write_fmt(format_args!("data=float_le\n"))); // TODO
        for (id, size) in dims.iter().enumerate() {
            try!(writer.write_fmt(format_args!("dim{}={}\n", id+1, size)));
        }
        try!(writer.write_fmt(format_args!("{}{}", 12 as char, 12 as char)));
        let b: &[u8] = unsafe {
            std::slice::from_raw_parts(data.as_ptr() as *const u8,
                                       data.len()*mem::size_of::<T>())
        };
        try!(writer.write_all(b));
        Ok(())
    }

    pub fn read<T>(self: &mut Self) -> Result<Vec<T>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(mem::size_of::<T>()*size);
        try!(self.reader.read_to_end(&mut buf_u8));
        let buf: Vec<T> = unsafe {
            let ptr = buf_u8.as_mut_ptr();
            let cap = buf_u8.capacity();
            mem::forget(buf_u8);
            Vec::<T>::from_raw_parts(
                mem::transmute(ptr),
                size,
                cap / mem::size_of::<T>())
        };
        Ok(buf)
    }

    pub fn open<P: AsRef<Path>>(p: &P) -> Result<AVSFile, Error> {
        let path = p.as_ref();
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (12u8, 12u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match tokens[0] {
                    "ndim" => {
                        let nd = try!(tokens[1].parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    "dim1" => sizes[0] = Some(try!(tokens[1].parse::<usize>())),
                    "dim2" => sizes[1] = Some(try!(tokens[1].parse::<usize>())),
                    "dim3" => sizes[2] = Some(try!(tokens[1].parse::<usize>())),
                    "dim4" => sizes[3] = Some(try!(tokens[1].parse::<usize>())),
                    "dim5" => sizes[4] = Some(try!(tokens[1].parse::<usize>())),
                    "dim6" => sizes[5] = Some(try!(tokens[1].parse::<usize>())),
                    "dim7" => sizes[6] = Some(try!(tokens[1].parse::<usize>())),
                    "data" =>
                        data_type = Some(try!(DataType::from_str(tokens[1]))),
                    "field" =>
                        field_type = Some(try!(FieldType::from_str(tokens[1]))),
                    "variable 1 file" =>
                        external = Some(tokens[1].to_string()),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
        }
    }
}

<commit_msg>added read support for XDRFloat, Byte<commit_after>use std::fs::{File};
use std::string::String;
use std::path::Path;
use std::convert::{From, AsRef};
use std::io::{Read, BufReader, Write};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

#[derive(Debug)]
pub enum Error {
    IO,
    Parse,
    DataType,
    FieldType,
    Malformed,
    NotImplemented
}

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

impl From<ParseIntError> for Error {
    fn from(_: ParseIntError) -> Error {
        Error::Parse
    }
}

#[derive(Debug)]
pub enum DataType {
    XDRFloat,
    FloatLE,
    Byte,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
            "xdr_float" => Ok(DataType::XDRFloat),
            "byte" => Ok(DataType::Byte),
            _ => Err(Error::DataType)
        }
    }

    fn num_bytes(self: &Self) -> usize {
        match *self {
            DataType::XDRFloat => 4usize,
            DataType::FloatLE => 4usize,
            DataType::Byte => 1usize,
        }
    }

    fn convert_to_f32(self: &Self, buf: &[u8]) -> f32 {
        match *self {
            DataType::XDRFloat => {
                let b = [buf[3], buf[2], buf[1], buf[0]];
                unsafe { mem::transmute(b) }
            },
            DataType::FloatLE => {
                let b = [buf[0], buf[1], buf[2], buf[3]];
                unsafe { mem::transmute(b) }
            },
            DataType::Byte => {
                buf[0] as f32
            },
        }
    }
}

#[derive(Debug)]
pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldType)
        }
    }
}

pub struct AVSFile {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read>
}

impl AVSFile {
    pub fn write<W: Write, T>(
                writer: &mut W, dims: &[usize], data: &[T])
                    -> Result<(), Error> {
        // header
        let ndim = dims.len();
        try!(writer.write_fmt(format_args!("# AVS FLD file (written by avsfldrs github.com/greyhill/avsfldrs)\n")));
        try!(writer.write_fmt(format_args!("ndim={}\n", ndim)));
        try!(writer.write_fmt(format_args!("veclen=1\n")));
        try!(writer.write_fmt(format_args!("nspace={}\n", ndim)));
        try!(writer.write_fmt(format_args!("field=uniform\n")));
        try!(writer.write_fmt(format_args!("data=float_le\n"))); // TODO
        for (id, size) in dims.iter().enumerate() {
            try!(writer.write_fmt(format_args!("dim{}={}\n", id+1, size)));
        }
        try!(writer.write_fmt(format_args!("{}{}", 12 as char, 12 as char)));
        let b: &[u8] = unsafe {
            std::slice::from_raw_parts(data.as_ptr() as *const u8,
                                       data.len()*mem::size_of::<T>())
        };
        try!(writer.write_all(b));
        Ok(())
    }

    pub fn read_to_f32(self: &mut Self) -> Result<Vec<f32>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(size * self.data_type.num_bytes());
        let mut buf_tr = Vec::<f32>::with_capacity(size);
        try!(self.reader.read_to_end(&mut buf_u8));

        for n in 0 .. size {
            let off0 = n*self.data_type.num_bytes();
            let off1 = (n+1)*self.data_type.num_bytes();
            buf_tr.push(self.data_type.convert_to_f32(&buf_u8[off0 .. off1]));
        }

        Ok(buf_tr)
    }

    pub fn read<T>(self: &mut Self) -> Result<Vec<T>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(mem::size_of::<T>()*size);
        try!(self.reader.read_to_end(&mut buf_u8));
        let buf: Vec<T> = unsafe {
            let ptr = buf_u8.as_mut_ptr();
            let cap = buf_u8.capacity();
            Vec::<T>::from_raw_parts(
                mem::transmute(ptr),
                size,
                cap / mem::size_of::<T>())
        };
        Ok(buf)
    }

    pub fn open<P: AsRef<Path>>(p: &P) -> Result<AVSFile, Error> {
        let path = p.as_ref();
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (12u8, 12u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match tokens[0] {
                    "ndim" => {
                        let nd = try!(tokens[1].parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    "dim1" => sizes[0] = Some(try!(tokens[1].parse::<usize>())),
                    "dim2" => sizes[1] = Some(try!(tokens[1].parse::<usize>())),
                    "dim3" => sizes[2] = Some(try!(tokens[1].parse::<usize>())),
                    "dim4" => sizes[3] = Some(try!(tokens[1].parse::<usize>())),
                    "dim5" => sizes[4] = Some(try!(tokens[1].parse::<usize>())),
                    "dim6" => sizes[5] = Some(try!(tokens[1].parse::<usize>())),
                    "dim7" => sizes[6] = Some(try!(tokens[1].parse::<usize>())),
                    "data" =>
                        data_type = Some(try!(DataType::from_str(tokens[1]))),
                    "field" =>
                        field_type = Some(try!(FieldType::from_str(tokens[1]))),
                    "variable 1 file" =>
                        external = Some(tokens[1].to_string()),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
        }
    }
}

<|endoftext|>


<commit_before>/// We use this numerical type for all calculations.
pub type Num = f32;

/// Represents the state of a neuron.
#[derive(Copy, Clone)]
pub struct State {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num
}

/// At which potential the neuron fires.
const FIRE_POTENTIAL : Num = 30.0;

impl State {
    pub fn new() -> State {
        State {
            v: -70.0,
            u: -14.0
        }
    }
    pub fn potential(&self) -> Num {
        if self.v < FIRE_POTENTIAL { self.v } else { FIRE_POTENTIAL }
    }
}

/// The neuron configuration parameters.
pub struct Config {
    /// Rate of recovery.
    a: Num,

    /// Sensitivity of recovery variable `u` to the membrane potential `v`.
    b: Num,

    /// After-spike reset value of membrane potential `v`.
    c: Num,

    /// After-spike reset of recovery variable `u`.
    d: Num
}

impl Config {
    /// Generates an excitatory neuron configuration according to Izhikevich's paper [reentry]
    /// where `r` is a random variable uniformly distributed in [0, 1].
    pub fn excitatory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        let r2 = r*r;
        Config {
            a: 0.02,
            b: 0.2,
            c: -65.0 + 15.0 * r2,
            d: 8.0 - 6.0 * r2
        }
    }

    pub fn inhibitory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        Config {
            a: 0.02 + 0.08 * r,
            b: 0.25 - 0.05 * r,
            c: -65.0,
            d: 2.0
        }
    }

    /// Regular spiking (RS) cell configuration.
    pub fn regular_spiking() -> Config {
        Config::excitatory(0.0)
    }

    /// Chattering (CH) cell configuration.
    pub fn chattering() -> Config {
        Config::excitatory(1.0)
    }
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    (0.04 * v + 5.0) * v + 140.0 - u + i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b*v - u)
}

impl State {
    #[inline(always)]
    fn calc(self, dt: Num, i_syn: Num, config: &Config) -> State {
        State {
            v: self.v + dt*dv(self.u, self.v, i_syn),
            u: self.u + dt*du(self.u, self.v, config.a, config.b)
        }
    }

    /// Calculate the new state after 1 ms.
    #[inline(always)]
    pub fn step_1ms(self, i_syn: Num, config: &Config) -> State {
        if self.v < FIRE_POTENTIAL {
            self.calc(0.5, i_syn, config).calc(0.5, i_syn, config)
        }
        else {
            State {
                v: config.c,
                u: self.u + config.d
            }
        }
    }
}
<commit_msg>Add accessor for recovery variable of a neurons state.<commit_after>/// We use this numerical type for all calculations.
pub type Num = f32;

/// Represents the state of a neuron.
#[derive(Copy, Clone)]
pub struct State {
    /// membrane potential of neuron (in mV)
    v: Num,

    /// recovery variable
    u: Num
}

/// At which potential the neuron fires.
const FIRE_POTENTIAL : Num = 30.0;

impl State {
    pub fn new() -> State {
        State {
            v: -70.0,
            u: -14.0
        }
    }
    pub fn potential(&self) -> Num {
        if self.v < FIRE_POTENTIAL { self.v } else { FIRE_POTENTIAL }
    }

    pub fn recovery(&self) -> Num {
        self.u
    }
}

/// The neuron configuration parameters.
pub struct Config {
    /// Rate of recovery.
    a: Num,

    /// Sensitivity of recovery variable `u` to the membrane potential `v`.
    b: Num,

    /// After-spike reset value of membrane potential `v`.
    c: Num,

    /// After-spike reset of recovery variable `u`.
    d: Num
}

impl Config {
    /// Generates an excitatory neuron configuration according to Izhikevich's paper [reentry]
    /// where `r` is a random variable uniformly distributed in [0, 1].
    pub fn excitatory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        let r2 = r*r;
        Config {
            a: 0.02,
            b: 0.2,
            c: -65.0 + 15.0 * r2,
            d: 8.0 - 6.0 * r2
        }
    }

    pub fn inhibitory(r: Num) -> Config {
        debug_assert!(r >= 0.0 && r <= 1.0);

        Config {
            a: 0.02 + 0.08 * r,
            b: 0.25 - 0.05 * r,
            c: -65.0,
            d: 2.0
        }
    }

    /// Regular spiking (RS) cell configuration.
    pub fn regular_spiking() -> Config {
        Config::excitatory(0.0)
    }

    /// Chattering (CH) cell configuration.
    pub fn chattering() -> Config {
        Config::excitatory(1.0)
    }
}

#[inline(always)]
fn dv(u: Num, v: Num, i_syn: Num) -> Num {
    (0.04 * v + 5.0) * v + 140.0 - u + i_syn
}

#[inline(always)]
fn du(u: Num, v: Num, a: Num, b: Num) -> Num {
    a * (b*v - u)
}

impl State {
    #[inline(always)]
    fn calc(self, dt: Num, i_syn: Num, config: &Config) -> State {
        State {
            v: self.v + dt*dv(self.u, self.v, i_syn),
            u: self.u + dt*du(self.u, self.v, config.a, config.b)
        }
    }

    /// Calculate the new state after 1 ms.
    #[inline(always)]
    pub fn step_1ms(self, i_syn: Num, config: &Config) -> State {
        if self.v < FIRE_POTENTIAL {
            self.calc(0.5, i_syn, config).calc(0.5, i_syn, config)
        }
        else {
            State {
                v: config.c,
                u: self.u + config.d
            }
        }
    }
}
<|endoftext|>


<commit_before>//! 汉语拼音转换工具 Rust 版。
//! [![Build Status](https://img.shields.io/travis/mozillazg/rust-pinyin/master.svg)](https://travis-ci.org/mozillazg/rust-pinyin)
//! [![Coverage Status](https://img.shields.io/coveralls/mozillazg/rust-pinyin/master.svg)](https://coveralls.io/github/mozillazg/rust-pinyin)
//! [![Crates.io Version](https://img.shields.io/crates/v/pinyin.svg)](https://crates.io/crates/pinyin)
//! [![GitHub
//! stars](https://img.shields.io/github/stars/mozillazg/rust-pinyin.svg?style=social&label=Star)](https://github.com/mozillazg/rust-pinyin)
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/pinyin) and can be
//! used by adding `pinyin` to your dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! pinyin = "*"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate pinyin;
//! ```
//!
//! # 示例
//!
//! ```
//! extern crate pinyin;
//!
//! pub fn main() {
//!     let hans = "中国人";
//!     let mut args = pinyin::Args::new();
//!
//!     // 默认输出 [["zhong"] ["guo"] ["ren"]]
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 包含声调 [["zh\u{14d}ng"], ["gu\u{f3}"], ["r\u{e9}n"]]
//!     args.style = pinyin::Style::Tone;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 声调用数字表示 [["zho1ng"] ["guo2"] ["re2n"]]
//!     args.style = pinyin::Style::Tone2;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 开启多音字模式
//!     args = pinyin::Args::new();
//!     args.heteronym = true;
//!     // [["zhong", "zhong"] ["guo"] ["ren"]]
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!     // [["zho1ng", "zho4ng"] ["guo2"] ["re2n"]]
//!     args.style = pinyin::Style::Tone2;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//! }
//! ```

#[macro_use]
extern crate phf;
extern crate regex;

use regex::Captures;
use regex::Regex;

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

/// 拼音风格
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum Style {
    /// 普通风格，不带声调（默认风格）。如： `pin yin`
    Normal,
    /// 声调风格1，拼音声调在韵母第一个字母上。如： `pīn yīn`
    Tone,
    /// 声调风格2，即拼音声调在各个拼音之后，用数字 [0-4] 进行表示。如： `pi1n yi1n`
    Tone2,
    /// 声母风格，只返回各个拼音的声母部分。如： 中国 的拼音 `zh g`
    Initials,
    /// 首字母风格，只返回拼音的首字母部分。如： `p y`
    FirstLetter,
    /// 韵母风格1，只返回各个拼音的韵母部分，不带声调。如： `ong uo`
    Finals,
    /// 韵母风格2，带声调，声调在韵母第一个字母上。如： `ōng uó`
    FinalsTone,
    /// 韵母风格2，带声调，声调在各个拼音之后，用数字 [0-4] 进行表示。如： `o1ng uo2`
    FinalsTone2,
}

// 声母表
const _INITIALS: [&'static str; 21] = [
    "b", "p", "m", "f", "d", "t", "n", "l", "g",
    "k", "h", "j", "q", "x", "r", "zh", "ch", "sh", "z", "c", "s",
];

/// 参数
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Args {
    /// 拼音风格
    pub style:     Style,
    /// 是否启用多音字模式
    pub heteronym: bool,
}

impl Args {
    /// 返回一个默认参数
    ///
    /// ```ignore
    /// Args {
    ///    style: Style::Normal,
    ///    heteronym: false,
    /// }
    /// ```
    pub fn new() -> Args {
        Args {
            style: Style::Normal,
            heteronym: false,
        }
    }
}

// 获取单个拼音中的声母
fn initial(p: String) -> String {
    let mut s = "".to_string();
    for v in _INITIALS.iter() {
        if p.starts_with(v) {
            s = v.to_string();
            break;
        }
    }
    s
}

// 获取单个拼音中的韵母
fn _final(p: &str) -> String {
    let i = initial(p.to_string());
    if i == "" {
        return p.to_string();
    }
    let s: Vec<&str> = p.splitn(2, &i).collect();
    s.concat()
}

fn to_fixed<'a>(p: String, a: &'a Args) -> String {
    match a.style {
        Style::Initials => {
            return initial(p).to_string();
        },
        _ => {},
    };

    let re_phonetic_symbol = Regex::new(
        r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]"
    ).unwrap();

    // 匹配使用数字标识声调的字符的正则表达式
    let re_tone2 = Regex::new(r"([aeoiuvnm])([0-4])$").unwrap();

    // 替换拼音中的带声调字符
    let py = re_phonetic_symbol.replace_all(&p, |caps: &Captures| {
        let cap = caps.at(0).unwrap();
        let symbol = match PHONETIC_SYMBOL_MAP.get(cap) {
            Some(&v) => v,
            None => "",
        };

        let m: String;
        match a.style {
            // 不包含声调
            Style::Normal | Style::FirstLetter | Style::Finals => {
                // 去掉声调: a1 -> a
                m = re_tone2.replace_all(symbol, "$1");
            },
            Style::Tone2 | Style::FinalsTone2 => {
                // 返回使用数字标识声调的字符
                m = symbol.to_string();
            },
            _ => {
                // 声调在头上
                m = cap.to_string();
            },
        }
        m
    });

    let ret = match a.style {
        // 首字母
        Style::FirstLetter => {
            py.chars().nth(0).unwrap().to_string()
        },
        // 韵母
        Style::Finals | Style::FinalsTone | Style::FinalsTone2 => {
            _final(&py)
        },
        _ => py,
    };

    ret
}

fn apply_style<'a>(pys: Vec<String>, a: &'a Args) -> Vec<String> {
    let mut new_pys: Vec<String> = vec![];
    for v in pys {
        let s = to_fixed(v, a);
        new_pys.push(s);
    }
    new_pys
}

fn single_pinyin<'a>(c: char, a: &'a Args) -> Vec<String> {
    let mut ret: Vec<String> = vec![];
    let n: u32 = c as u32;

    match PINYIN_MAP.get(&n) {
        Some(&pys) => {
            let x: Vec<&str> = pys.split(',').collect();
            if x.len() == 0 || a.heteronym {
                for s in x {
                    ret.push(s.to_string());
                };
            } else {
                ret = vec![x[0].to_string()];
            }
        },
        None => {
            ret = vec![];
        }
    };

    apply_style(ret, a)
}

/// 汉字转拼音
///
/// ```
/// let hans = "中国人";
/// let args = pinyin::Args::new();
///
/// // 默认输出 [["zhong"] ["guo"] ["ren"]]
/// println!("{:?}",  pinyin::pinyin(hans, &args));
/// ```
pub fn pinyin<'a>(s: &'a str, a: &'a Args) -> Vec<Vec<String>> {
    let mut ret: Vec<Vec<String>> = Vec::new();
    let chars: Vec<char> = s.chars().collect();
    for c in chars {
        ret.push(single_pinyin(c, a));
    }

    return ret
}
<commit_msg>删除不必要的 ownership, lifetimes 相关代码<commit_after>//! 汉语拼音转换工具 Rust 版。
//! [![Build Status](https://img.shields.io/travis/mozillazg/rust-pinyin/master.svg)](https://travis-ci.org/mozillazg/rust-pinyin)
//! [![Coverage Status](https://img.shields.io/coveralls/mozillazg/rust-pinyin/master.svg)](https://coveralls.io/github/mozillazg/rust-pinyin)
//! [![Crates.io Version](https://img.shields.io/crates/v/pinyin.svg)](https://crates.io/crates/pinyin)
//! [![GitHub
//! stars](https://img.shields.io/github/stars/mozillazg/rust-pinyin.svg?style=social&label=Star)](https://github.com/mozillazg/rust-pinyin)
//!
//! # Usage
//!
//! This crate is [on crates.io](https://crates.io/crates/pinyin) and can be
//! used by adding `pinyin` to your dependencies in your project's `Cargo.toml`.
//!
//! ```toml
//! [dependencies]
//! pinyin = "0.1"
//! ```
//!
//! and this to your crate root:
//!
//! ```rust
//! extern crate pinyin;
//! ```
//!
//! # 示例
//!
//! ```
//! extern crate pinyin;
//!
//! pub fn main() {
//!     let hans = "中国人";
//!     let mut args = pinyin::Args::new();
//!
//!     // 默认输出 [["zhong"] ["guo"] ["ren"]]
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 包含声调 [["zh\u{14d}ng"], ["gu\u{f3}"], ["r\u{e9}n"]]
//!     args.style = pinyin::Style::Tone;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 声调用数字表示 [["zho1ng"] ["guo2"] ["re2n"]]
//!     args.style = pinyin::Style::Tone2;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!
//!     // 开启多音字模式
//!     args = pinyin::Args::new();
//!     args.heteronym = true;
//!     // [["zhong", "zhong"] ["guo"] ["ren"]]
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//!     // [["zho1ng", "zho4ng"] ["guo2"] ["re2n"]]
//!     args.style = pinyin::Style::Tone2;
//!     println!("{:?}",  pinyin::pinyin(hans, &args));
//! }
//! ```

#[macro_use]
extern crate phf;
extern crate regex;

use regex::Captures;
use regex::Regex;

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

/// 拼音风格
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum Style {
    /// 普通风格，不带声调（默认风格）。如： `pin yin`
    Normal,
    /// 声调风格1，拼音声调在韵母第一个字母上。如： `pīn yīn`
    Tone,
    /// 声调风格2，即拼音声调在各个拼音之后，用数字 [0-4] 进行表示。如： `pi1n yi1n`
    Tone2,
    /// 声母风格，只返回各个拼音的声母部分。如： 中国 的拼音 `zh g`
    Initials,
    /// 首字母风格，只返回拼音的首字母部分。如： `p y`
    FirstLetter,
    /// 韵母风格1，只返回各个拼音的韵母部分，不带声调。如： `ong uo`
    Finals,
    /// 韵母风格2，带声调，声调在韵母第一个字母上。如： `ōng uó`
    FinalsTone,
    /// 韵母风格2，带声调，声调在各个拼音之后，用数字 [0-4] 进行表示。如： `o1ng uo2`
    FinalsTone2,
}

// 声母表
const _INITIALS: [&'static str; 21] = [
    "b", "p", "m", "f", "d", "t", "n", "l", "g",
    "k", "h", "j", "q", "x", "r", "zh", "ch", "sh", "z", "c", "s",
];

/// 参数
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Args {
    /// 拼音风格
    pub style:     Style,
    /// 是否启用多音字模式
    pub heteronym: bool,
}

impl Args {
    /// 返回一个默认参数
    ///
    /// ```ignore
    /// Args {
    ///    style: Style::Normal,
    ///    heteronym: false,
    /// }
    /// ```
    pub fn new() -> Args {
        Args {
            style: Style::Normal,
            heteronym: false,
        }
    }
}

// 获取单个拼音中的声母
fn initial(p: String) -> String {
    let mut s = "".to_string();
    for v in _INITIALS.iter() {
        if p.starts_with(v) {
            s = v.to_string();
            break;
        }
    }
    s
}

// 获取单个拼音中的韵母
fn _final(p: &str) -> String {
    let i = initial(p.to_string());
    if i == "" {
        return p.to_string();
    }
    let s: Vec<&str> = p.splitn(2, &i).collect();
    s.concat()
}

fn to_fixed(p: String, a: &Args) -> String {
    match a.style {
        Style::Initials => {
            return initial(p).to_string();
        },
        _ => {},
    };

    let re_phonetic_symbol = Regex::new(
        r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]"
    ).unwrap();

    // 匹配使用数字标识声调的字符的正则表达式
    let re_tone2 = Regex::new(r"([aeoiuvnm])([0-4])$").unwrap();

    // 替换拼音中的带声调字符
    let py = re_phonetic_symbol.replace_all(&p, |caps: &Captures| {
        let cap = caps.at(0).unwrap();
        let symbol = match PHONETIC_SYMBOL_MAP.get(cap) {
            Some(&v) => v,
            None => "",
        };

        let m: String;
        match a.style {
            // 不包含声调
            Style::Normal | Style::FirstLetter | Style::Finals => {
                // 去掉声调: a1 -> a
                m = re_tone2.replace_all(symbol, "$1");
            },
            Style::Tone2 | Style::FinalsTone2 => {
                // 返回使用数字标识声调的字符
                m = symbol.to_string();
            },
            _ => {
                // 声调在头上
                m = cap.to_string();
            },
        }
        m
    });

    let ret = match a.style {
        // 首字母
        Style::FirstLetter => {
            py.chars().nth(0).unwrap().to_string()
        },
        // 韵母
        Style::Finals | Style::FinalsTone | Style::FinalsTone2 => {
            _final(&py)
        },
        _ => py,
    };

    ret
}

fn apply_style(pys: Vec<String>, a: &Args) -> Vec<String> {
    let mut new_pys: Vec<String> = vec![];
    for v in pys {
        let s = to_fixed(v, a);
        new_pys.push(s);
    }
    new_pys
}

fn single_pinyin(c: char, a: &Args) -> Vec<String> {
    let mut ret: Vec<String> = vec![];
    let n: u32 = c as u32;

    match PINYIN_MAP.get(&n) {
        Some(&pys) => {
            let x: Vec<&str> = pys.split(',').collect();
            if x.len() == 0 || a.heteronym {
                for s in x {
                    ret.push(s.to_string());
                };
            } else {
                ret = vec![x[0].to_string()];
            }
        },
        None => {
            ret = vec![];
        }
    };

    apply_style(ret, a)
}

/// 汉字转拼音
///
/// ```
/// let hans = "中国人";
/// let args = pinyin::Args::new();
///
/// // 默认输出 [["zhong"] ["guo"] ["ren"]]
/// println!("{:?}",  pinyin::pinyin(hans, &args));
/// ```
pub fn pinyin(s: &str, a: &Args) -> Vec<Vec<String>> {
    let mut ret: Vec<Vec<String>> = Vec::new();
    let chars: Vec<char> = s.chars().collect();
    for c in chars {
        ret.push(single_pinyin(c, a));
    }

    return ret
}
<|endoftext|>


<commit_before>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    pub fn new() -> Self { Default::default() }

    pub fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<commit_msg>Make MouseTranslationData fields private<commit_after>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    pub fn new() -> Self { Default::default() }

    pub fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;

#[macro_use]
extern crate lazy_static;

use hyper::Client;
use std::env::var;
use std::io::Read;
use std::sync::Mutex;
use url::form_urlencoded;

lazy_static! {
    static ref REGISTER: Mutex<Vec<u16>> = Mutex::new(vec![]);
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_init(ctn: u16, pn: u16) -> i8 {
    let index = REGISTER.lock().unwrap().iter().position(|&x| x == ctn);

    if index != None {
        return -1
    } else {
        REGISTER.lock().unwrap().push(ctn);
    }

    let ctn_string = ctn.to_string();
    let pn_string = pn.to_string();
    let path = "ct_init/".to_string() + &ctn_string + "/" + &pn_string;

    let response = post_query(&path, vec![]);

    match response {
        Ok(v) => v.parse::<i8>().unwrap(),
        Err(_) => -1
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_data(ctn: u16, dad: u8, sad: u8, lenc: u16, command: u8, lenr: u16, response: u8) -> i8 {

    1
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_close(ctn: u16) -> i8 {
    let index = REGISTER.lock().unwrap().iter().position(|&x| x == ctn);

    if index != None {
        REGISTER.lock().unwrap().retain(|&x| x == ctn);
    } else {
        return -1
    }

    let ctn_string = ctn.to_string();
    let path = "ct_close/".to_string() + &ctn_string;

    let response = post_query(&path, vec![]);

    match response {
        Ok(v) => v.parse::<i8>().unwrap(),
        Err(_) => -1
    }
}

fn env_or_default(var_name: &str, default: &str) -> String {
    match var(var_name) {
        Ok(s) => s,
        Err(_) => default.into(),
    }
}

type Query<'a> = Vec<(&'a str, &'a str)>;

fn post_query(path: &str, query: Query) -> hyper::Result<String> {
    let base_url = env_or_default("BASE_URL", "http://localhost:8080/k2/ctapi/");
    let url = base_url + path;

    let client = Client::new();
    let body = form_urlencoded::Serializer::new(String::new())
        .extend_pairs(query.iter())
        .finish();
    let mut response = client.post(&url)
        .body(&body[..])
        .send()?;
    let mut buf = String::new();
    response.read_to_string(&mut buf)?;

    Ok(buf)
}
<commit_msg>add hashmap to store ctn and pn<commit_after>extern crate hyper;
extern crate url;

#[macro_use]
extern crate lazy_static;

use hyper::Client;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::sync::Mutex;
use url::form_urlencoded;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_init(ctn: u16, pn: u16) -> i8 {
    if MAP.lock().unwrap().contains_key(&ctn) {
        return -1
    } else {
        MAP.lock().unwrap().insert(ctn, pn);
    }

    let ctn_string = ctn.to_string();
    let pn_string = pn.to_string();
    let path = "ct_init/".to_string() + &ctn_string + "/" + &pn_string;

    let response = post_query(&path, vec![]);

    match response {
        Ok(v) => v.parse::<i8>().unwrap(),
        Err(_) => -1
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_data(ctn: u16, dad: u8, sad: u8, lenc: u16, command: u8, lenr: u16, response: u8) -> i8 {

    1
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_close(ctn: u16) -> i8 {
    if !MAP.lock().unwrap().contains_key(&ctn) {
        return -1
    }

    let pn = MAP.lock().unwrap().remove(&ctn).unwrap();

    let ctn_string = ctn.to_string();
    let path = "ct_close/".to_string() + &ctn_string;

    let response = post_query(&path, vec![]);

    match response {
        Ok(v) => v.parse::<i8>().unwrap(),
        Err(_) => -1
    }
}

fn env_or_default(var_name: &str, default: &str) -> String {
    match var(var_name) {
        Ok(s) => s,
        Err(_) => default.into(),
    }
}

type Query<'a> = Vec<(&'a str, &'a str)>;

fn post_query(path: &str, query: Query) -> hyper::Result<String> {
    let base_url = env_or_default("BASE_URL", "http://localhost:8080/k2/ctapi/");
    let url = base_url + path;

    let client = Client::new();
    let body = form_urlencoded::Serializer::new(String::new())
        .extend_pairs(query.iter())
        .finish();
    let mut response = client.post(&url)
        .body(&body[..])
        .send()?;
    let mut buf = String::new();
    response.read_to_string(&mut buf)?;

    Ok(buf)
}
<|endoftext|>


<commit_before>extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::Write;
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};

static FORMAT: &'static str = "[=>_]";

pub enum Units {
    None,
    Bytes
}

pub struct Bar {
    prefix: String,
    total: usize,
    current: AtomicUsize,
    units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String,
    pub show_percent: bool,
    pub show_counter: bool,
    pub show_bar: bool
}

impl Bar {
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            prefix: String::new(),
            total: total,
            current: AtomicUsize::new(0),
            units: Units::Bytes,
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_empty: String::new(),
            bar_end: String::new(),
            show_percent: true,
            show_counter: true,
            show_bar: true
        };
        bar.format(FORMAT);
        bar
    }

    /// bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    pub fn prefix(&mut self, pre: &str) {
        self.prefix = pre.to_owned();
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        self.current.fetch_add(delta, Ordering::Relaxed)
    }

    pub fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        self.write(current)
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }

        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        let _ = write!(&mut std::io::stderr(), "\r{}", display);
    }
}

#[test]
fn it_works() {
}
<commit_msg>default for units, width doesnt need to be pub<commit_after>extern crate capsize;
extern crate termsize;

use capsize::Capacity;
use std::io::Write;
use std::iter;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::default::Default;

static FORMAT: &'static str = "[=>_]";

pub enum Units {
    None,
    Bytes
}

impl Default for Units {
    fn default() -> Units {
        Units::None
    }
}

pub struct Bar {
    prefix: String,
    total: usize,
    current: AtomicUsize,
    units: Units,
    bar_start: String,
    bar_current: String,
    bar_current_n: String,
    bar_empty: String,
    bar_end: String,
    pub show_percent: bool,
    pub show_counter: bool,
    pub show_bar: bool
}

impl Bar {
    pub fn new(total: usize) -> Bar {
        let mut bar = Bar {
            prefix: String::new(),
            total: total,
            current: AtomicUsize::new(0),
            units: Default::default(),
            bar_start: String::new(),
            bar_current: String::new(),
            bar_current_n: String::new(),
            bar_empty: String::new(),
            bar_end: String::new(),
            show_percent: true,
            show_counter: true,
            show_bar: true
        };
        bar.format(FORMAT);
        bar
    }

    /// bar.format("[=>_]")
    pub fn format(&mut self, spec: &str) {
        if spec.len() == 5 {
            let parts = spec.split("").collect::<Vec<&str>>();
            self.bar_start = parts[1].to_owned();
            self.bar_current = parts[2].to_owned();
            self.bar_current_n = parts[3].to_owned();
            self.bar_empty = parts[4].to_owned();
            self.bar_end = parts[5].to_owned();
        }
    }

    /// set prefix string
    pub fn prefix(&mut self, pre: &str) {
        self.prefix = pre.to_owned();
    }

    /// increment bar count by one
    pub fn incr(&self) -> usize {
        self.add(1)
    }

    /// add 1 to the bar count
    pub fn add(&self, delta: usize) -> usize {
        self.current.fetch_add(delta, Ordering::Relaxed)
    }

    /// sets the bar count to specified value
    pub fn set(&self, value: usize) {
        self.current.store(value, Ordering::Relaxed)
    }

    pub fn update(&self) {
        let current = self.current.load(Ordering::Relaxed);
        self.write(current)
    }

    pub fn finish_print(&self, msg: &str) {
        println!("");
        println!("{}", msg)
    }

    fn width(&self) -> usize {
        termsize::get().map(|s|s.cols as usize).unwrap_or(80)
    }

    fn write(&self, current: usize) {
        fn repeat(what: &str, n: usize) -> String {
            iter::repeat(what).take(n).collect::<String>()
        }

        fn unit(value: usize, units: &Units) -> String {
            match *units {
                Units::None => value.to_string(),
                Units::Bytes => (value as i64).capacity()
            }
        }

        let width = self.width();

        let mut prefix = self.prefix.clone();
        let mut mid = String::new();
        let mut suffix = String::new();

        // counter
        if self.show_counter {
            prefix = prefix + &format!(
                "{} / {} ", unit(current, &self.units), unit(self.total, &self.units)
            );
        }

        // percent complete
        if self.show_percent {
            let percent = current as f64 / (self.total as f64 / 100_f64);
            suffix = suffix + &format!(
                " {:.*} %", 2, percent
            );
        }

        if self.show_bar {
            let size = width - (prefix.len() + suffix.len() + 3);
            if size > 0 {
                let cur_count = (
                    (current as f64 / self.total as f64) * size as f64
                ).ceil() as usize;
                let empt_count = size - cur_count;
                mid = self.bar_start.clone();
                if empt_count > 0 {
                    mid = mid + &repeat(self.bar_current.as_ref(), (cur_count - 1) as usize) +  &self.bar_current_n;
                } else {
                    mid = mid + &repeat(self.bar_current.as_ref(), cur_count as usize);
                }
                mid = mid + &repeat(self.bar_empty.as_ref(), (empt_count) as usize) + &self.bar_end
            }
        }
        let mut display = prefix + &mid + &suffix;
        if display.len() < width {
            let remaining = width - display.len();
            display = display + &repeat(" ", remaining);
        }

        let _ = write!(&mut std::io::stderr(), "\r{}", display);
    }
}

#[test]
fn it_works() {
}
<|endoftext|>