<commit_before>// Copyright 2014 The Gfx-rs 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.

#![feature(core, os, env, plugin, std_misc)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate gfx;
extern crate glfw;
extern crate time;
extern crate "gfx_gl" as gl;

use time::precise_time_s;
use cgmath::FixedArray;
use cgmath::{Matrix, Point3, Vector3, Matrix3, ToMatrix4};
use cgmath::{Transform, AffineMatrix3, Vector4, Array1};
use gfx::{Device, DeviceExt, ToSlice};
use gfx::batch::RefBatch;
use glfw::Context;
use gl::Gl;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;
use std::env;
use std::str::FromStr;
use std::sync::mpsc::Receiver;
use std::iter::repeat;
use std::ffi::CString;
use std::num::Int;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params {
    #[name = "u_Transform"]
    transform: [[f32; 4]; 4],
}

static VERTEX_SRC: &'static [u8] = b"
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1., 0., 0., 1.);
    }
";

//----------------------------------------

fn gfx_main(mut glfw: glfw::Glfw,
            mut window: glfw::Window,
            events: Receiver<(f64, glfw::WindowEvent)>,
            dimension: i16) {
    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| window.get_proc_address(s));

    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let vertex_data = [
        // front (0, 1, 0)
        Vertex { pos: [-1,  1, -1] },
        Vertex { pos: [ 1,  1, -1] },
        Vertex { pos: [ 1,  1,  1] },
    ];

    let mesh = device.create_mesh(&vertex_data);
    let slice = mesh.to_slice(gfx::PrimitiveType::TriangleList);

    let texture_info = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let image_info = texture_info.to_image_info();
    let texture = device.create_texture(texture_info)
        .ok().expect("Failed to create texture");
    device.update_texture(&texture, &image_info,
                          &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
        .ok().expect("Failed to update texture");

    let program = device.link_program(VERTEX_SRC, FRAGMENT_SRC)
                        .ok().expect("Failed to link shaders");
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(0f32, -5.0, 0.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    let mut graphics = gfx::Graphics::new(device);
    let batch: RefBatch<Params> = graphics.make_batch(&program, &mesh, slice, &state)
                                          .ok().expect("Failed to make batch");

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        let start = precise_time_s() * 1000.;
        graphics.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        for x in (-dimension) ..dimension {
            for y in (-dimension) ..dimension {
                let mut model = Matrix3::identity().mul_s(0.01f32).to_matrix4();
                model.w = Vector4::new(x as f32 * 0.05,
                                       0f32,
                                       y as f32 * 0.05,
                                       1f32);

                let data = Params {
                    transform: proj.mul_m(&view.mat)
                                   .mul_m(&model).into_fixed(),
                };
                graphics.draw(&batch, &data, &frame).unwrap();
            }
        }

        let pre_submit = precise_time_s() * 1000.;
        graphics.end_frame();
        let post_submit = precise_time_s() * 1000.;
        window.swap_buffers();
        let swap = precise_time_s() * 1000.;

        println!("total time:\t\t{0:4.2}ms", swap - start);
        println!("\tcreate list:\t{0:4.2}ms", pre_submit - start);
        println!("\tsubmit:\t\t{0:4.2}ms", post_submit - pre_submit);
        println!("\tgpu wait:\t{0:4.2}ms", swap - post_submit)
    }
}

static VS_SRC: &'static str = "
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
";

static FS_SRC: &'static str = "
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1., 0., 0., 1.);
    }
";

fn compile_shader(gl: &Gl, src: &str, ty: GLenum) -> GLuint { unsafe {
    use std::num::Int;
    let shader = gl.CreateShader(ty);
    // Attempt to compile the shader
    let src = CString::from_slice(src.as_bytes());
    gl.ShaderSource(shader, 1, &src.as_ptr(), ptr::null());
    gl.CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf: Vec<u8> = repeat(0u8).take((len as isize).saturating_sub(1) as usize).collect();     // subtract 1 to skip the trailing null character
        gl.GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ShaderInfoLog not valid utf8"));
    }
    shader
}}

fn link_program(gl: &Gl, vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl.CreateProgram();
    gl.AttachShader(program, vs);
    gl.AttachShader(program, fs);
    gl.LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl.GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf: Vec<u8> = repeat(0u8).take((len as isize).saturating_sub(1) as usize).collect();     // subtract 1 to skip the trailing null character
        gl.GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
}}

fn gl_main(mut glfw: glfw::Glfw,
           mut window: glfw::Window,
           _: Receiver<(f64, glfw::WindowEvent),>,
           dimension: i16) {
    let gl = Gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(&gl, VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(&gl, FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(&gl, vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    let trans_uniform = unsafe {
        // Create Vertex Array Object
        gl.GenVertexArrays(1, &mut vao);
        gl.BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl.GenBuffers(1, &mut vbo);
        gl.BindBuffer(gl::ARRAY_BUFFER, vbo);

        let vertex_data = vec![
            // front (0, 1, 0)
            Vertex { pos: [-1,  1, -1] },
            Vertex { pos: [ 1,  1, -1] },
            Vertex { pos: [ 1,  1,  1] },
        ];

        gl.BufferData(gl::ARRAY_BUFFER,
                      (vertex_data.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
                      mem::transmute(&vertex_data[0]),
                      gl::STATIC_DRAW);

        // Use shader program
        gl.UseProgram(program);
        let o_color = CString::from_slice("o_Color".as_bytes());
        gl.BindFragDataLocation(program, 0, o_color.as_ptr());

        // Specify the layout of the vertex data
        let a_pos = CString::from_slice("a_Pos".as_bytes());
        gl.BindFragDataLocation(program, 0, a_pos.as_ptr());

        let pos_attr = gl.GetAttribLocation(program, a_pos.as_ptr());
        gl.EnableVertexAttribArray(pos_attr as GLuint);
        gl.VertexAttribPointer(pos_attr as GLuint, 3, gl::BYTE,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let u_transform = CString::from_slice("u_Transform".as_bytes());
        gl.GetUniformLocation(program, u_transform.as_ptr())
    };

    let (w, h) = window.get_framebuffer_size();
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(0f32, -5.0, 0.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        let start = precise_time_s() * 1000.;

        // Clear the screen to black
        unsafe {
            gl.ClearColor(0.3, 0.3, 0.3, 1.0);
            gl.Clear(gl::COLOR_BUFFER_BIT);
        }

        for x in (-dimension) ..dimension {
            for y in (-dimension) ..dimension {
                let mut model = Matrix3::identity().mul_s(0.01f32).to_matrix4();
                model.w = Vector4::new(x as f32 * 0.05,
                                       0f32,
                                       y as f32 * 0.05,
                                       1f32);

                let mat = proj.mul_m(&view.mat).mul_m(&model);

                unsafe {
                    gl.UniformMatrix4fv(trans_uniform,
                                        1,
                                        gl::FALSE,
                                        mat.x.ptr());
                    gl.DrawArrays(gl::TRIANGLES, 0, 3);
                }

            }
        }

        let submit = precise_time_s() * 1000.;

        // Swap buffers
        window.swap_buffers();
        let swap = precise_time_s() * 1000.;

        println!("total time:\t\t{0:4.2}ms", swap - start);
        println!("\tsubmit:\t\t{0:4.2}ms", submit - start);
        println!("\tgpu wait:\t{0:4.2}ms", swap - submit)

    }

    // Cleanup
    unsafe {
        gl.DeleteProgram(program);
        gl.DeleteShader(fs);
        gl.DeleteShader(vs);
        gl.DeleteBuffers(1, &vbo);
        gl.DeleteVertexArrays(1, &vao);
    }
}

fn main() {
    use std::num::Float;

    let ref mut args = env::args();
    let args_count = env::args().count();
    if args_count == 1 {
        println!("gfx-perf [gl|gfx] <size>");
        return;
    }

    let mode = args.nth(1).unwrap().into_string().unwrap();
    let count: i16 = if args_count == 3 {
        FromStr::from_str(&args.next().unwrap().into_string().unwrap()).ok()
    } else {
        None
    }.unwrap_or(10000);

    let count = ((count as f64).sqrt() / 2.) as i16;

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS)
        .ok().expect("Failed to initialize glfs-rs");

    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
    glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));

    let (mut window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    println!("count is {}", count*count*4);
    match mode.as_slice() {
        "gfx" => gfx_main(glfw, window, events, count),
        "gl" => gl_main(glfw, window, events, count),
        x => {
            println!("{} is not a known mode", x)
        }
    }
}
<commit_msg>Fixed Performance example to compile<commit_after>// Copyright 2014 The Gfx-rs 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.

#![feature(core, env, plugin, std_misc)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate gfx;
extern crate glfw;
extern crate time;
extern crate "gfx_gl" as gl;

use time::precise_time_s;
use cgmath::FixedArray;
use cgmath::{Matrix, Point3, Vector3, Matrix3, ToMatrix4};
use cgmath::{Transform, AffineMatrix3, Vector4, Array1};
use gfx::{Device, DeviceExt, ToSlice};
use gfx::batch::RefBatch;
use glfw::Context;
use gl::Gl;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;
use std::env;
use std::str::FromStr;
use std::sync::mpsc::Receiver;
use std::iter::repeat;
use std::ffi::CString;
use std::num::Int;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params {
    #[name = "u_Transform"]
    transform: [[f32; 4]; 4],
}

static VERTEX_SRC: &'static [u8] = b"
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1., 0., 0., 1.);
    }
";

//----------------------------------------

fn gfx_main(mut glfw: glfw::Glfw,
            mut window: glfw::Window,
            events: Receiver<(f64, glfw::WindowEvent)>,
            dimension: i16) {
    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| window.get_proc_address(s));

    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let vertex_data = [
        // front (0, 1, 0)
        Vertex { pos: [-1,  1, -1] },
        Vertex { pos: [ 1,  1, -1] },
        Vertex { pos: [ 1,  1,  1] },
    ];

    let mesh = device.create_mesh(&vertex_data);
    let slice = mesh.to_slice(gfx::PrimitiveType::TriangleList);

    let texture_info = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let image_info = texture_info.to_image_info();
    let texture = device.create_texture(texture_info)
        .ok().expect("Failed to create texture");
    device.update_texture(&texture, &image_info,
                          &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
        .ok().expect("Failed to update texture");

    let program = device.link_program(VERTEX_SRC, FRAGMENT_SRC)
                        .ok().expect("Failed to link shaders");
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(0f32, -5.0, 0.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    let mut graphics = gfx::Graphics::new(device);
    let batch: RefBatch<Params> = graphics.make_batch(&program, &mesh, slice, &state)
                                          .ok().expect("Failed to make batch");

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        let start = precise_time_s() * 1000.;
        graphics.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        for x in (-dimension) ..dimension {
            for y in (-dimension) ..dimension {
                let mut model = Matrix3::identity().mul_s(0.01f32).to_matrix4();
                model.w = Vector4::new(x as f32 * 0.05,
                                       0f32,
                                       y as f32 * 0.05,
                                       1f32);

                let data = Params {
                    transform: proj.mul_m(&view.mat)
                                   .mul_m(&model).into_fixed(),
                };
                graphics.draw(&batch, &data, &frame).unwrap();
            }
        }

        let pre_submit = precise_time_s() * 1000.;
        graphics.end_frame();
        let post_submit = precise_time_s() * 1000.;
        window.swap_buffers();
        let swap = precise_time_s() * 1000.;

        println!("total time:\t\t{0:4.2}ms", swap - start);
        println!("\tcreate list:\t{0:4.2}ms", pre_submit - start);
        println!("\tsubmit:\t\t{0:4.2}ms", post_submit - pre_submit);
        println!("\tgpu wait:\t{0:4.2}ms", swap - post_submit)
    }
}

static VS_SRC: &'static str = "
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
";

static FS_SRC: &'static str = "
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1., 0., 0., 1.);
    }
";

fn compile_shader(gl: &Gl, src: &str, ty: GLenum) -> GLuint { unsafe {
    use std::num::Int;
    let shader = gl.CreateShader(ty);
    // Attempt to compile the shader
    let src = CString::from_slice(src.as_bytes());
    gl.ShaderSource(shader, 1, &src.as_ptr(), ptr::null());
    gl.CompileShader(shader);

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf: Vec<u8> = repeat(0u8).take((len as isize).saturating_sub(1) as usize).collect();     // subtract 1 to skip the trailing null character
        gl.GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ShaderInfoLog not valid utf8"));
    }
    shader
}}

fn link_program(gl: &Gl, vs: GLuint, fs: GLuint) -> GLuint { unsafe {
    let program = gl.CreateProgram();
    gl.AttachShader(program, vs);
    gl.AttachShader(program, fs);
    gl.LinkProgram(program);
    // Get the link status
    let mut status = gl::FALSE as GLint;
    gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);

    // Fail on error
    if status != (gl::TRUE as GLint) {
        let mut len: GLint = 0;
        gl.GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf: Vec<u8> = repeat(0u8).take((len as isize).saturating_sub(1) as usize).collect();     // subtract 1 to skip the trailing null character
        gl.GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
        panic!("{}", str::from_utf8(buf.as_slice()).ok().expect("ProgramInfoLog not valid utf8"));
    }
    program
}}

fn gl_main(mut glfw: glfw::Glfw,
           mut window: glfw::Window,
           _: Receiver<(f64, glfw::WindowEvent),>,
           dimension: i16) {
    let gl = Gl::load_with(|s| window.get_proc_address(s));

    // Create GLSL shaders
    let vs = compile_shader(&gl, VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(&gl, FS_SRC, gl::FRAGMENT_SHADER);
    let program = link_program(&gl, vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    let trans_uniform = unsafe {
        // Create Vertex Array Object
        gl.GenVertexArrays(1, &mut vao);
        gl.BindVertexArray(vao);

        // Create a Vertex Buffer Object and copy the vertex data to it
        gl.GenBuffers(1, &mut vbo);
        gl.BindBuffer(gl::ARRAY_BUFFER, vbo);

        let vertex_data = vec![
            // front (0, 1, 0)
            Vertex { pos: [-1,  1, -1] },
            Vertex { pos: [ 1,  1, -1] },
            Vertex { pos: [ 1,  1,  1] },
        ];

        gl.BufferData(gl::ARRAY_BUFFER,
                      (vertex_data.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
                      mem::transmute(&vertex_data[0]),
                      gl::STATIC_DRAW);

        // Use shader program
        gl.UseProgram(program);
        let o_color = CString::from_slice("o_Color".as_bytes());
        gl.BindFragDataLocation(program, 0, o_color.as_ptr());

        // Specify the layout of the vertex data
        let a_pos = CString::from_slice("a_Pos".as_bytes());
        gl.BindFragDataLocation(program, 0, a_pos.as_ptr());

        let pos_attr = gl.GetAttribLocation(program, a_pos.as_ptr());
        gl.EnableVertexAttribArray(pos_attr as GLuint);
        gl.VertexAttribPointer(pos_attr as GLuint, 3, gl::BYTE,
                                gl::FALSE as GLboolean, 0, ptr::null());

        let u_transform = CString::from_slice("u_Transform".as_bytes());
        gl.GetUniformLocation(program, u_transform.as_ptr())
    };

    let (w, h) = window.get_framebuffer_size();
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(0f32, -5.0, 0.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    while !window.should_close() {
        // Poll events
        glfw.poll_events();

        let start = precise_time_s() * 1000.;

        // Clear the screen to black
        unsafe {
            gl.ClearColor(0.3, 0.3, 0.3, 1.0);
            gl.Clear(gl::COLOR_BUFFER_BIT);
        }

        for x in (-dimension) ..dimension {
            for y in (-dimension) ..dimension {
                let mut model = Matrix3::identity().mul_s(0.01f32).to_matrix4();
                model.w = Vector4::new(x as f32 * 0.05,
                                       0f32,
                                       y as f32 * 0.05,
                                       1f32);

                let mat = proj.mul_m(&view.mat).mul_m(&model);

                unsafe {
                    gl.UniformMatrix4fv(trans_uniform,
                                        1,
                                        gl::FALSE,
                                        mat.x.ptr());
                    gl.DrawArrays(gl::TRIANGLES, 0, 3);
                }

            }
        }

        let submit = precise_time_s() * 1000.;

        // Swap buffers
        window.swap_buffers();
        let swap = precise_time_s() * 1000.;

        println!("total time:\t\t{0:4.2}ms", swap - start);
        println!("\tsubmit:\t\t{0:4.2}ms", submit - start);
        println!("\tgpu wait:\t{0:4.2}ms", swap - submit)

    }

    // Cleanup
    unsafe {
        gl.DeleteProgram(program);
        gl.DeleteShader(fs);
        gl.DeleteShader(vs);
        gl.DeleteBuffers(1, &vbo);
        gl.DeleteVertexArrays(1, &vao);
    }
}

fn main() {
    use std::num::Float;

    let ref mut args = env::args();
    let args_count = env::args().count();
    if args_count == 1 {
        println!("gfx-perf [gl|gfx] <size>");
        return;
    }

    let mode = args.nth(1).unwrap();
    let count: i16 = if args_count == 3 {
        FromStr::from_str(&args.next().unwrap()).ok()
    } else {
        None
    }.unwrap_or(10000);

    let count = ((count as f64).sqrt() / 2.) as i16;

    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS)
        .ok().expect("Failed to initialize glfs-rs");

    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
    glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));

    let (mut window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    println!("count is {}", count*count*4);
    match mode.as_slice() {
        "gfx" => gfx_main(glfw, window, events, count),
        "gl" => gl_main(glfw, window, events, count),
        x => {
            println!("{} is not a known mode", x)
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate bencher;
extern crate chess;

use bencher::Bencher;
use chess::{Board, ChessMove, Color, ALL_SQUARES};

const INITIAL_FEN: &str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
const MIDDLEGAME_FEN: &str = "rn1qkb1r/pbp2ppp/1p2p3/3n4/8/2N2NP1/PP1PPPBP/R1BQ1RK1 b kq - 1 7";

fn perft_4(bench: &mut Bencher) {
    let pos = Board::from_fen(INITIAL_FEN.to_owned()).expect("valid fen");
    bench.iter(|| assert_eq!(pos.perft(4), 197281));
}

fn perft_5(bench: &mut Bencher) {
    let pos = Board::from_fen(INITIAL_FEN.to_owned()).expect("valid fen");
    bench.iter(|| assert_eq!(pos.perft(5), 4865609));
}

fn enumerate_moves(bench: &mut Bencher) {
    let pos = Board::from_fen(MIDDLEGAME_FEN.to_owned()).expect("valid fen");
    bench.iter(|| {
        let mut moves = [ChessMove::new(ALL_SQUARES[0], ALL_SQUARES[0], None); 256];
        assert_eq!(pos.enumerate_moves(&mut moves), 39);
    });
}

fn make_move(bench: &mut Bencher) {
    let pos = Board::from_fen(MIDDLEGAME_FEN.to_owned()).expect("valid fen");
    let m = ChessMove::new(ALL_SQUARES[61], ALL_SQUARES[52], None);
    bench.iter(|| {
       let after = pos.make_move(m);
       assert_eq!(after.side_to_move(), Color::White);
    });
}

benchmark_group!(benches, perft_4, perft_5, enumerate_moves, make_move);
benchmark_main!(benches);
<commit_msg>New (more) benchmarks.<commit_after>#[macro_use]
extern crate bencher;
extern crate chess;

use bencher::Bencher;
use chess::{Board, ChessMove, Color, ALL_SQUARES, MoveGen};

const MIDDLEGAME_FEN: &str = "rn1qkb1r/pbp2ppp/1p2p3/3n4/8/2N2NP1/PP1PPPBP/R1BQ1RK1 b kq - 1 7";

// This is a helper function to remove boilerplate code from all the perft_* _movegenbenchmarks
fn movegen_perft(bench: &mut Bencher, fen: String, depth: usize, count: usize) {
     let pos = Board::from_fen(fen).expect("Valid FEN");

     bench.iter(|| assert_eq!(MoveGen::movegen_perft_test(pos, depth), count));
}

// This is a helper function to remove boilerplate code from all the perft_* _boardbenchmarks
fn board_perft(bench: &mut Bencher, fen: String, depth: u64, count: u64) {
    let pos = Board::from_fen(fen).expect("Valid FEN");

    bench.iter(|| assert_eq!(pos.perft(depth), count));
}

fn board_enumerate_moves(bench: &mut Bencher) {
    let pos = Board::from_fen(MIDDLEGAME_FEN.to_owned()).expect("valid fen");
    bench.iter(|| {
        let mut moves = [ChessMove::new(ALL_SQUARES[0], ALL_SQUARES[0], None); 256];
        assert_eq!(pos.enumerate_moves(&mut moves), 39);
    });
}

fn board_make_move(bench: &mut Bencher) {
    let pos = Board::from_fen(MIDDLEGAME_FEN.to_owned()).expect("valid fen");
    let m = ChessMove::new(ALL_SQUARES[61], ALL_SQUARES[52], None);
    bench.iter(|| {
       let after = pos.make_move(m);
       assert_eq!(after.side_to_move(), Color::White);
    });
}

// These first two contain a technically invalid FEN position
// The position is completely valid, except it cannot be reached by any set of legal moves.
// Many chess move generators fail here due to a particular en-passant optimization.
// Should these two test ever fail, it should fail with an invaild FEN error, not an incorrect
// move count.

fn perft_01_board(bench: &mut Bencher) {
    board_perft(bench, "8/5bk1/8/2Pp4/8/1K6/8/8 w - d6 0 1".to_owned(), 6, 824064);
}

fn perft_02_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/1k6/8/2pP4/8/5BK1/8 b - d3 0 1".to_owned(), 6, 824064);
}

// These are all normal perft tests.

fn perft_03_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1".to_owned(), 6, 1440467);
}

fn perft_04_board(bench: &mut Bencher) {
    board_perft(bench, "8/5k2/8/2Pp4/2B5/1K6/8/8 w - d6 0 1".to_owned(), 6, 1440467);
}

fn perft_05_board(bench: &mut Bencher) {
    board_perft(bench, "5k2/8/8/8/8/8/8/4K2R w K - 0 1".to_owned(), 6, 661072);
}

fn perft_06_board(bench: &mut Bencher) {
    board_perft(bench, "4k2r/8/8/8/8/8/8/5K2 b k - 0 1".to_owned(), 6, 661072);
}

fn perft_07_board(bench: &mut Bencher) {
    board_perft(bench, "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1".to_owned(), 6, 803711);
}

fn perft_08_board(bench: &mut Bencher) {
    board_perft(bench, "r3k3/8/8/8/8/8/8/3K4 b q - 0 1".to_owned(), 6, 803711);
}

fn perft_09_board(bench: &mut Bencher) {
    board_perft(bench, "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1".to_owned(), 4, 1274206);
}

fn perft_10_board(bench: &mut Bencher) {
    board_perft(bench, "r3k2r/7b/8/8/8/8/1B4BQ/R3K2R b KQkq - 0 1".to_owned(), 4, 1274206);
}

fn perft_11_board(bench: &mut Bencher) {
    board_perft(bench, "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1".to_owned(), 4, 1720476);
}

fn perft_12_board(bench: &mut Bencher) {
    board_perft(bench, "r3k2r/8/5Q2/8/8/3q4/8/R3K2R w KQkq - 0 1".to_owned(), 4, 1720476);
}

fn perft_13_board(bench: &mut Bencher) {
    board_perft(bench, "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1".to_owned(), 6, 3821001);
}

fn perft_14_board(bench: &mut Bencher) {
    board_perft(bench, "3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1".to_owned(), 6, 3821001);
}

fn perft_15_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1".to_owned(), 5, 1004658);
}

fn perft_16_board(bench: &mut Bencher) {
    board_perft(bench, "5K2/8/1Q6/2N5/8/1p2k3/8/8 w - - 0 1".to_owned(), 5, 1004658);
}

fn perft_17_board(bench: &mut Bencher) {
    board_perft(bench, "4k3/1P6/8/8/8/8/K7/8 w - - 0 1".to_owned(), 6, 217342);
}

fn perft_18_board(bench: &mut Bencher) {
    board_perft(bench, "8/k7/8/8/8/8/1p6/4K3 b - - 0 1".to_owned(), 6, 217342);
}

fn perft_19_board(bench: &mut Bencher) {
    board_perft(bench, "8/P1k5/K7/8/8/8/8/8 w - - 0 1".to_owned(), 6, 92683);
}

fn perft_20_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/8/8/8/k7/p1K5/8 b - - 0 1".to_owned(), 6, 92683);
}

fn perft_21_board(bench: &mut Bencher) {
    board_perft(bench, "K1k5/8/P7/8/8/8/8/8 w - - 0 1".to_owned(), 6, 2217);
}

fn perft_22_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/8/8/8/p7/8/k1K5 b - - 0 1".to_owned(), 6, 2217);
}

fn perft_23_board(bench: &mut Bencher) {
    board_perft(bench, "8/k1P5/8/1K6/8/8/8/8 w - - 0 1".to_owned(), 7, 567584);
}

fn perft_24_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/8/8/1k6/8/K1p5/8 b - - 0 1".to_owned(), 7, 567584);
}

fn perft_25_board(bench: &mut Bencher) {
    board_perft(bench, "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1".to_owned(), 4, 23527);
}

fn perft_26_board(bench: &mut Bencher) {
    board_perft(bench, "8/5k2/8/5N2/5Q2/2K5/8/8 w - - 0 1".to_owned(), 4, 23527);
}

fn perft_kiwipete_board(bench: &mut Bencher) {
    board_perft(bench, "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1".to_owned(), 5, 193690690);
}

// Movegen Struct Tests.  Same as above

fn perft_01_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/5bk1/8/2Pp4/8/1K6/8/8 w - d6 0 1".to_owned(), 6, 824064); // Invalid FEN
}

fn perft_02_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/1k6/8/2pP4/8/5BK1/8 b - d3 0 1".to_owned(), 6, 824064); // Invalid FEN
}

fn perft_03_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1".to_owned(), 6, 1440467);
}

fn perft_04_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/5k2/8/2Pp4/2B5/1K6/8/8 w - d6 0 1".to_owned(), 6, 1440467);
}

fn perft_05_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "5k2/8/8/8/8/8/8/4K2R w K - 0 1".to_owned(), 6, 661072);
}

fn perft_06_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "4k2r/8/8/8/8/8/8/5K2 b k - 0 1".to_owned(), 6, 661072);
}

fn perft_07_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1".to_owned(), 6, 803711);
}

fn perft_08_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k3/8/8/8/8/8/8/3K4 b q - 0 1".to_owned(), 6, 803711);
}

fn perft_09_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1".to_owned(), 4, 1274206);
}

fn perft_10_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k2r/7b/8/8/8/8/1B4BQ/R3K2R b KQkq - 0 1".to_owned(), 4, 1274206);
}

fn perft_11_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1".to_owned(), 4, 1720476);
}

fn perft_12_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k2r/8/5Q2/8/8/3q4/8/R3K2R w KQkq - 0 1".to_owned(), 4, 1720476);
}

fn perft_13_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1".to_owned(), 6, 3821001);
}

fn perft_14_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1".to_owned(), 6, 3821001);
}

fn perft_15_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1".to_owned(), 5, 1004658);
}

fn perft_16_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "5K2/8/1Q6/2N5/8/1p2k3/8/8 w - - 0 1".to_owned(), 5, 1004658);
}

fn perft_17_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "4k3/1P6/8/8/8/8/K7/8 w - - 0 1".to_owned(), 6, 217342);
}

fn perft_18_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/k7/8/8/8/8/1p6/4K3 b - - 0 1".to_owned(), 6, 217342);
}

fn perft_19_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/P1k5/K7/8/8/8/8/8 w - - 0 1".to_owned(), 6, 92683);
}

fn perft_20_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/8/8/8/k7/p1K5/8 b - - 0 1".to_owned(), 6, 92683);
}

fn perft_21_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "K1k5/8/P7/8/8/8/8/8 w - - 0 1".to_owned(), 6, 2217);
}

fn perft_22_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/8/8/8/p7/8/k1K5 b - - 0 1".to_owned(), 6, 2217);
}

fn perft_23_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/k1P5/8/1K6/8/8/8/8 w - - 0 1".to_owned(), 7, 567584);
}

fn perft_24_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/8/8/1k6/8/K1p5/8 b - - 0 1".to_owned(), 7, 567584);
}

fn perft_25_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1".to_owned(), 4, 23527);
}

fn perft_26_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "8/5k2/8/5N2/5Q2/2K5/8/8 w - - 0 1".to_owned(), 4, 23527);
}

fn perft_kiwipete_movegen(bench: &mut Bencher) {
    movegen_perft(bench, "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1".to_owned(), 5, 193690690);
}

benchmark_group!(
    benches,
    perft_01_board,
    perft_02_board,
    perft_03_board,
    perft_04_board,
    perft_05_board,
    perft_06_board,
    perft_07_board,
    perft_08_board,
    perft_09_board,
    perft_10_board,
    perft_11_board,
    perft_12_board,
    perft_13_board,
    perft_14_board,
    perft_15_board,
    perft_16_board,
    perft_17_board,
    perft_18_board,
    perft_19_board,
    perft_20_board,
    perft_21_board,
    perft_22_board,
    perft_23_board,
    perft_24_board,
    perft_25_board,
    perft_26_board,
    perft_01_movegen,
    perft_02_movegen,
    perft_03_movegen,
    perft_04_movegen,
    perft_05_movegen,
    perft_06_movegen,
    perft_07_movegen,
    perft_08_movegen,
    perft_09_movegen,
    perft_10_movegen,
    perft_11_movegen,
    perft_12_movegen,
    perft_13_movegen,
    perft_14_movegen,
    perft_15_movegen,
    perft_16_movegen,
    perft_17_movegen,
    perft_18_movegen,
    perft_19_movegen,
    perft_20_movegen,
    perft_21_movegen,
    perft_22_movegen,
    perft_23_movegen,
    perft_24_movegen,
    perft_25_movegen,
    perft_26_movegen,
    perft_kiwipete_board,
    perft_kiwipete_movegen,
    board_enumerate_moves,
    board_make_move);

benchmark_main!(benches);
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Write;

use ppu::*;

#[cfg(test)]
mod spec_tests;

const ADDRESSABLE_MEMORY: usize = 65536;

pub trait Memory {
    fn store(&mut self, u16, u8);
    fn store16(&mut self, addr: u16, data: u16) {
        let lowb = (data & 0xff) as u8;
        let highb = ((data >> 8) & 0xff) as u8;
        self.store(addr, lowb);
        self.store(addr + 1, highb);
    }
    fn load(&self, u16) -> u8;
    fn load16(&self, addr: u16) -> u16 {
        self.load(addr) as u16 | (self.load(addr + 1) as u16) << 8
    }

    // probably a premature optimization, but we implement inc and dec here so
    // that we can alter the values in place.
    fn inc(&mut self, u16) -> u8;
    fn dec(&mut self, u16) -> u8;
    fn dump(&self, file: &'static str);
}

pub struct NesMemory {
    ram: [u8; 2048],
    ppu: Ppu,
}

impl NesMemory {
    pub fn new() -> Self {
        NesMemory {
            ppu: Ppu::new(),
            ram: [0; 2048],
        }
    }
}

impl Memory for NesMemory {
    fn store(&mut self, addr: u16, data: u8) {
        match addr {
            0x0...0x1fff => {
                // 2kb ram, mirrored 4 times
                let addr = addr as usize;
                self.ram[addr & 0x7ff] = data;
            }
            0x2000...0x3fff => {
                // PPU registers, mirrored every 8 bytes
                self.ppu.write_reg(addr, data);
            }
            0x4000...0x4013 => {
                // APU Registers
                unimplemented!();
            }
            0x4014 => {
                // Sprite DMA W
                unimplemented!();
            }
            0x4015 => {
                // Sound Status RW
                unimplemented!();
            }
            0x4016 => {
                // Input 1 RW
                unimplemented!();
            }
            0x4017 => {
                // Input 2, Frame Counter RW
                unimplemented!();
            }
            0x4018...0x401f => {
                // ??
                unimplemented!();
            }
            0x4020...0xffff => {
                // mapped to cartridge
                unimplemented!();
            }
            _ => {
                panic!("Should never get here.");
            }
        }
    }

    fn load(&self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn load16(&self, addr: u16) -> u16 {
        unimplemented!();
    }

    fn inc(&mut self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn dec(&mut self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn dump(&self, file_loc: &'static str) {
        unimplemented!();
    }
}

pub struct SimpleMemory {
    addr: [u8; ADDRESSABLE_MEMORY],
}

impl SimpleMemory {
    pub fn new() -> Self {
        SimpleMemory { addr: [0; ADDRESSABLE_MEMORY] }
    }

    pub fn store_many(&mut self, addr: u16, data: &[u8]) {
        for i in 0..data.len() {
            self.store(addr + i as u16, data[i]);
        }
    }
}

impl Memory for SimpleMemory {
    fn store(&mut self, addr: u16, data: u8) {
        let addr = addr as usize;
        self.addr[addr] = data;
    }

    fn load(&self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr]
    }

    fn inc(&mut self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr] = (self.addr[addr] as u16 + 1) as u8;
        self.addr[addr]
    }

    fn dec(&mut self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr] = (self.addr[addr] as i16 - 1) as u8;
        self.addr[addr]
    }

    fn dump(&self, file_loc: &'static str) {
        let mut f = File::create(file_loc).unwrap();
        f.write_all(&self.addr).unwrap();
    }
}
<commit_msg>Remove unused implementation<commit_after>use std::fs::File;
use std::io::Write;

use ppu::*;

#[cfg(test)]
mod spec_tests;

const ADDRESSABLE_MEMORY: usize = 65536;

pub trait Memory {
    fn store(&mut self, u16, u8);
    fn store16(&mut self, addr: u16, data: u16) {
        let lowb = (data & 0xff) as u8;
        let highb = ((data >> 8) & 0xff) as u8;
        self.store(addr, lowb);
        self.store(addr + 1, highb);
    }
    fn load(&self, u16) -> u8;
    fn load16(&self, addr: u16) -> u16 {
        self.load(addr) as u16 | (self.load(addr + 1) as u16) << 8
    }
    fn inc(&mut self, u16) -> u8;
    fn dec(&mut self, u16) -> u8;
    fn dump(&self, file: &'static str);
}

pub struct NesMemory {
    ram: [u8; 2048],
    ppu: Ppu,
}

impl NesMemory {
    pub fn new() -> Self {
        NesMemory {
            ppu: Ppu::new(),
            ram: [0; 2048],
        }
    }
}

impl Memory for NesMemory {
    fn store(&mut self, addr: u16, data: u8) {
        match addr {
            0x0...0x1fff => {
                // 2kb ram, mirrored 4 times
                let addr = addr as usize;
                self.ram[addr & 0x7ff] = data;
            }
            0x2000...0x3fff => {
                // PPU registers, mirrored every 8 bytes
                self.ppu.write_reg(addr, data);
            }
            0x4000...0x4013 => {
                // APU Registers
                unimplemented!();
            }
            0x4014 => {
                // Sprite DMA W
                unimplemented!();
            }
            0x4015 => {
                // Sound Status RW
                unimplemented!();
            }
            0x4016 => {
                // Input 1 RW
                unimplemented!();
            }
            0x4017 => {
                // Input 2, Frame Counter RW
                unimplemented!();
            }
            0x4018...0x401f => {
                // ??
                unimplemented!();
            }
            0x4020...0xffff => {
                // mapped to cartridge
                unimplemented!();
            }
            _ => {
                panic!("Should never get here.");
            }
        }
    }

    fn load(&self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn inc(&mut self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn dec(&mut self, addr: u16) -> u8 {
        unimplemented!();
    }

    fn dump(&self, file_loc: &'static str) {
        unimplemented!();
    }
}

pub struct SimpleMemory {
    addr: [u8; ADDRESSABLE_MEMORY],
}

impl SimpleMemory {
    pub fn new() -> Self {
        SimpleMemory { addr: [0; ADDRESSABLE_MEMORY] }
    }

    pub fn store_many(&mut self, addr: u16, data: &[u8]) {
        for i in 0..data.len() {
            self.store(addr + i as u16, data[i]);
        }
    }
}

impl Memory for SimpleMemory {
    fn store(&mut self, addr: u16, data: u8) {
        let addr = addr as usize;
        self.addr[addr] = data;
    }

    fn load(&self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr]
    }

    fn inc(&mut self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr] = (self.addr[addr] as u16 + 1) as u8;
        self.addr[addr]
    }

    fn dec(&mut self, addr: u16) -> u8 {
        let addr = addr as usize;
        self.addr[addr] = (self.addr[addr] as i16 - 1) as u8;
        self.addr[addr]
    }

    fn dump(&self, file_loc: &'static str) {
        let mut f = File::create(file_loc).unwrap();
        f.write_all(&self.addr).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::str::Chars;
use std::io::Reader;
use std::str::SendStr;
use span::Span;
use std::str::Owned;
use std::from_str::from_str;

/// A `Token` represents a special symbol within
/// the language. These do not contain any extra metadata
/// with it, that's stored elsewhere.
///
/// Unlike most languages, characters like `+`, `-`, `*`, `/`
/// are **not** considered tokens, but, in fact regular identifiers.
/// This allows us to implement these without the compiler
/// to have any sort of knowledge of them.
#[deriving(PartialEq, Show, Clone)]
pub enum Token {
    Ident(String),
    Str(String),
    Integer(i64),
    LBracket,
    RBracket,
    Comma,
    Keyword(SendStr),
    Colon,
    Caret,
    LParen,
    RParen,
    Noop,
    Done
}

/// The lexer is the system that has any notion of an input stream. The
/// stream can come from many sources, thus, we use the Reader trait
/// that is implemented for strings, files, tcp, etc...
///
/// The lexer should also not consume the whole stream at once, as
/// that will be a bottleneck for larger input sources.
pub struct Lexer<'a> {
    source: &'a str,
    iter: Chars<'a>,
    token: Token,
    done: bool,
    span: Span
}

impl<'a> Lexer<'a> {
    /// Return a brand new lexer containing an iterator
    /// of chars and a bunch of state to keep track of (such
    /// as the current Span).
    pub fn new(source: &'a str) -> Lexer<'a> {
        Lexer {
            source: source,
            iter: source.chars(),
            token: Noop,
            done: false,
            span: Span::new(0, 0)
        }
    }

    pub fn collect(&mut self) -> Vec<Token> {
        let mut vec = Vec::new();

        self.bump().while_some(|tok| {
            if tok != Done && tok != Noop {
                vec.push(tok);
            }

            if !self.done {
                self.bump()
            } else {
                None
            }
        });

        vec
    }

    /// Parse and fetch the next token in the text stream.
    /// This doesn't return the token, it stores it
    /// in the lexer.
    pub fn bump(&mut self) -> Option<Token> {
        // Fetch the next token so that we can start matching
        // against it. If we don't return anything, we'll set
        // the token to `Done`, resulting in a completed lexer.
        //
        // FIXME: I don't think I'm checking for a `None` case
        //        anywhere else.
        let c = match self.iter.next() {
            Some(c) => c,
            None => {
                self.done  = true;
                self.token = Done;
                return None;
            }
        };

        match c {
            ' ' => { return self.bump() },
            '\n' => { return self.bump() },
            '\t' => { return self.bump() },
            ',' => { self.token = Comma },
            // Parse some simple tokens.
            '(' => { self.token = LParen },
            ')' => { self.token = RParen },
            '^' => { self.token = Caret },
            '[' => { self.token = LBracket },
            ']' => { self.token = RBracket },
            num @ '0'..'9' => {
                let mut combined = String::new();
                combined.push_char(num);

                self.iter.next().while_some(|n| {

                    match n {
                       '0'..'9' => combined.push_char(n),
                        '\n' => { return None; },
                        n if n.is_whitespace() => { return None; },
                        _ => fail!("A number must be isolated from other tokens.")
                    }

                    self.iter.next()
                });

                let num = match from_str::<i64>(combined.as_slice()) {
                    Some(num) => num,
                    None => fail!("Not a number.")
                };

                self.token = Integer(num);
            },
            // Parse a simple keyword. Keywords are somewhat like
            // strings, but, they're more limited in the format, but
            // a lot nicer to use.
            ':' => {
                let mut keyword = String::new();
                self.iter.next().while_some(|a| {
                    if self.is_keyword(a) {
                        keyword.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                self.token = Keyword(Owned(keyword));
            },
            // Parse the beginning of a string until we find the ending
            // quote. Anything can be placed within the double quotes.
            //
            // This doesn't support any escaping yet, so that'll break.
            // To support it, we'll need to keep track of the previous
            // token. Finding a `\` character will result in it
            // being saved until we look at the next character; which
            // we'll look back at the previous character to figure
            // out our current state. Escaping will only be set if
            // it matches a good escape pattern.
            '"' => {
                let mut concat = String::new();
                self.iter.next().while_some(|a| {
                    if a == '"' {
                        None
                    } else {
                        concat.push_char(a);
                        self.iter.next()
                    }
                });

                self.token = Str(concat);
            },
            // An identifier is composed of any
            // characters that contain no whitespace
            // and doesn't start with the designated
            // characters above.
            ch => {
                let mut ident = String::new();

                if self.is_ident(ch) {
                    ident.push_char(ch);
                } else {
                    // Push an `Unknown` token here.
                }

                self.iter.next().while_some(|a| {
                    if self.is_ident(a) {
                        ident.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                if ident.len() > 0 {
                    self.token = Ident(ident);
                }
            }
        }

        Some(self.token.clone())
    }

    /// Determine if a char is allowed within an identifier.
    /// An identifier can be used for:
    ///
    /// * Function names
    /// * Binding names
    /// * Other
    ///
    /// Because many of the built-in forms have identifiers
    /// such as `+`, `-`, `*`, `/`, we can't make these tokens,
    /// nor can we exclude them from the identifier format.
    pub fn is_ident(&self, ch: char) -> bool {
        if ch.is_whitespace() || ch == ':' || ch == '(' || ch == ')' || ch == '"'
            || ch == '@' || ch == '!' || ch == '\n' || ch == '\t' || ch == ',' {
            false
        } else {
            true
        }
    }

    /// Verify if the char is within the allowed character set for keywords. This
    /// only checks a single character at a time.
    #[inline]
    pub fn is_keyword(&self, a: char) -> bool {
        if a.is_whitespace() || a == '(' || a == ')' || a == '^' || a == ':' || a == ',' {
            false
        } else {
            true
        }
    }

    /// Expect a given token to come next, otherwise
    /// fail. Failing will result in a formatted
    /// error message that uses the Span and lets
    /// the user know what went wrong.
    pub fn expect(&mut self, tok: &Token) {
        if self.token == *tok {
            self.bump();
        } else {
            fail!("Expected {} but found {}", *tok, self.token);
        }
    }

    /// Optionally eat a given token. If the token is not
    /// found, this will simply return false and
    /// won't fail.
    pub fn eat(&mut self, tok: &Token) -> bool {
        if self.token == *tok {
            self.bump();
            true
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use span::Span;
    use std::str::{Slice, Owned};

    #[test]
    fn noop() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.token, Noop);
    }

    #[test]
    fn zeroed_span() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.span, Span::new(0, 0));
    }

    #[test]
    fn bump_empty() {
        let mut lexer = Lexer::new("");
        lexer.bump();
        assert_eq!(lexer.token, Done);
    }

    #[test]
    fn bump_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.token, LParen);
    }

    #[test]
    fn bump_rparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        assert_eq!(lexer.token, RParen);
    }

    #[test]
    fn bump_simple_keyword() {
        let mut lexer = Lexer::new(":foo");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo")));
    }

    #[test]
    fn bump_keyword_dash() {
        let mut lexer = Lexer::new(":foo-");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-")));
    }

    #[test]
    fn bump_keyword_dash_middle() {
        let mut lexer = Lexer::new(":foo-bar");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-bar")));
    }

    #[test]
    fn bump_string() {
        let mut lexer = Lexer::new("\"hah-w091:--:\"");
        lexer.bump();
        assert_eq!(lexer.token, Str("hah-w091:--:".to_string()));
    }

    #[test]
    fn bump_ident() {
        let mut lexer = Lexer::new("foo-bar-&#^");
        lexer.bump();
        assert_eq!(lexer.token, Ident("foo-bar-&#^".to_string()));
    }

    #[test]
    fn should_eat_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.eat(&LParen), true);
    }

    #[test]
    #[should_fail]
    fn should_expect_lparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        lexer.expect(&LParen);
    }

    #[test]
    fn should_expect() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        lexer.expect(&LParen);
    }
}
<commit_msg>Added support for negation on integers<commit_after>use std::str::Chars;
use std::io::Reader;
use std::str::SendStr;
use span::Span;
use std::str::Owned;
use std::from_str::from_str;

/// A `Token` represents a special symbol within
/// the language. These do not contain any extra metadata
/// with it, that's stored elsewhere.
///
/// Unlike most languages, characters like `+`, `-`, `*`, `/`
/// are **not** considered tokens, but, in fact regular identifiers.
/// This allows us to implement these without the compiler
/// to have any sort of knowledge of them.
#[deriving(PartialEq, Show, Clone)]
pub enum Token {
    Ident(String),
    Str(String),
    Integer(i64),
    LBracket,
    RBracket,
    Comma,
    Keyword(SendStr),
    Colon,
    Caret,
    LParen,
    RParen,
    Noop,
    Done
}

/// The lexer is the system that has any notion of an input stream. The
/// stream can come from many sources, thus, we use the Reader trait
/// that is implemented for strings, files, tcp, etc...
///
/// The lexer should also not consume the whole stream at once, as
/// that will be a bottleneck for larger input sources.
pub struct Lexer<'a> {
    source: &'a str,
    iter: Chars<'a>,
    token: Token,
    done: bool,
    span: Span
}

impl<'a> Lexer<'a> {
    /// Return a brand new lexer containing an iterator
    /// of chars and a bunch of state to keep track of (such
    /// as the current Span).
    pub fn new(source: &'a str) -> Lexer<'a> {
        Lexer {
            source: source,
            iter: source.chars(),
            token: Noop,
            done: false,
            span: Span::new(0, 0)
        }
    }

    pub fn collect(&mut self) -> Vec<Token> {
        let mut vec = Vec::new();

        self.bump().while_some(|tok| {
            if tok != Done && tok != Noop {
                vec.push(tok);
            }

            if !self.done {
                self.bump()
            } else {
                None
            }
        });

        vec
    }

    /// Parse and fetch the next token in the text stream.
    /// This doesn't return the token, it stores it
    /// in the lexer.
    pub fn bump(&mut self) -> Option<Token> {
        // Fetch the next token so that we can start matching
        // against it. If we don't return anything, we'll set
        // the token to `Done`, resulting in a completed lexer.
        //
        // FIXME: I don't think I'm checking for a `None` case
        //        anywhere else.
        let c = match self.iter.next() {
            Some(c) => c,
            None => {
                self.done  = true;
                self.token = Done;
                return None;
            }
        };

        match c {
            ' ' => { return self.bump() },
            '\n' => { return self.bump() },
            '\t' => { return self.bump() },
            ',' => { self.token = Comma },
            // Parse some simple tokens.
            '(' => { self.token = LParen },
            ')' => { self.token = RParen },
            '^' => { self.token = Caret },
            '[' => { self.token = LBracket },
            ']' => { self.token = RBracket },
            num @ '0'..'9' | num @ '-' => {
                let mut combined = String::new();
                combined.push_char(num);

                self.iter.next().while_some(|n| {

                    match n {
                       '0'..'9' => combined.push_char(n),
                        '\n' => { return None; },
                        n if n.is_whitespace() => { return None; },
                        _ => fail!("A number must be isolated from other tokens.")
                    }

                    self.iter.next()
                });

                let num = match from_str::<i64>(combined.as_slice()) {
                    Some(num) => num,
                    None => fail!("Not a number.")
                };

                self.token = Integer(num);
            },
            // Parse a simple keyword. Keywords are somewhat like
            // strings, but, they're more limited in the format, but
            // a lot nicer to use.
            ':' => {
                let mut keyword = String::new();
                self.iter.next().while_some(|a| {
                    if self.is_keyword(a) {
                        keyword.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                self.token = Keyword(Owned(keyword));
            },
            // Parse the beginning of a string until we find the ending
            // quote. Anything can be placed within the double quotes.
            //
            // This doesn't support any escaping yet, so that'll break.
            // To support it, we'll need to keep track of the previous
            // token. Finding a `\` character will result in it
            // being saved until we look at the next character; which
            // we'll look back at the previous character to figure
            // out our current state. Escaping will only be set if
            // it matches a good escape pattern.
            '"' => {
                let mut concat = String::new();
                self.iter.next().while_some(|a| {
                    if a == '"' {
                        None
                    } else {
                        concat.push_char(a);
                        self.iter.next()
                    }
                });

                self.token = Str(concat);
            },
            // An identifier is composed of any
            // characters that contain no whitespace
            // and doesn't start with the designated
            // characters above.
            ch => {
                let mut ident = String::new();

                if self.is_ident(ch) {
                    ident.push_char(ch);
                } else {
                    // Push an `Unknown` token here.
                }

                self.iter.next().while_some(|a| {
                    if self.is_ident(a) {
                        ident.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                if ident.len() > 0 {
                    self.token = Ident(ident);
                }
            }
        }

        Some(self.token.clone())
    }

    /// Determine if a char is allowed within an identifier.
    /// An identifier can be used for:
    ///
    /// * Function names
    /// * Binding names
    /// * Other
    ///
    /// Because many of the built-in forms have identifiers
    /// such as `+`, `-`, `*`, `/`, we can't make these tokens,
    /// nor can we exclude them from the identifier format.
    pub fn is_ident(&self, ch: char) -> bool {
        if ch.is_whitespace() || ch == ':' || ch == '(' || ch == ')' || ch == '"'
            || ch == '@' || ch == '!' || ch == '\n' || ch == '\t' || ch == ',' {
            false
        } else {
            true
        }
    }

    /// Verify if the char is within the allowed character set for keywords. This
    /// only checks a single character at a time.
    #[inline]
    pub fn is_keyword(&self, a: char) -> bool {
        if a.is_whitespace() || a == '(' || a == ')' || a == '^' || a == ':' || a == ',' {
            false
        } else {
            true
        }
    }

    /// Expect a given token to come next, otherwise
    /// fail. Failing will result in a formatted
    /// error message that uses the Span and lets
    /// the user know what went wrong.
    pub fn expect(&mut self, tok: &Token) {
        if self.token == *tok {
            self.bump();
        } else {
            fail!("Expected {} but found {}", *tok, self.token);
        }
    }

    /// Optionally eat a given token. If the token is not
    /// found, this will simply return false and
    /// won't fail.
    pub fn eat(&mut self, tok: &Token) -> bool {
        if self.token == *tok {
            self.bump();
            true
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use span::Span;
    use std::str::{Slice, Owned};

    #[test]
    fn noop() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.token, Noop);
    }

    #[test]
    fn zeroed_span() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.span, Span::new(0, 0));
    }

    #[test]
    fn bump_empty() {
        let mut lexer = Lexer::new("");
        lexer.bump();
        assert_eq!(lexer.token, Done);
    }

    #[test]
    fn bump_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.token, LParen);
    }

    #[test]
    fn bump_rparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        assert_eq!(lexer.token, RParen);
    }

    #[test]
    fn bump_simple_keyword() {
        let mut lexer = Lexer::new(":foo");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo")));
    }

    #[test]
    fn bump_keyword_dash() {
        let mut lexer = Lexer::new(":foo-");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-")));
    }

    #[test]
    fn bump_keyword_dash_middle() {
        let mut lexer = Lexer::new(":foo-bar");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-bar")));
    }

    #[test]
    fn bump_string() {
        let mut lexer = Lexer::new("\"hah-w091:--:\"");
        lexer.bump();
        assert_eq!(lexer.token, Str("hah-w091:--:".to_string()));
    }

    #[test]
    fn bump_ident() {
        let mut lexer = Lexer::new("foo-bar-&#^");
        lexer.bump();
        assert_eq!(lexer.token, Ident("foo-bar-&#^".to_string()));
    }

    #[test]
    fn should_eat_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.eat(&LParen), true);
    }

    #[test]
    #[should_fail]
    fn should_expect_lparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        lexer.expect(&LParen);
    }

    #[test]
    fn should_expect() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        lexer.expect(&LParen);
    }
}
<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate unescape;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate linefeed;
#[macro_use]
extern crate log;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate prettytable;

#[macro_use]
mod utils;
mod command_executor;
#[macro_use]
mod commands;
mod libindy;

use command_executor::CommandExecutor;

use commands::{common, did, ledger, pool, wallet};

use linefeed::{Reader, ReadResult, Terminal};
use linefeed::complete::{Completer, Completion};

use std::env;
use std::fs::File;
use std::io::BufReader;
use std::rc::Rc;

fn main() {
    utils::logger::LoggerUtils::init();

    let command_executor = build_executor();

    if env::args().len() == 1 {
        execute_stdin(command_executor);
    } else {
        let mut args = env::args();
        args.next(); //skip 0 param
        execute_batch(command_executor, Some(&args.next().unwrap()))
    }
}

fn build_executor() -> CommandExecutor {
    CommandExecutor::build()
        .add_command(common::about_command::new())
        .add_command(common::exit_command::new())
        .add_command(common::prompt_command::new())
        .add_command(common::show_command::new())
        .add_group(did::group::new())
        .add_command(did::new_command::new())
        .add_command(did::use_command::new())
        .add_command(did::rotate_key_command::new())
        .add_command(did::list_command::new())
        .finalize_group()
        .add_group(pool::group::new())
        .add_command(pool::create_command::new())
        .add_command(pool::connect_command::new())
        .add_command(pool::list_command::new())
        .add_command(pool::disconnect_command::new())
        .add_command(pool::delete_command::new())
        .finalize_group()
        .add_group(wallet::group::new())
        .add_command(wallet::create_command::new())
        .add_command(wallet::open_command::new())
        .add_command(wallet::list_command::new())
        .add_command(wallet::close_command::new())
        .add_command(wallet::delete_command::new())
        .finalize_group()
        .add_group(ledger::group::new())
        .add_command(ledger::nym_command::new())
        .add_command(ledger::get_nym_command::new())
        .add_command(ledger::attrib_command::new())
        .add_command(ledger::get_attrib_command::new())
        .add_command(ledger::schema_command::new())
        .add_command(ledger::get_schema_command::new())
        .add_command(ledger::claim_def_command::new())
        .add_command(ledger::get_claim_def_command::new())
        .add_command(ledger::node_command::new())
        .add_command(ledger::pool_config_command::new())
        .add_command(ledger::pool_upgrade_command::new())
        .add_command(ledger::custom_command::new())
        .finalize_group()
        .finalize()
}

fn execute_stdin(command_executor: CommandExecutor) {
    #[cfg(target_os = "windows")]
        ansi_term::enable_ansi_support().is_ok();

    match Reader::new("indy-cli") {
        Ok(reader) => execute_interactive(command_executor, reader),
        Err(_) => execute_batch(command_executor, None),
    }
}

fn execute_interactive<T>(command_executor: CommandExecutor, mut reader: Reader<T>)
    where T: Terminal {
    let command_executor = Rc::new(command_executor);
    reader.set_completer(command_executor.clone());
    reader.set_prompt(&command_executor.ctx().get_prompt());

    while let Ok(ReadResult::Input(line)) = reader.read_line() {
        if line.trim().is_empty() {
            continue;
        }

        command_executor.execute(&line).is_ok();
        reader.add_history(line);
        reader.set_prompt(&command_executor.ctx().get_prompt());

        if command_executor.ctx().is_exit() {
            break;
        }
    }
}

fn execute_batch(command_executor: CommandExecutor, script_path: Option<&str>) {
    if let Some(script_path) = script_path {
        let file = match File::open(script_path) {
            Ok(file) => file,
            Err(err) => return println_err!("Can't open script file {}\nError: {}", script_path, err),
        };
        _iter_batch(command_executor, BufReader::new(file));
    } else {
        let stdin = std::io::stdin();
        _iter_batch(command_executor, stdin.lock());
    };
}

fn _iter_batch<T>(command_executor: CommandExecutor, reader: T) where T: std::io::BufRead {
    let mut line_num = 1;
    for line in reader.lines() {
        let line = if let Ok(line) = line { line } else {
            return println_err!("Can't parse line #{}", line_num);
        };
        println!("{}", line);
        let (line, force) = if line.starts_with("-") {
            (line[1..].as_ref(), true)
        } else {
            (line[0..].as_ref(), false)
        };
        if command_executor.execute(line).is_err() && !force {
            return println_err!("Batch execution failed at line #{}", line_num);
        }
        println!();
        line_num += 1;
    }
}

impl<Term: Terminal> Completer<Term> for CommandExecutor {
    fn complete(&self, word: &str, reader: &Reader<Term>,
                start: usize, end: usize) -> Option<Vec<Completion>> {
        Some(self
            .complete(reader.buffer(),
                      word,
                      start,
                      end)
            .into_iter()
            .map(|c| Completion {
                completion: c.0,
                display: None,
                suffix: linefeed::Suffix::Some(c.1),
            })
            .collect())
    }
}
<commit_msg>Added help for batch mode<commit_after>extern crate ansi_term;
extern crate unescape;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate linefeed;
#[macro_use]
extern crate log;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
extern crate prettytable;

#[macro_use]
mod utils;
mod command_executor;
#[macro_use]
mod commands;
mod libindy;

use command_executor::CommandExecutor;

use commands::{common, did, ledger, pool, wallet};

use linefeed::{Reader, ReadResult, Terminal};
use linefeed::complete::{Completer, Completion};

use std::env;
use std::fs::File;
use std::io::BufReader;
use std::rc::Rc;

fn main() {
    utils::logger::LoggerUtils::init();

    if env::args().find(|a| a == "-h" || a == "--help").is_some() {
        return _print_help();
    }

    let command_executor = build_executor();

    if env::args().len() == 1 {
        execute_stdin(command_executor);
    } else {
        let mut args = env::args();
        args.next(); //skip 0 param
        execute_batch(command_executor, Some(&args.next().unwrap()))
    }
}

fn build_executor() -> CommandExecutor {
    CommandExecutor::build()
        .add_command(common::about_command::new())
        .add_command(common::exit_command::new())
        .add_command(common::prompt_command::new())
        .add_command(common::show_command::new())
        .add_group(did::group::new())
        .add_command(did::new_command::new())
        .add_command(did::use_command::new())
        .add_command(did::rotate_key_command::new())
        .add_command(did::list_command::new())
        .finalize_group()
        .add_group(pool::group::new())
        .add_command(pool::create_command::new())
        .add_command(pool::connect_command::new())
        .add_command(pool::list_command::new())
        .add_command(pool::disconnect_command::new())
        .add_command(pool::delete_command::new())
        .finalize_group()
        .add_group(wallet::group::new())
        .add_command(wallet::create_command::new())
        .add_command(wallet::open_command::new())
        .add_command(wallet::list_command::new())
        .add_command(wallet::close_command::new())
        .add_command(wallet::delete_command::new())
        .finalize_group()
        .add_group(ledger::group::new())
        .add_command(ledger::nym_command::new())
        .add_command(ledger::get_nym_command::new())
        .add_command(ledger::attrib_command::new())
        .add_command(ledger::get_attrib_command::new())
        .add_command(ledger::schema_command::new())
        .add_command(ledger::get_schema_command::new())
        .add_command(ledger::claim_def_command::new())
        .add_command(ledger::get_claim_def_command::new())
        .add_command(ledger::node_command::new())
        .add_command(ledger::pool_config_command::new())
        .add_command(ledger::pool_upgrade_command::new())
        .add_command(ledger::custom_command::new())
        .finalize_group()
        .finalize()
}

fn execute_stdin(command_executor: CommandExecutor) {
    #[cfg(target_os = "windows")]
        ansi_term::enable_ansi_support().is_ok();

    match Reader::new("indy-cli") {
        Ok(reader) => execute_interactive(command_executor, reader),
        Err(_) => execute_batch(command_executor, None),
    }
}

fn execute_interactive<T>(command_executor: CommandExecutor, mut reader: Reader<T>)
    where T: Terminal {
    let command_executor = Rc::new(command_executor);
    reader.set_completer(command_executor.clone());
    reader.set_prompt(&command_executor.ctx().get_prompt());

    while let Ok(ReadResult::Input(line)) = reader.read_line() {
        if line.trim().is_empty() {
            continue;
        }

        command_executor.execute(&line).is_ok();
        reader.add_history(line);
        reader.set_prompt(&command_executor.ctx().get_prompt());

        if command_executor.ctx().is_exit() {
            break;
        }
    }
}

fn execute_batch(command_executor: CommandExecutor, script_path: Option<&str>) {
    if let Some(script_path) = script_path {
        let file = match File::open(script_path) {
            Ok(file) => file,
            Err(err) => return println_err!("Can't open script file {}\nError: {}", script_path, err),
        };
        _iter_batch(command_executor, BufReader::new(file));
    } else {
        let stdin = std::io::stdin();
        _iter_batch(command_executor, stdin.lock());
    };
}

fn _print_help() {
    println_acc!("Hyperledger Indy CLI");
    println!();
    println_acc!("CLI supports 2 execution modes:");
    println_acc!("\tInteractive - reads commands from terminal. To start just run indy-cli without params.");
    println_acc!("\tUsage: indy-cli");
    println!();
    println_acc!("\tBatch - all commands will be read from text file or pipe and executed in series.");
    println_acc!("\tUsage: indy-cli <path-to-text-file>");
    println!();
}

fn _iter_batch<T>(command_executor: CommandExecutor, reader: T) where T: std::io::BufRead {
    let mut line_num = 1;
    for line in reader.lines() {
        let line = if let Ok(line) = line { line } else {
            return println_err!("Can't parse line #{}", line_num);
        };
        println!("{}", line);
        let (line, force) = if line.starts_with("-") {
            (line[1..].as_ref(), true)
        } else {
            (line[0..].as_ref(), false)
        };
        if command_executor.execute(line).is_err() && !force {
            return println_err!("Batch execution failed at line #{}", line_num);
        }
        println!();
        line_num += 1;
    }
}

impl<Term: Terminal> Completer<Term> for CommandExecutor {
    fn complete(&self, word: &str, reader: &Reader<Term>,
                start: usize, end: usize) -> Option<Vec<Completion>> {
        Some(self
            .complete(reader.buffer(),
                      word,
                      start,
                      end)
            .into_iter()
            .map(|c| Completion {
                completion: c.0,
                display: None,
                suffix: linefeed::Suffix::Some(c.1),
            })
            .collect())
    }
}
<|endoftext|>


<commit_before>mod document_spec;

use futures::future::{Future, ok, err, result};
use futures::sync::oneshot;
use hyper;
use hyper::{Get, Post, Head, StatusCode};
use hyper::client::Client;
use hyper::server::{Request, Response, Service, NewService};
use hyper::header::{Authorization, Bearer};
use hyper_tls::HttpsConnector;
use serde_json;
use slog;
use std::marker::PhantomData;
use tokio_core::reactor::{Remote, Handle};

use http::*;
use error::{Error, ErrorKind};
pub use self::document_spec::{DocumentSpec, PapersUri};
use renderer::Renderer;
use config::Config;

pub trait FromHandle: Clone {
    fn build(handle: &Handle) -> Self;
}

impl FromHandle for Client<HttpsConnector> {
    fn build(handle: &Handle) -> Self {
        Client::configure()
            .connector(https_connector(handle))
            .build(handle)
    }
}

pub fn log_request(logger: &slog::Logger, req: &Request) {
    info!(
        logger,
        "{} {} IP={:?}",
        req.method(),
        req.path(),
        req.remote_addr(),
    );
}

pub struct Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error> + FromHandle + 'static,
{
    remote: Remote,
    config: &'static Config,
    _renderer: PhantomData<C>,
}

impl<C> Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error>
        + FromHandle
        + 'static,
{
    pub fn new(remote: Remote, config: &'static Config) -> Papers<C> {
        Papers {
            remote,
            config,
            _renderer: PhantomData,
        }
    }

    // Check Authorization header if `PAPERS_BEARER` env var is set
    fn check_auth_header(&self, req: &Request) -> Result<(), Error> {
        let headers = req.headers().clone();
        let authorization = headers.get::<Authorization<Bearer>>();
        match authorization {
            Some(header_bearer) => {
                if self.config.auth != "" && header_bearer.token != self.config.auth {
                    return Err(Error::from_kind(ErrorKind::Forbidden));
                }
            }
            None => {
                if self.config.auth != "" {
                    return Err(Error::from_kind(ErrorKind::Forbidden));
                }
            }
        }
        Ok(())
    }

    fn submit(&self, req: Request) -> Box<Future<Item = Response, Error = Error>> {
        debug!(self.config.logger, "{:#?}", req);

        if let Err(error) = self.check_auth_header(&req) {
            return Box::new(err(error));
        }

        if !req.has_content_type(mime!(Application / Json)) {
            return Box::new(err(ErrorKind::UnprocessableEntity.into()));
        }

        let body = req.get_body_bytes();

        let document_spec = body.and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity)),
            )
        });

        let logger = self.config.logger.clone();
        let max_assets_per_document = self.config.max_assets_per_document;
        let document_spec = document_spec.and_then(move |spec| {
            if spec.assets_urls.len() > max_assets_per_document as usize {
                error!(
                    logger,
                    "Assets URLs length exceeds the maximum ({}).\
                    To change it set PAPERS_MAX_ASSETS_PER_DOCUMENT",
                    max_assets_per_document,
                );
                return err(ErrorKind::UnprocessableEntity.into());
            }
            ok(spec)
        });

        let response = {
            let config = self.config;
            let remote = self.remote.clone();
            document_spec.and_then(move |document_spec| {
                remote.spawn(move |handle| {
                    let client = C::build(&handle);
                    Renderer::new(config, handle, client).render(document_spec)
                });
                ok(Response::new().with_status(StatusCode::Ok))
            })
        };

        Box::new(response)
    }

    fn preview(&self, req: Request) -> Box<Future<Item = Response, Error = Error>> {
        debug!(self.config.logger, "{:#?}", req);

        if let Err(error) = self.check_auth_header(&req) {
            return Box::new(err(error));
        }

        if !req.has_content_type(mime!(Application / Json)) {
            return Box::new(err(ErrorKind::UnprocessableEntity.into()));
        }

        let body = req.get_body_bytes();
        let document_spec = body.and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|_| ErrorKind::UnprocessableEntity.into()),
            )
        });

        let preview = {
            let remote = self.remote.clone();
            let config = self.config;
            let (sender, receiver) = oneshot::channel();
            document_spec
                .and_then(move |document_spec| {
                    remote.spawn(move |handle| {
                        let client = C::build(&handle);
                        Renderer::new(config, handle, client).preview(document_spec, sender)
                    });
                    ok(())
                })
                .and_then(move |_| receiver.map_err(|err| panic!(err)))
                .flatten()
        };

        let response = preview.and_then(|populated_template| {
            ok(
                Response::new()
                    .with_status(StatusCode::Ok)
                    .with_body(populated_template),
            )
        });

        Box::new(response)

    }

    fn health_check(&self, _: Request) -> Box<Future<Item = Response, Error = Error>> {
        Box::new(ok(Response::new().with_status(StatusCode::Ok)))
    }
}

impl<C> Service for Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error>
        + FromHandle
        + 'static,
{
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Response, Error = hyper::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        log_request(&self.config.logger, &req);
        let response = match (req.method(), req.path()) {
            (&Get, "/healthz") |
            (&Head, "/healthz") => self.health_check(req),
            (&Post, "/preview") => self.preview(req),
            (&Post, "/submit") => self.submit(req),
            _ => Box::new(ok(Response::new().with_status(StatusCode::NotFound))),
        }.then(|handler_result| match handler_result {
            Ok(response) => ok(response),
            Err(err) => ok(err.into_response()),
        });

        Box::new(response)
    }
}

impl<C> NewService for Papers<C>
where
    C: Service<
        Request = Request,
        Response = Response,
        Error = hyper::Error,
    >
        + FromHandle
        + 'static,
{
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Instance = Papers<C>;

    fn new_service(&self) -> Result<Self::Instance, ::std::io::Error> {
        Ok(Papers {
            remote: self.remote.clone(),
            config: self.config,
            _renderer: PhantomData,
        })
    }
}
<commit_msg>🚨 Fix clippy warnings<commit_after>mod document_spec;

use futures::future::{Future, ok, err, result};
use futures::sync::oneshot;
use hyper;
use hyper::{Get, Post, Head, StatusCode};
use hyper::client::Client;
use hyper::server::{Request, Response, Service, NewService};
use hyper::header::{Authorization, Bearer};
use hyper_tls::HttpsConnector;
use serde_json;
use slog;
use std::marker::PhantomData;
use tokio_core::reactor::{Remote, Handle};

use http::*;
use error::{Error, ErrorKind};
pub use self::document_spec::{DocumentSpec, PapersUri};
use renderer::Renderer;
use config::Config;

pub trait FromHandle: Clone {
    fn build(handle: &Handle) -> Self;
}

impl FromHandle for Client<HttpsConnector> {
    fn build(handle: &Handle) -> Self {
        Client::configure()
            .connector(https_connector(handle))
            .build(handle)
    }
}

pub fn log_request(logger: &slog::Logger, req: &Request) {
    info!(
        logger,
        "{} {} IP={:?}",
        req.method(),
        req.path(),
        req.remote_addr(),
    );
}

pub struct Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error> + FromHandle + 'static,
{
    remote: Remote,
    config: &'static Config,
    _renderer: PhantomData<C>,
}

impl<C> Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error>
        + FromHandle
        + 'static,
{
    pub fn new(remote: Remote, config: &'static Config) -> Papers<C> {
        Papers {
            remote,
            config,
            _renderer: PhantomData,
        }
    }

    // Check Authorization header if `PAPERS_BEARER` env var is set
    fn check_auth_header(&self, req: &Request) -> Result<(), Error> {
        let headers = req.headers().clone();
        let authorization = headers.get::<Authorization<Bearer>>();
        match authorization {
            Some(header_bearer) => {
                if self.config.auth != "" && header_bearer.token != self.config.auth {
                    return Err(Error::from_kind(ErrorKind::Forbidden));
                }
            }
            None => {
                if self.config.auth != "" {
                    return Err(Error::from_kind(ErrorKind::Forbidden));
                }
            }
        }
        Ok(())
    }

    fn submit(&self, req: Request) -> Box<Future<Item = Response, Error = Error>> {
        debug!(self.config.logger, "{:#?}", req);

        if let Err(error) = self.check_auth_header(&req) {
            return Box::new(err(error));
        }

        if !req.has_content_type(mime!(Application / Json)) {
            return Box::new(err(ErrorKind::UnprocessableEntity.into()));
        }

        let body = req.get_body_bytes();

        let document_spec = body.and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|err| Error::with_chain(err, ErrorKind::UnprocessableEntity)),
            )
        });

        let logger = self.config.logger.clone();
        let max_assets_per_document = self.config.max_assets_per_document;
        let document_spec = document_spec.and_then(move |spec| {
            if spec.assets_urls.len() > max_assets_per_document as usize {
                error!(
                    logger,
                    "Assets URLs length exceeds the maximum ({}).\
                    To change it set PAPERS_MAX_ASSETS_PER_DOCUMENT",
                    max_assets_per_document,
                );
                return err(ErrorKind::UnprocessableEntity.into());
            }
            ok(spec)
        });

        let response = {
            let config = self.config;
            let remote = self.remote.clone();
            document_spec.and_then(move |document_spec| {
                remote.spawn(move |handle| {
                    let client = C::build(handle);
                    Renderer::new(config, handle, client).render(document_spec)
                });
                ok(Response::new().with_status(StatusCode::Ok))
            })
        };

        Box::new(response)
    }

    fn preview(&self, req: Request) -> Box<Future<Item = Response, Error = Error>> {
        debug!(self.config.logger, "{:#?}", req);

        if let Err(error) = self.check_auth_header(&req) {
            return Box::new(err(error));
        }

        if !req.has_content_type(mime!(Application / Json)) {
            return Box::new(err(ErrorKind::UnprocessableEntity.into()));
        }

        let body = req.get_body_bytes();
        let document_spec = body.and_then(|body| {
            result(
                serde_json::from_slice::<DocumentSpec>(body.as_slice())
                    .map_err(|_| ErrorKind::UnprocessableEntity.into()),
            )
        });

        let preview = {
            let remote = self.remote.clone();
            let config = self.config;
            let (sender, receiver) = oneshot::channel();
            document_spec
                .and_then(move |document_spec| {
                    remote.spawn(move |handle| {
                        let client = C::build(handle);
                        Renderer::new(config, handle, client).preview(document_spec, sender)
                    });
                    ok(())
                })
                .and_then(move |_| receiver.map_err(|err| panic!(err)))
                .flatten()
        };

        let response = preview.and_then(|populated_template| {
            ok(
                Response::new()
                    .with_status(StatusCode::Ok)
                    .with_body(populated_template),
            )
        });

        Box::new(response)

    }

    fn health_check(&self, _: Request) -> Box<Future<Item = Response, Error = Error>> {
        Box::new(ok(Response::new().with_status(StatusCode::Ok)))
    }
}

impl<C> Service for Papers<C>
where
    C: Service<Request = Request, Response = Response, Error = hyper::Error>
        + FromHandle
        + 'static,
{
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Response, Error = hyper::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        log_request(&self.config.logger, &req);
        let response = match (req.method(), req.path()) {
            (&Get, "/healthz") |
            (&Head, "/healthz") => self.health_check(req),
            (&Post, "/preview") => self.preview(req),
            (&Post, "/submit") => self.submit(req),
            _ => Box::new(ok(Response::new().with_status(StatusCode::NotFound))),
        }.then(|handler_result| match handler_result {
            Ok(response) => ok(response),
            Err(err) => ok(err.into_response()),
        });

        Box::new(response)
    }
}

impl<C> NewService for Papers<C>
where
    C: Service<
        Request = Request,
        Response = Response,
        Error = hyper::Error,
    >
        + FromHandle
        + 'static,
{
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Instance = Papers<C>;

    fn new_service(&self) -> Result<Self::Instance, ::std::io::Error> {
        Ok(Papers {
            remote: self.remote.clone(),
            config: self.config,
            _renderer: PhantomData,
        })
    }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl Program {
    pub fn new(statements: Vec<Statement>) -> Program {
        Program(statements)
    }
}

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.program() {
            Ok(parser.ast())
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        //TODO: This probably isn't the right type since this should accept anything and then get
        // statically checked to ensure the correct number was put here
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    ConditionGroup {
        // Condition expression and body block
        branches: Vec<(Expression, Block)>,
        // "default" or "else" branch body
        default: Option<Block>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub struct Identifier(Vec<String>);

impl FromStr for Identifier {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Identifier(s.split("::").map(|s| s.to_owned()).collect()))
    }
}

impl<'a> From<&'a str> for Identifier {
    fn from(s: &'a str) -> Identifier {
        s.parse().unwrap()
    }
}

pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;
<commit_msg>Revert "Implementation of Identifier as a path of any number of segments"<commit_after>use std::str::FromStr;

use pest::prelude::*;

use super::{Rdp, ParseError};

#[derive(Debug, PartialEq, Clone)]
pub struct Program(Vec<Statement>);

impl Program {
    pub fn new(statements: Vec<Statement>) -> Program {
        Program(statements)
    }
}

impl IntoIterator for Program {
    type Item = Statement;
    type IntoIter = ::std::vec::IntoIter<Statement>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromStr for Program {
    type Err = ParseError;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut parser = Rdp::new(StringInput::new(input));

        if parser.program() {
            Ok(parser.ast())
        }
        else {
            let (expected, pos) = parser.expected();
            let (line, col) = parser.input().line_col(pos);
            Err(ParseError {
                line: line,
                col: col,
                expected: expected,
            })
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Statement {
    Comment(String),
    Declaration {
        pattern: Pattern,
        type_def: TypeDefinition,
        expr: Option<Expression>,
    },
    Assignment {
        lhs: Identifier,
        expr: Expression,
    },
    WhileLoop {
        condition: Expression,
        body: Block,
    },
    Expression {
        expr: Expression,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Pattern {
    Identifier(Identifier),
}

#[derive(Debug, PartialEq, Clone)]
pub enum TypeDefinition {
    Name {
        name: Identifier,
    },
    Array {
        type_def: Box<TypeDefinition>,
        //TODO: This probably isn't the right type since this should accept anything and then get
        // statically checked to ensure the correct number was put here
        size: Option<Expression>,
    },
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    StringLiteral(String),
    Identifier(Identifier),
    Number(Number),
    Call {
        method: Box<Expression>,
        args: FuncArgs,
    },
    Access {
        target: Box<Expression>,
        field: Box<Expression>,
    },
    ConditionGroup {
        // Condition expression and body block
        branches: Vec<(Expression, Block)>,
        // "default" or "else" branch body
        default: Option<Block>,
    },
}

pub type Identifier = String;
pub type Block = Vec<Statement>;
pub type Number = i32;
pub type FuncArgs = Vec<FuncArg>;
pub type FuncArg = Expression;
<|endoftext|>