<commit_before>// See LICENSE file for copyright and license details.

#![macro_escape]

use std::ptr;
use std::mem;
use core_misc::deg_to_rad;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, VertexCoord};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::c_str::CString;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Mesh {
    vertex_coords_vbo: Vbo,
    length: ZInt,
    mode: MeshRenderMode,
}

impl Mesh {
    pub fn new(zgl: &Zgl, data: &[VertexCoord]) -> Mesh {
        let length = data.len() as ZInt;
        Mesh {
            vertex_coords_vbo: Vbo::from_data(zgl, data),
            length: length,
            mode: MeshRenderMode::Triangles,
        }
    }

    pub fn draw(&self, zgl: &Zgl) {
        self.vertex_coords_vbo.bind(zgl);
        unsafe {
            let attr_id = 0; // TODO: gl.GetAttribLocation(shader, name)
            let components_count = 3;
            let is_normalized = gl::FALSE;
            let stride = 0;
            zgl.gl.VertexAttribPointer(
                attr_id,
                components_count,
                gl::FLOAT,
                is_normalized,
                stride,
                ptr::null_mut(),
            );
            zgl.check();
            zgl.gl.EnableVertexAttribArray(0); // attr_id?
            zgl.check();
            zgl.gl.DrawArrays(self.mode.to_gl_type(), 0, self.length);
            zgl.check();
        }
    }
}

pub struct Zgl {
    pub gl: Gl,
}

impl Zgl {
    pub fn new(get_proc_address: |&str| -> *const c_void) -> Zgl {
        let gl = Gl::load_with(|s| get_proc_address(s));
         Zgl{gl: gl}
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        let version = unsafe {
            CString::new(self.gl.GetString(name) as *const i8, false)
        };
        String::from_str(version.as_str()
            .expect("Can`t convert gl.GetString result to rust string"))
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: ZFloat) -> Matrix4<ZFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: ZFloat) -> Matrix4<ZFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8, ..4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }
}

/*
pub enum MeshRenderMode {
    Triangles,
    Lines,
}

impl MeshRenderMode {
    fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            MeshRenderMode::Lines => gl::LINES,
        }
    }
}
*/

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

/*
pub struct Vao {
    id: GLuint,
}

impl Vao {
    pub fn new(zgl: &Zgl) -> Vao {
        let mut id = 0;
        unsafe {
            zgl.gl.GenVertexArrays(1, &mut id);
        }
        zgl.check();
        let vao = Vao{id: id};
        vao.bind();
        vao
    }

    pub fn bind(&self) {
        gl.BindVertexArray(self.id);
        zgl.check();
    }

    pub fn unbind(&self) {
        gl.BindVertexArray(0);
        zgl.check();
    }

    pub fn draw_array(&self, mesh_mode: MeshRenderMode, faces_count: ZInt) {
        let starting_index = 0;
        let vertices_count = faces_count * 3;
        let mode = mesh_mode.to_gl_type();
        gl.DrawArrays(mode, starting_index, vertices_count);
        zgl.check();
    }
}

impl Drop for Vao {
    fn drop(&mut self) {
        unsafe {
            gl.DeleteVertexArrays(1, &self.id);
        }
        zgl.check();
    }
}
*/

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/zgl.rs: Removed commented-out VAO class<commit_after>// See LICENSE file for copyright and license details.

#![macro_escape]

use std::ptr;
use std::mem;
use core_misc::deg_to_rad;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, VertexCoord};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::c_str::CString;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Mesh {
    vertex_coords_vbo: Vbo,
    length: ZInt,
    mode: MeshRenderMode,
}

impl Mesh {
    pub fn new(zgl: &Zgl, data: &[VertexCoord]) -> Mesh {
        let length = data.len() as ZInt;
        Mesh {
            vertex_coords_vbo: Vbo::from_data(zgl, data),
            length: length,
            mode: MeshRenderMode::Triangles,
        }
    }

    pub fn draw(&self, zgl: &Zgl) {
        self.vertex_coords_vbo.bind(zgl);
        unsafe {
            let attr_id = 0; // TODO: gl.GetAttribLocation(shader, name)
            let components_count = 3;
            let is_normalized = gl::FALSE;
            let stride = 0;
            zgl.gl.VertexAttribPointer(
                attr_id,
                components_count,
                gl::FLOAT,
                is_normalized,
                stride,
                ptr::null_mut(),
            );
            zgl.check();
            zgl.gl.EnableVertexAttribArray(0); // attr_id?
            zgl.check();
            zgl.gl.DrawArrays(self.mode.to_gl_type(), 0, self.length);
            zgl.check();
        }
    }
}

pub struct Zgl {
    pub gl: Gl,
}

impl Zgl {
    pub fn new(get_proc_address: |&str| -> *const c_void) -> Zgl {
        let gl = Gl::load_with(|s| get_proc_address(s));
         Zgl{gl: gl}
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        let version = unsafe {
            CString::new(self.gl.GetString(name) as *const i8, false)
        };
        String::from_str(version.as_str()
            .expect("Can`t convert gl.GetString result to rust string"))
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: ZFloat) -> Matrix4<ZFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: ZFloat) -> Matrix4<ZFloat> {
        let rad = rad(deg_to_rad(angle));
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8, ..4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }
}

/*
pub enum MeshRenderMode {
    Triangles,
    Lines,
}

impl MeshRenderMode {
    fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            MeshRenderMode::Lines => gl::LINES,
        }
    }
}
*/

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function.
// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS
// versions use 3 leading underscores in the names of called functions instead of 2.
#[cfg(not(any(target_os = "ios", target_env = "msvc")))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl ___udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl ___aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memcpy(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) {
    use core::ptr;

    let mut dest = dest as *mut u32;
    let mut src = src as *mut u32;

    while n >= 4 {
        ptr::write(dest, ptr::read(src));
        dest = dest.offset(1);
        src = src.offset(1);
        n -= 4;
    }

    __aeabi_memcpy(dest as *mut u8, src as *const u8, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memcpy4(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    // Note the different argument order
    ::mem::memset(dest, c, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) {
    use core::ptr;

    let mut dest = dest as *mut u32;

    let byte = (c as u32) & 0xff;
    let c = (byte << 24) | (byte << 16) | (byte << 8) | byte;

    while n >= 4 {
        ptr::write(dest, c);
        dest = dest.offset(1);
        n -= 4;
    }

    __aeabi_memset(dest as *mut u8, n, byte as i32);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    __aeabi_memset4(dest, n, c);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    __aeabi_memset(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[no_mangle]
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
pub extern "C" fn __clzsi2(mut x: usize) -> usize {
  // TODO: const this? Requires const if
  let mut y: usize;
  let mut n: usize = {
    #[cfg(target_pointer_width = "64")]
    {
      64
    }
    #[cfg(target_pointer_width = "32")]
    {
      32
    }
    #[cfg(target_pointer_width = "16")]
    {
      16
    }
  };
  #[cfg(target_pointer_width = "64")]
  {
    y = x >> 32;
    if y != 0 {
      n -= 32;
      x = y;
    }
  }
  #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
  {
    y = x >> 16;
    if y != 0 {
      n -= 16;
      x = y;
    }
  }
  y = x >> 8;
  if y != 0 {
    n -= 8;
    x = y;
  }
  y = x >> 4;
  if y != 0 {
    n -= 4;
    x = y;
  }
  y = x >> 2;
  if y != 0 {
    n -= 2;
    x = y;
  }
  y = x >> 1;
  if y != 0 {
    n - 2
  } else {
    n - x
  }
}
<commit_msg>modify to fit into standard rustfmt output<commit_after>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function.
// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS
// versions use 3 leading underscores in the names of called functions instead of 2.
#[cfg(not(any(target_os = "ios", target_env = "msvc")))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl ___udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl ___aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memcpy(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) {
    use core::ptr;

    let mut dest = dest as *mut u32;
    let mut src = src as *mut u32;

    while n >= 4 {
        ptr::write(dest, ptr::read(src));
        dest = dest.offset(1);
        src = src.offset(1);
        n -= 4;
    }

    __aeabi_memcpy(dest as *mut u8, src as *const u8, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memcpy4(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    // Note the different argument order
    ::mem::memset(dest, c, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) {
    use core::ptr;

    let mut dest = dest as *mut u32;

    let byte = (c as u32) & 0xff;
    let c = (byte << 24) | (byte << 16) | (byte << 8) | byte;

    while n >= 4 {
        ptr::write(dest, c);
        dest = dest.offset(1);
        n -= 4;
    }

    __aeabi_memset(dest as *mut u8, n, byte as i32);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    __aeabi_memset4(dest, n, c);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    __aeabi_memset(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[no_mangle]
#[cfg(any(
    target_pointer_width = "16",
    target_pointer_width = "32",
    target_pointer_width = "64"
))]
pub extern "C" fn __clzsi2(mut x: usize) -> usize {
    // TODO: const this? Requires const if
    let mut y: usize;
    let mut n: usize = {
        #[cfg(target_pointer_width = "64")]
        {
            64
        }
        #[cfg(target_pointer_width = "32")]
        {
            32
        }
        #[cfg(target_pointer_width = "16")]
        {
            16
        }
    };
    #[cfg(target_pointer_width = "64")]
    {
        y = x >> 32;
        if y != 0 {
            n -= 32;
            x = y;
        }
    }
    #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
    {
        y = x >> 16;
        if y != 0 {
            n -= 16;
            x = y;
        }
    }
    y = x >> 8;
    if y != 0 {
        n -= 8;
        x = y;
    }
    y = x >> 4;
    if y != 0 {
        n -= 4;
        x = y;
    }
    y = x >> 2;
    if y != 0 {
        n -= 2;
        x = y;
    }
    y = x >> 1;
    if y != 0 {
        n - 2
    } else {
        n - x
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Le,
    Lt,
    Minus,
    Neq,       // !=
    NeqStrict, // !==
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
                BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict
                => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    Try(Vec<Stmt>, Vec<Stmt>, Vec<Stmt>),
    Throw(Box<Exp>),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch {{\n", indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<commit_msg>add try/catch variable binding<commit_after>use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BinOp {
    And,
    Ge,
    Gt,
    Eql,       // ==
    EqlStrict, // ===
    Le,
    Lt,
    Minus,
    Neq,       // !=
    NeqStrict, // !==
    Or,
    Plus,
    Slash,
    Star,
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Precedence {
    Const = 110,
    Sign = 100,
    Inc = 90,
    Mult = 70,
    Add = 60,
    Equality = 50,
    And = 40,
    Or = 30,
}

impl BinOp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            BinOp::And => Precedence::And,
            BinOp::Ge | BinOp::Gt | BinOp::Eql | BinOp::Le | BinOp::Lt |
                BinOp::Neq | BinOp::EqlStrict | BinOp::NeqStrict
                => Precedence::Equality,
            BinOp::Or => Precedence::Or,
            BinOp::Minus | BinOp::Plus => Precedence::Add,
            BinOp::Slash | BinOp::Star => Precedence::Mult,
        }
    }

    pub fn is_commutative(&self) -> bool {
        match *self {
            BinOp::Minus | BinOp::Slash => false,
            _ => true
        }
    }
}

impl Display for BinOp {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            BinOp::And => write!(fmt, "&&"),
            BinOp::Ge => write!(fmt, ">="),
            BinOp::Gt => write!(fmt, ">"),
            BinOp::Eql => write!(fmt, "=="),
            BinOp::EqlStrict => write!(fmt, "==="),
            BinOp::Le => write!(fmt, "<="),
            BinOp::Lt => write!(fmt, "<"),
            BinOp::Minus => write!(fmt, "-"),
            BinOp::Neq => write!(fmt, "!="),
            BinOp::NeqStrict => write!(fmt, "!=="),
            BinOp::Or => write!(fmt, "||"),
            BinOp::Plus => write!(fmt, "+"),
            BinOp::Slash => write!(fmt, "/"),
            BinOp::Star => write!(fmt, "*"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum Exp {
    BinExp(Box<Exp>, BinOp, Box<Exp>),
    Bool(bool),
    Call(Box<Exp>, Vec<Box<Exp>>),
    Defun(Option<String>, Vec<String>, Vec<Stmt>),
    Float(f64),
    InstanceVar(Box<Exp>, String),
    Neg(Box<Exp>),
    Null,
    NewObject(Box<Exp>, Vec<Box<Exp>>),
    Object(Vec<(String, Box<Exp>)>),
    Pos(Box<Exp>),
    PostDec(Box<Exp>),
    PostInc(Box<Exp>),
    PreDec(Box<Exp>),
    PreInc(Box<Exp>),
    TypeOf(Box<Exp>),
    Str(String),
    Undefined,
    Var(String),
}

impl Exp {
    pub fn precedence(&self) -> Precedence {
        match *self {
            Exp::BinExp(_, ref o, _) => o.precedence(),
            Exp::Neg(_) | Exp::Pos(_) => Precedence::Sign,
            Exp::PostDec(_) | Exp::PostInc(_) | Exp::PreDec(_) | Exp::PreInc(_) => Precedence::Inc,
            _ => Precedence::Const
        }
    }
}

macro_rules! group {
    ($e:expr, $p:expr) => {
        if $e.precedence() < $p {
            format!("({})", $e)
        } else {
            format!("{}", $e)
        }
    }
}

impl Exp {
    fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        match *self {
            Exp::BinExp(ref e1, ref o, ref e2) => {
                let prec = self.precedence();

                // Put grouping parentheses if the left subexpression has a lower-precedence
                // operator, e.g. (1 + 2) * 3
                let left = if prec > e1.precedence() {
                    format!("({})", e1)
                } else {
                    format!("{}", e1)
                };

                let right_prec = e2.precedence();

                // Put grouping parentheses around the right subexpression if it has a
                // lower-precedence operator,  __OR__ if `o` is not commutative and the precedence
                // is the same, e.g. (1 + 2) * 3 __OR__ 1 - (2 + 3)
                let right = if prec > right_prec || (!o.is_commutative() && prec == right_prec) {
                    format!("({})", e2)
                } else {
                    format!("{}", e2)
                };

                write!(fmt, "{} {} {}", left, o, right)
            }
            Exp::Bool(b) => write!(fmt, "{}", b),
            Exp::Call(ref func, ref args) => {
                try!(write!(fmt, "{}(", func));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg));
                }

                write!(fmt, ")")
            }
            Exp::Defun(ref opt, ref params, ref body) => {
                try!(write!(fmt, "function"));

                if let &Some(ref func) = opt {
                    try!(write!(fmt, " {}", func));
                }

                try!(write!(fmt, "("));

                for (i, param) in params.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", param));
                }

                try!(write!(fmt, ") {{\n"));
                stmt_block!(body);

                let indent : String = (0..indent_level).map(|_| " ").collect();

                write!(fmt, "{}}}", indent)
            }
            Exp::Float(f) => write!(fmt, "{}", f),
            Exp::InstanceVar(ref obj, ref name) => write!(fmt, "{}.{}", obj, name),
            Exp::Neg(ref e) => write!(fmt, "-{}", group!(e, Precedence::Sign)),
            Exp::NewObject(ref name, ref args) => {
                try!(write!(fmt, "new {}(", name));

                for (i, arg) in args.iter().enumerate() {
                    if i != 0 {
                        try!(write!(fmt, ", "));
                    }

                    try!(write!(fmt, "{}", arg))
                }

                write!(fmt, ")")
            }
            Exp::Null => write!(fmt, "null"),
            Exp::Object(ref properties) => {
                if properties.is_empty() {
                    return write!(fmt, "{{}}");
                }

                try!(writeln!(fmt, "{{"));

                let indent : String = (0..indent_level + 2).map(|_| " ").collect();

                for (i, &(ref name, ref prop)) in properties.iter().enumerate() {
                    if i != 0 {
                        try!(writeln!(fmt, ","));
                    }

                    try!(write!(fmt, "{}{}: ", indent, name));
                    try!(prop.fmt_helper(&mut fmt, indent_level + 2));
                }

                write!(fmt, "\n}}")
            }
            Exp::Pos(ref e) => write!(fmt, "+{}", group!(e, Precedence::Sign)),
            Exp::PostDec(ref e) => write!(fmt, "{}--", group!(e, Precedence::Inc)),
            Exp::PostInc(ref e) => write!(fmt, "{}++", group!(e, Precedence::Inc)),
            Exp::PreDec(ref e) => write!(fmt, "--{}", group!(e, Precedence::Inc)),
            Exp::PreInc(ref e) => write!(fmt, "++{}", group!(e, Precedence::Inc)),
            Exp::TypeOf(ref e) => write!(fmt, "typeof {}", e),
            Exp::Str(ref s) => write!(fmt, "\"{}\"", s),
            Exp::Undefined => write!(fmt, "undefined"),
            Exp::Var(ref v) => write!(fmt, "{}", v),
        }
    }
}

impl Display for Exp {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}

#[derive(Clone, Debug)]
pub enum Stmt {
    Assign(String, Exp),
    BareExp(Exp),
    Decl(String, Exp),
    Empty,
    If(Exp, Vec<Stmt>, Vec<Stmt>),
    Ret(Exp),
    Seq(Box<Stmt>, Box<Stmt>),
    Try(Vec<Stmt>, Vec<Stmt>, String, Vec<Stmt>), // try block, catch block, catch variable, finally block
    Throw(Box<Exp>),
    While(Exp, Vec<Stmt>),
}

impl Stmt {
    pub fn fmt_helper(&self, mut fmt: &mut Formatter, indent_level: i32) -> Result<(), Error> {
        macro_rules! stmt_block {
            ($stmt:expr) => {
                for s in $stmt {
                    try!(s.fmt_helper(&mut fmt, indent_level + 2))
                }
            }
        }

        macro_rules! indented_stmt {
            ($s:expr) => {
                try!($s.fmt_helper(&mut fmt, indent_level + 2))
            }
        }

        macro_rules! exp_semi {
            ($exp:expr) => {{
                try!($exp.fmt_helper(&mut fmt, indent_level));
                writeln!(fmt, ";")
            }}
        }

        let indent : String = (0..indent_level).map(|_| " ").collect();

        match *self {
            Stmt::Assign(ref v, ref exp) => {
                try!(write!(fmt, "{}{} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::BareExp(ref exp) => {
                try!(write!(fmt, "{}", indent));
                exp_semi!(exp)
            }
            Stmt::Decl(ref v, ref exp) => {
                try!(write!(fmt, "{}var {} = ", indent, v));
                exp_semi!(exp)
            }
            Stmt::Empty => Ok(()),
            Stmt::If(ref e, ref s, ref els) => {
                try!(write!(fmt, "{}if (", indent));
                try!(e.fmt_helper(&mut fmt, indent_level + 2));
                try!(writeln!(fmt, ") {{\n"));
                stmt_block!(s);

                if els.len() > 0 {
                    stmt_block!(s);
                }

                //if let &Some(ref stmt) = els {
                //    try!(write!(fmt, "{}else {{\n", indent));
                //    indented_stmt!(stmt);
                //    try!(write!(fmt, "{}}}\n", indent));
                //}

                Ok(())
            }
            Stmt::Ret(ref e) => {
                try!(write!(fmt, "{}return ", indent));
                exp_semi!(e)
            }
            Stmt::Seq(ref s1, ref s2) => {
                try!(s1.fmt_helper(&mut fmt, indent_level));
                s2.fmt_helper(&mut fmt, indent_level)
            }
            Stmt::Throw(ref e) => {
                write!(fmt, "{}throw {}", indent, e)
            }
            Stmt::Try(ref stmt, ref catch_block, ref finally_block) => {
                try!(write!(fmt, "{}try {{\n", indent));
                stmt_block!(stmt);
                try!(write!(fmt, "{}}}\n", indent));

                if catch_block.len() > 0 {
                    try!(write!(fmt, "{}catch {{\n", indent));
                    stmt_block!(catch_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                if finally_block.len() > 0 {
                    try!(write!(fmt, "{}finally {{\n", indent));
                    stmt_block!(finally_block);
                    try!(write!(fmt, "{}}}\n", indent));
                }

                Ok(())
            }
            Stmt::While(ref exp, ref stmt) => {
                try!(write!(fmt, "{}while ({}) {{\n", indent, exp));
                stmt_block!(stmt);
                write!(fmt, "{}}}\n", indent)
            }
        }
    }
}

impl Display for Stmt {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        self.fmt_helper(&mut fmt, 0)
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;
pub mod logger;

use cpu::CpuState;
use memory::Memory;

fn main() {
    let rom = rom_loader::load_ines("roms/nestest.nes").unwrap();
    let mut cpu: CpuState = Default::default();
    let mut mem:Memory = Memory::new();
    // TODO: implement loading the rom into the correct position in memory

    // TODO: handle this properly instead of just unwrapping
    let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
    let executor = cpu::CpuExecutor::new(opcode_info.0);
    let mut logger = logger::NesTest::new("resources/nestest.out",opcode_info.1);

    executor.power_on(&mut cpu, &mut mem);
    cpu.pc = 0xC000;
    mem.write(0,&rom);

    for i in 0..10 {
        executor.fetch_and_decode(&mut cpu,&mut mem);
        logger.log_after_fetch(&cpu,&mem);
        executor.execute(&mut cpu,&mut mem);
    }
}

<commit_msg>removed erroneous comment<commit_after>extern crate byteorder;
pub mod rom_loader;
pub mod memory;
pub mod cpu;
pub mod logger;

use cpu::CpuState;
use memory::Memory;

fn main() {
    let rom = rom_loader::load_ines("roms/nestest.nes").unwrap();
    let mut cpu: CpuState = Default::default();
    let mut mem:Memory = Memory::new();

    // TODO: handle this properly instead of just unwrapping
    let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
    let executor = cpu::CpuExecutor::new(opcode_info.0);
    let mut logger = logger::NesTest::new("resources/nestest.out",opcode_info.1);

    executor.power_on(&mut cpu, &mut mem);
    cpu.pc = 0xC000;
    mem.write(0,&rom);

    for i in 0..10 {
        executor.fetch_and_decode(&mut cpu,&mut mem);
        logger.log_after_fetch(&cpu,&mem);
        executor.execute(&mut cpu,&mut mem);
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self {
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, Error> {
        // Make sure that the bot isn't already in the room to be joined
        for room in self.rooms.borrow().iter() {
            if room_id == room {
                return Err("Already in room".into());
            }
        }

        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response, Error> {
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, Error> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, Error> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<String>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<commit_msg>Simplify Result type usage in Bot<commit_after>use std::collections::HashMap;
use std::{result, thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

type Result<T> = result::Result<T, Error>;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self {
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response> {
        // Make sure that the bot isn't already in the room to be joined
        for room in self.rooms.borrow().iter() {
            if room_id == room {
                return Err("Already in room".into());
            }
        }

        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response> {
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<String>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::fs::File;
use std::net::Ipv4Addr;
use std::ffi::{CStr, CString};
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};

use libc::{socket, close, SOCK_DGRAM, AF_INET, c_char, O_RDWR, open};

use tun::Tun;
use common::error::*;
use common::sockaddr::SockAddr;
use tun::configuration::{Configurable, Configuration};

use super::sys::*;

pub fn create(configuration: &Configuration) -> Result<Device> {
    Device::from_configuration(&configuration)
}

#[derive(Debug)]
pub struct Device {
    name: String,
    tun: File,
    ctl: File,
}

impl Device {
    pub unsafe fn request(&self) -> ifreq {
        let mut req: ifreq = mem::zeroed();
        ptr::copy_nonoverlapping(self.name.as_ptr() as *const c_char,
                                 req.ifr_ifrn.ifrn_name.as_mut_ptr(),
                                 self.name.len());

        req
    }
}

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

impl Write for Device {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.tun.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.tun.flush()
    }
}

impl Tun for Device {
    fn name(&self) -> &str {
        &self.name
    }

    fn address(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into)
        }
    }
    fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_addr = SockAddr::from(value).into();

            if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn broadcast(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
        }
    }
    fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();

            if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn destination(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
        }
    }
    fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();

            if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn netmask(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::unchecked(&req.ifr_ifru.ifru_netmask).map(Into::into)
        }
    }
    fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();

            if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn mtu(&self) -> Result<i32> {
        unsafe {
            let mut req = self.request();

            if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(req.ifr_ifru.ifru_mtu)
        }
    }
    fn set_mtu(&mut self, value: i32) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_mtu = value;

            if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn flags(&self) -> Result<i16> {
        unsafe {
            let mut req = self.request();

            if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(req.ifr_ifru.ifru_flags)
        }
    }
    fn set_flags(&mut self, value: i16) -> Result<()> {
        let origin_flags = self.flags()?;
        let mut value = value;

        unsafe {
            let mut req = self.request();

            req.ifr_ifru.ifru_flags = if value < 0 {
                value = -value;
                origin_flags & !value
            } else {
                origin_flags | value
            };

            if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn set_enabled(&mut self, value: bool) -> Result<()> {
        if value {
            return self.set_flags(IFF_UP | IFF_RUNNING);
        }

        self.set_flags(-IFF_UP)
    }
}

impl Configurable for Device {
    fn from_configuration(configuration: &Configuration) -> Result<Self> {
        let device_name = match configuration.name.as_ref() {
            Some(name) => {
                let name = CString::new(name.clone())?;

                if name.as_bytes_with_nul().len() > IFNAMSIZ {
                    return Err(ErrorKind::NameTooLong.into());
                }

                Some(name)
            }

            None => None,
        };

        let tun = unsafe { open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR) };
        if tun < 0 {
            return Err(io::Error::last_os_error().into());
        }

        let mut req: ifreq = unsafe { mem::zeroed() };

        if let Some(device_name) = device_name.as_ref() {
            unsafe {
                ptr::copy_nonoverlapping(device_name.as_ptr() as *const c_char,
                                         req.ifr_ifrn.ifrn_name.as_mut_ptr(),
                                         device_name.as_bytes().len())
            };
        }

        // TODO: add IFF_NO_PI flag?
        req.ifr_ifru.ifru_flags = IFF_TUN;

        unsafe {
            if tunsetiff(tun, &mut req as *mut _ as *mut _) < 0 {
                close(tun);
                return Err(io::Error::last_os_error().into());
            }
        }

        let ctl = unsafe { socket(AF_INET, SOCK_DGRAM, 0) };
        if ctl < 0 {
            return Err(io::Error::last_os_error().into());
        }

        let mut device = unsafe {
            Device {
                name: CStr::from_ptr(req.ifr_ifrn.ifrn_name.as_ptr()).to_string_lossy().into(),
                tun: File::from_raw_fd(tun),
                ctl: File::from_raw_fd(ctl),
            }
        };

        device.configure(configuration)?;
        Ok(device)
    }
    fn configure(&mut self, configuration: &Configuration) -> Result<()> {
        if let Some(ip) = configuration.address {
            self.set_address(ip)?;
        }

        if let Some(ip) = configuration.destination {
            self.set_destination(ip)?;
        }

        if let Some(ip) = configuration.broadcast {
            self.set_broadcast(ip)?;
        }

        if let Some(ip) = configuration.netmask {
            self.set_netmask(ip)?;
        }

        if let Some(mtu) = configuration.mtu {
            self.set_mtu(mtu)?;
        }

        self.set_enabled(configuration.enabled)?;

        Ok(())
    }
}
<commit_msg>fix linux build<commit_after>use std::mem;
use std::ptr;
use std::fs::File;
use std::net::Ipv4Addr;
use std::ffi::{CStr, CString};
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd};

use libc::{socket, close, SOCK_DGRAM, AF_INET, c_char, O_RDWR, open};

use tun::Tun;
use common::error::*;
use common::sockaddr::SockAddr;
use tun::configuration::{Configurable, Configuration};

use super::sys::*;

pub fn create(configuration: &Configuration) -> Result<Device> {
    Device::from_configuration(&configuration)
}

#[derive(Debug)]
pub struct Device {
    name: String,
    tun: File,
    ctl: File,
}

impl Device {
    pub unsafe fn request(&self) -> ifreq {
        let mut req: ifreq = mem::zeroed();
        ptr::copy_nonoverlapping(self.name.as_ptr() as *const c_char,
                                 req.ifr_ifrn.ifrn_name.as_mut_ptr(),
                                 self.name.len());

        req
    }
}

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

impl Write for Device {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.tun.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.tun.flush()
    }
}

impl Tun for Device {
    fn name(&self) -> &str {
        &self.name
    }

    fn address(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_addr).map(Into::into)
        }
    }
    fn set_address(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_addr = SockAddr::from(value).into();

            if siocsifaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn broadcast(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifbrdaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_broadaddr).map(Into::into)
        }
    }
    fn set_broadcast(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_broadaddr = SockAddr::from(value).into();

            if siocsifbrdaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn destination(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifdstaddr(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::new(&req.ifr_ifru.ifru_dstaddr).map(Into::into)
        }
    }
    fn set_destination(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_dstaddr = SockAddr::from(value).into();

            if siocsifdstaddr(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn netmask(&self) -> Result<Ipv4Addr> {
        unsafe {
            let mut req = self.request();

            if siocgifnetmask(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            SockAddr::unchecked(&req.ifr_ifru.ifru_netmask).map(Into::into)
        }
    }
    fn set_netmask(&mut self, value: Ipv4Addr) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_netmask = SockAddr::from(value).into();

            if siocsifnetmask(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn mtu(&self) -> Result<i32> {
        unsafe {
            let mut req = self.request();

            if siocgifmtu(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(req.ifr_ifru.ifru_mtu)
        }
    }
    fn set_mtu(&mut self, value: i32) -> Result<()> {
        unsafe {
            let mut req = self.request();
            req.ifr_ifru.ifru_mtu = value;

            if siocsifmtu(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn flags(&self) -> Result<i16> {
        unsafe {
            let mut req = self.request();

            if siocgifflags(self.ctl.as_raw_fd(), &mut req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(req.ifr_ifru.ifru_flags)
        }
    }
    fn set_flags(&mut self, value: i16) -> Result<()> {
        let origin_flags = self.flags()?;
        let mut value = value;

        unsafe {
            let mut req = self.request();

            req.ifr_ifru.ifru_flags = if value < 0 {
                value = -value;
                origin_flags & !value
            } else {
                origin_flags | value
            };

            if siocsifflags(self.ctl.as_raw_fd(), &req) < 0 {
                return Err(io::Error::last_os_error().into());
            }

            Ok(())
        }
    }

    fn set_enabled(&mut self, value: bool) -> Result<()> {
        if value {
            return self.set_flags(IFF_UP | IFF_RUNNING);
        }

        self.set_flags(-IFF_UP)
    }
}

impl Configurable for Device {
    fn from_configuration(configuration: &Configuration) -> Result<Self> {
        let device_name = match configuration.name.as_ref() {
            Some(name) => {
                let name = CString::new(name.clone())?;

                if name.as_bytes_with_nul().len() > IFNAMSIZ {
                    return Err(ErrorKind::TunNameTooLong.into());
                }

                Some(name)
            }

            None => None,
        };

        let tun = unsafe { open(b"/dev/net/tun\0".as_ptr() as *const _, O_RDWR) };
        if tun < 0 {
            return Err(io::Error::last_os_error().into());
        }

        let mut req: ifreq = unsafe { mem::zeroed() };

        if let Some(device_name) = device_name.as_ref() {
            unsafe {
                ptr::copy_nonoverlapping(device_name.as_ptr() as *const c_char,
                                         req.ifr_ifrn.ifrn_name.as_mut_ptr(),
                                         device_name.as_bytes().len())
            };
        }

        // TODO: add IFF_NO_PI flag?
        req.ifr_ifru.ifru_flags = IFF_TUN;

        unsafe {
            if tunsetiff(tun, &mut req as *mut _ as *mut _) < 0 {
                close(tun);
                return Err(io::Error::last_os_error().into());
            }
        }

        let ctl = unsafe { socket(AF_INET, SOCK_DGRAM, 0) };
        if ctl < 0 {
            return Err(io::Error::last_os_error().into());
        }

        let mut device = unsafe {
            Device {
                name: CStr::from_ptr(req.ifr_ifrn.ifrn_name.as_ptr()).to_string_lossy().into(),
                tun: File::from_raw_fd(tun),
                ctl: File::from_raw_fd(ctl),
            }
        };

        device.configure(configuration)?;
        Ok(device)
    }
    fn configure(&mut self, configuration: &Configuration) -> Result<()> {
        if let Some(ip) = configuration.address {
            self.set_address(ip)?;
        }

        if let Some(ip) = configuration.destination {
            self.set_destination(ip)?;
        }

        if let Some(ip) = configuration.broadcast {
            self.set_broadcast(ip)?;
        }

        if let Some(ip) = configuration.netmask {
            self.set_netmask(ip)?;
        }

        if let Some(mtu) = configuration.mtu {
            self.set_mtu(mtu)?;
        }

        self.set_enabled(configuration.enabled)?;

        Ok(())
    }
}
<|endoftext|>


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

use std::collections::HashMap;
use rustc_serialize::json::{Json, ToJson, Object};
use {Ring, GeoJsonResult};

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
#[derive(RustcEncodable, Clone, Debug)]
pub struct LineString {
    pub coordinates: Ring,
}

impl ToJson for LineString {
    fn to_json(&self) -> Json {
        let mut d = HashMap::new();
        d.insert(format!("type"), "LineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

impl LineString {
    pub fn from_json(json_geometry: &Object) -> GeoJsonResult<LineString> {
        let json_point = expect_property!(json_geometry, "coordinates", "missing 'coordinates' field");
        let coordinates = try!(Ring::from_json(expect_array!(json_point)));
        return Ok(LineString{coordinates: coordinates});
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::{ToJson, Json};
    use {Pos, LineString, Ring};

    #[test]
    fn test_line_string_to_json() {
        let line_string = LineString{coordinates: Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])])};
        let json_string = format!("{}", line_string.to_json());
        assert_eq!("{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}", json_string);
    }

    #[test]
    fn test_line_string_from_json() {
        let json_string = "{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}";
        let json_doc = Json::from_str(json_string).unwrap();
        let line_string = LineString::from_json(json_doc.as_object().unwrap()).ok().unwrap();
        assert_eq!(json_string, format!("{}", line_string.to_json()));
    }
}
<commit_msg>Replace LineString Ring with Vec<Pos><commit_after>// Copyright 2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use rustc_serialize::json::{Json, ToJson, Object};
use {Pos, GeoJsonResult};

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
#[derive(RustcEncodable, Clone, Debug)]
pub struct LineString {
    pub coordinates: Vec<Pos>,
}

impl ToJson for LineString {
    fn to_json(&self) -> Json {
        let mut d = HashMap::new();
        d.insert(format!("type"), "LineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

impl LineString {
    pub fn from_json(json_geometry: &Object) -> GeoJsonResult<LineString> {
        let json_point = expect_property!(json_geometry, "coordinates", "missing 'coordinates' field");
        let mut coordinates = vec![];
        for coordinate in expect_array!(json_point).iter() {
            coordinates.push(try!(Pos::from_json(expect_array!(coordinate))))
        }
        return Ok(LineString{coordinates: coordinates});
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::{ToJson, Json};
    use {Pos, LineString};

    #[test]
    fn test_line_string_to_json() {
        let line_string = LineString{coordinates: vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]};
        let json_string = format!("{}", line_string.to_json());
        assert_eq!("{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}", json_string);
    }

    #[test]
    fn test_line_string_from_json() {
        let json_string = "{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}";
        let json_doc = Json::from_str(json_string).unwrap();
        let line_string = LineString::from_json(json_doc.as_object().unwrap()).ok().unwrap();
        assert_eq!(json_string, format!("{}", line_string.to_json()));
    }
}
<|endoftext|>