<commit_before>#![feature(globs)]

extern crate gl;
extern crate glfw;
extern crate native;
extern crate time;

use gl::types::*;
use glfw::Context;
use std::mem;
use std::ptr;
use std::str;

mod actor;
mod actor_manager;

// Shader sources
// vertex shader
static VS_SRC: &'static str =
   "#version 150\n\
    in vec4 shape;\n\
    uniform vec3 position;\n\
    void main() {\n\
        float x = shape[0];\n\
        float y = shape[1];\n\
        float x_pos = position[0];\n\
        float y_pos = position[1];\n\
        float angle = position[2];\n\
        float xx = (x * cos(angle) + y * sin(angle)) + x_pos;\n\
        float yy = (-x * sin(angle) + y * cos(angle)) + y_pos;\n\
        gl_Position = vec4(xx, yy, 0.0, 1.0);\n\
    }";

// fragment shader
static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 0.3, 0.3, 0.8);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &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 = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // 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::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }
    program
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw.create_window(800, 600, "rusteroids", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_all_polling(true);

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| glfw.get_proc_address(s));

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

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

    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);

        // Use shader program
        gl::UseProgram(program);
        "out_color".with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));

        // Specify the layout of the vertex data
        let pos_attr = "shape".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,     // must match the layout in the shader.
                                2,                      // size
                                gl::FLOAT,              // type
                                gl::FALSE as GLboolean, // normalized?
                                0,                      // stride
                                ptr::null());           // array buffer offset

        loc = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));

    }

    let mut t = time::get_time();
    let fr:i32 = 100000000 / 60;

    let mut actors = actor_manager::ActorManager::new();

    let v: Vec<GLfloat> = vec!(
        0.0,  0.05,
        0.025, -0.05,
        -0.025, -0.05,
    );
    let p = actor::Actor::new(1, 0, 0, 0, 0, 10, 10, 0.0, v, 1.1);
    actors.add(p);

    let v: Vec<GLfloat> = vec!(
        0.0,  0.05,
        0.025, -0.05,
        -0.025, -0.05,
    );

    let e = new_actor(0, 0, 100, 100, 2, 2, 0.0, v, 1.1);
    actors.add(e);

    while !window.should_close() {

        // Poll events
        glfw.poll_events();

        let t2 = time::get_time();

        // switch to 1 frame a second
        //let fr = 1000000000;

        if t2.nsec - fr > t.nsec || t2.sec > t.sec {
            t = t2;

            let mut messages = vec!();

            for event in glfw::flush_messages(&events) {
                handle_window_event(&window, event, &mut messages);
            }

            let acs = actors.get();
            for &actor in acs.iter(){
                if actor.t == 1 {
                    messages.push((actor.id, "begin_increase_throttle"));
                }
            }

            calculate_collisions(&actors, &mut messages);

            let mut output_messages = vec!();

            actors.update(messages, &mut output_messages);
            draw_scene(&actors, loc, &window);
            process_messages(&mut output_messages, &mut actors);
        }

    }

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

fn process_messages(output_messages: &Vec<(&str, actor::ActorView)>, actor_manager: &mut actor_manager::ActorManager){

    for &(msg, v) in output_messages.iter(){
        match msg{
            "fire"  => actor_manager.add(new_bullet(v.id, v.x as i32, v.y as i32, v.rotation * 180.0 / 3.14159265359)),
            _       => ()
        }
    }

}

fn new_actor(parent: i32, t:i32, x: i32, y:i32, w: i32, h: i32, r: f32, v: Vec<f32>, acc:f32) -> actor::Actor{
    let id = actor::Actor::get_count();
    actor::Actor::new(id, parent, t, x, y, w, h, r, v, acc)
}

fn new_bullet(parent: i32, x: i32, y:i32, r:f32) -> actor::Actor{
    let v: Vec<GLfloat> = vec!(
        0.0,  0.005,
        0.005, -0.005,
        -0.005, -0.005,
    );
    new_actor(parent, 1, x, y, 2, 2, r, v, 1.8)
}

fn calculate_collisions(actor_manager: &actor_manager::ActorManager, messages: &mut Vec<(i32, &str)>){

    let actors = actor_manager.get();

    for &actor in actors.iter(){
        for &actor2 in actors.iter(){
            if actor.id == actor2.id
                || actor.id == 0
                || actor2.id == 0
                || actor.id == actor2.parent
                || actor2.id == actor.parent {
                continue;
            }

            let d = 10.0;
            let a1 = &actor.get_view();
            let a2 = &actor2.get_view();

            if a1.x + d > a2.x && a1.x - d < a2.x && a1.y + d > a2.y && a1.y - d < a2.y {
                messages.push((actor.id, "die"));
                messages.push((actor2.id, "die"));
            }
        }
    }
}

fn handle_window_event(window: &glfw::Window, (time, event): (f64, glfw::WindowEvent), messages : &mut Vec<(i32, &str)>) {
    match event {
        // glfw::PosEvent(x, y)                => window.set_title(format!("Time: {}, Window pos: ({}, {})", time, x, y).as_slice()),
        // glfw::SizeEvent(w, h)               => window.set_title(format!("Time: {}, Window size: ({}, {})", time, w, h).as_slice()),
        glfw::CloseEvent                    => println!("Time: {}, Window close requested.", time),
        glfw::RefreshEvent                  => println!("Time: {}, Window refresh callback triggered.", time),
        glfw::FocusEvent(true)              => println!("Time: {}, Window focus gained.", time),
        glfw::FocusEvent(false)             => println!("Time: {}, Window focus lost.", time),
        glfw::IconifyEvent(true)            => println!("Time: {}, Window was minimised", time),
        glfw::IconifyEvent(false)           => println!("Time: {}, Window was maximised.", time),
        glfw::FramebufferSizeEvent(w, h)    => println!("Time: {}, Framebuffer size: ({}, {})", time, w, h),
        // glfw::CharEvent(character)          => println!("Time: {}, Character: {}", time, character),
        glfw::MouseButtonEvent(btn, action, mods) => println!("Time: {}, Button: {}, Action: {}, Modifiers: [{}]", time, glfw::ShowAliases(btn), action, mods),
        // glfw::CursorPosEvent(xpos, ypos)    => window.set_title(format!("Time: {}, Cursor position: ({}, {})", time, xpos, ypos).as_slice()),
        glfw::CursorEnterEvent(true)        => println!("Time: {}, Cursor entered window.", time),
        glfw::CursorEnterEvent(false)       => println!("Time: {}, Cursor left window.", time),
        // glfw::ScrollEvent(x, y)             => window.set_title(format!("Time: {}, Scroll offset: ({}, {})", time, x, y).as_slice()),
        glfw::KeyEvent(key, /* scancode */ _, action, /* mods */ _ ) => {
            // println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
            match (key, action) {
                (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                (glfw::KeyUp, glfw::Press) => messages.push((1, "begin_increase_throttle")),
                (glfw::KeyDown, glfw::Press) => messages.push((1, "begin_decrease_throttle")),
                (glfw::KeyUp, glfw::Release) => messages.push((1, "stop_increase_throttle")),
                (glfw::KeyDown, glfw::Release) => messages.push((1, "stop_decrease_throttle")),
                (glfw::KeyRight, glfw::Press) => messages.push((1, "begin_rotate_right")),
                (glfw::KeyLeft, glfw::Press) => messages.push((1, "begin_rotate_left")),
                (glfw::KeyRight, glfw::Release) => messages.push((1, "stop_rotate_right")),
                (glfw::KeyLeft, glfw::Release) => messages.push((1, "stop_rotate_left")),
                (glfw::KeySpace, glfw::Release) => messages.push((1, "fire")),
                // (glfw::KeyR, glfw::Press) => {
                //     // Resize should cause the window to "refresh"
                //     let (window_width, window_height) = window.get_size();
                //     window.set_size(window_width + 1, window_height);
                //     window.set_size(window_width, window_height);
                // }
                _ => {}
            }
        },

        _ => ()
    }
}

fn draw_scene(actor_manager:&actor_manager::ActorManager, loc:i32, window: &glfw::Window){

    let actors = actor_manager.get();

    // Clear the screen to black
    gl::ClearColor(0.2, 0.2, 0.4, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    for &actor in actors.iter() {
        let v = &actor.get_view();
        let s = actor.get_shape();
        draw_actor(v, s, loc);
    }

    window.swap_buffers();
}

fn draw_actor(p: &actor::ActorView, v:&Vec<f32>, loc:i32){

    unsafe{

        gl::BufferData(gl::ARRAY_BUFFER,
               (v.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
               mem::transmute(&v[0]),
               gl::DYNAMIC_DRAW); // STATIC | DYNAMIC | STREAM

        gl::Uniform3f(loc, p.x / 2000.0, p.y / 2000.0, p.rotation);
    }

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
}
<commit_msg>slightly better collison detection<commit_after>#![feature(globs)]

extern crate gl;
extern crate glfw;
extern crate native;
extern crate time;

use gl::types::*;
use glfw::Context;
use std::mem;
use std::ptr;
use std::str;

mod actor;
mod actor_manager;

// Shader sources
// vertex shader
static VS_SRC: &'static str =
   "#version 150\n\
    in vec4 shape;\n\
    uniform vec3 position;\n\
    void main() {\n\
        float x = shape[0];\n\
        float y = shape[1];\n\
        float x_pos = position[0];\n\
        float y_pos = position[1];\n\
        float angle = position[2];\n\
        float xx = (x * cos(angle) + y * sin(angle)) + x_pos;\n\
        float yy = (-x * sin(angle) + y * cos(angle)) + y_pos;\n\
        gl_Position = vec4(xx, yy, 0.0, 1.0);\n\
    }";

// fragment shader
static FS_SRC: &'static str =
   "#version 150\n\
    out vec4 out_color;\n\
    void main() {\n\
       out_color = vec4(1.0, 0.3, 0.3, 0.8);\n\
    }";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &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 = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();
    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);
    unsafe {
        // 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::from_elem(len as uint - 1, 0u8);     // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }
    program
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    // Choose a GL profile that is compatible with OS X 10.7+
    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw.create_window(800, 600, "rusteroids", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_all_polling(true);

    // It is essential to make the context current before calling `gl::load_with`.
    window.make_current();

    // Load the OpenGL function pointers
    gl::load_with(|s| glfw.get_proc_address(s));

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

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

    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);

        // Use shader program
        gl::UseProgram(program);
        "out_color".with_c_str(|ptr| gl::BindFragDataLocation(program, 0, ptr));

        // Specify the layout of the vertex data
        let pos_attr = "shape".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,     // must match the layout in the shader.
                                2,                      // size
                                gl::FLOAT,              // type
                                gl::FALSE as GLboolean, // normalized?
                                0,                      // stride
                                ptr::null());           // array buffer offset

        loc = "position".with_c_str(|ptr| gl::GetUniformLocation(program, ptr));

    }

    let mut t = time::get_time();
    let fr:i32 = 100000000 / 60;

    let mut actors = actor_manager::ActorManager::new();

    let v: Vec<GLfloat> = vec!(
        0.0,  0.05,
        0.025, -0.05,
        -0.025, -0.05,
    );
    let p = actor::Actor::new(1, 0, 0, 0, 0, 10, 10, 0.0, v, 1.1);
    actors.add(p);

    let v: Vec<GLfloat> = vec!(
        0.0,  0.05,
        0.025, -0.05,
        -0.025, -0.05,
    );

    let e = new_actor(0, 0, 400, 400, 2, 2, 0.0, v, 1.1);
    actors.add(e);

    while !window.should_close() {

        // Poll events
        glfw.poll_events();

        let t2 = time::get_time();

        // switch to 1 frame a second
        //let fr = 1000000000;

        if t2.nsec - fr > t.nsec || t2.sec > t.sec {
            t = t2;

            let mut messages = vec!();

            for event in glfw::flush_messages(&events) {
                handle_window_event(&window, event, &mut messages);
            }

            let acs = actors.get();
            for &actor in acs.iter(){
                if actor.t == 1 {
                    messages.push((actor.id, "begin_increase_throttle"));
                }
            }

            calculate_collisions(&actors, &mut messages);

            let mut output_messages = vec!();

            actors.update(messages, &mut output_messages);
            draw_scene(&actors, loc, &window);
            process_messages(&mut output_messages, &mut actors);
        }

    }

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

fn process_messages(output_messages: &Vec<(&str, actor::ActorView)>, actor_manager: &mut actor_manager::ActorManager){

    for &(msg, v) in output_messages.iter(){
        println!("message : {} - {}", msg, v);
        match msg{
            "fire"  => actor_manager.add(new_bullet(v.id, v.x as i32, v.y as i32, v.rotation * 180.0 / 3.14159265359)),
            _       => ()
        }
    }

}

fn new_actor(parent: i32, t:i32, x: i32, y:i32, w: i32, h: i32, r: f32, v: Vec<f32>, acc:f32) -> actor::Actor{
    let id = actor::Actor::get_count();
    actor::Actor::new(id, parent, t, x, y, w, h, r, v, acc)
}

fn new_bullet(parent: i32, x: i32, y:i32, r:f32) -> actor::Actor{
    let v: Vec<GLfloat> = vec!(
        0.0,  0.005,
        0.005, -0.005,
        -0.005, -0.005,
    );
    new_actor(parent, 1, x, y, 2, 2, r, v, 1.8)
}

fn calculate_collisions(actor_manager: &actor_manager::ActorManager, messages: &mut Vec<(i32, &str)>){

    let actors = actor_manager.get();

    for &actor in actors.iter(){

        let actors2 = actor_manager.get();
        for &actor2 in actors2.iter(){

            if     actor.id     == 0
                || actor2.id    == 0
                || actor.id     == actor2.id
                || actor.id     == actor2.parent
                || actor2.id    == actor.parent {
                continue;
            }

            let d = 100.0;
            let a1 = &actor.get_view();
            let a2 = &actor2.get_view();

            if a1.x + d > a2.x && a1.x - d < a2.x && a1.y + d > a2.y && a1.y - d < a2.y {
                println!("boom! : {} + {}", actor.id, actor2.id);
                messages.push((actor.id, "die"));
            }
        }
    }

}

fn handle_window_event(window: &glfw::Window, (time, event): (f64, glfw::WindowEvent), messages : &mut Vec<(i32, &str)>) {
    match event {
        // glfw::PosEvent(x, y)                => window.set_title(format!("Time: {}, Window pos: ({}, {})", time, x, y).as_slice()),
        // glfw::SizeEvent(w, h)               => window.set_title(format!("Time: {}, Window size: ({}, {})", time, w, h).as_slice()),
        glfw::CloseEvent                    => println!("Time: {}, Window close requested.", time),
        glfw::RefreshEvent                  => println!("Time: {}, Window refresh callback triggered.", time),
        glfw::FocusEvent(true)              => println!("Time: {}, Window focus gained.", time),
        glfw::FocusEvent(false)             => println!("Time: {}, Window focus lost.", time),
        glfw::IconifyEvent(true)            => println!("Time: {}, Window was minimised", time),
        glfw::IconifyEvent(false)           => println!("Time: {}, Window was maximised.", time),
        glfw::FramebufferSizeEvent(w, h)    => println!("Time: {}, Framebuffer size: ({}, {})", time, w, h),
        // glfw::CharEvent(character)          => println!("Time: {}, Character: {}", time, character),
        glfw::MouseButtonEvent(btn, action, mods) => println!("Time: {}, Button: {}, Action: {}, Modifiers: [{}]", time, glfw::ShowAliases(btn), action, mods),
        // glfw::CursorPosEvent(xpos, ypos)    => window.set_title(format!("Time: {}, Cursor position: ({}, {})", time, xpos, ypos).as_slice()),
        glfw::CursorEnterEvent(true)        => println!("Time: {}, Cursor entered window.", time),
        glfw::CursorEnterEvent(false)       => println!("Time: {}, Cursor left window.", time),
        // glfw::ScrollEvent(x, y)             => window.set_title(format!("Time: {}, Scroll offset: ({}, {})", time, x, y).as_slice()),
        glfw::KeyEvent(key, /* scancode */ _, action, /* mods */ _ ) => {
            // println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
            match (key, action) {
                (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                (glfw::KeyUp, glfw::Press) => messages.push((1, "begin_increase_throttle")),
                (glfw::KeyDown, glfw::Press) => messages.push((1, "begin_decrease_throttle")),
                (glfw::KeyUp, glfw::Release) => messages.push((1, "stop_increase_throttle")),
                (glfw::KeyDown, glfw::Release) => messages.push((1, "stop_decrease_throttle")),
                (glfw::KeyRight, glfw::Press) => messages.push((1, "begin_rotate_right")),
                (glfw::KeyLeft, glfw::Press) => messages.push((1, "begin_rotate_left")),
                (glfw::KeyRight, glfw::Release) => messages.push((1, "stop_rotate_right")),
                (glfw::KeyLeft, glfw::Release) => messages.push((1, "stop_rotate_left")),
                (glfw::KeySpace, glfw::Release) => messages.push((1, "fire")),
                // (glfw::KeyR, glfw::Press) => {
                //     // Resize should cause the window to "refresh"
                //     let (window_width, window_height) = window.get_size();
                //     window.set_size(window_width + 1, window_height);
                //     window.set_size(window_width, window_height);
                // }
                _ => {}
            }
        },

        _ => ()
    }
}

fn draw_scene(actor_manager:&actor_manager::ActorManager, loc:i32, window: &glfw::Window){

    let actors = actor_manager.get();

    // Clear the screen to black
    gl::ClearColor(0.2, 0.2, 0.4, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);

    for &actor in actors.iter() {
        let v = &actor.get_view();
        let s = actor.get_shape();
        draw_actor(v, s, loc);
    }

    window.swap_buffers();
}

fn draw_actor(p: &actor::ActorView, v:&Vec<f32>, loc:i32){

    unsafe{

        gl::BufferData(gl::ARRAY_BUFFER,
               (v.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
               mem::transmute(&v[0]),
               gl::DYNAMIC_DRAW); // STATIC | DYNAMIC | STREAM

        gl::Uniform3f(loc, p.x / 2000.0, p.y / 2000.0, p.rotation);
    }

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
}
<|endoftext|>


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

use std::collections::HashMap;
use std::io;
use std::io::prelude::*;
use std::fs;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::env;
use std::env::consts::{DLL_EXTENSION, DLL_PREFIX};

extern crate itertools;
use itertools::*;

#[macro_use]
extern crate clap;
use clap::Arg;

extern crate colored;
use colored::*;

extern crate difference_engine;
use difference_engine::*;

fn main() {
  let arg_matches =
    clap::App::new("DEng, the Difference Engine")
      .version(crate_version!())
      .author("Alexander Altman")
      .about("An extensible language-aware diff")
      .settings(&[clap::AppSettings::ColoredHelp])
      .args(&[Arg::with_name("show languages")
                .long("show-languages")
                .short("L")
                .help("Lists all of the languages currently supported by DEng")
                .conflicts_with_all(&["show presentations", "language name", "presentation name", "old file", "new file"]),
              Arg::with_name("show presentations")
                .long("show-presentations")
                .short("P")
                .help("Lists all of the presentations currently supported by DEng")
                .conflicts_with_all(&["show languages", "language name", "presentation name", "old file", "new file"]),
              Arg::with_name("language name")
                .long("language")
                .short("l")
                .help("The language to use when examining the supplied files for differences.{n}If this option isn't provided, DEng \
                       will perform a naïve line-by-line diff.")
                .takes_value(true),
              Arg::with_name("presentation name")
                .long("presentation")
                .short("p")
                .help("The presentation to use when outputting the calculated diff.{n}If this option isn't provided, DEng will color \
                       new-file-only parts red and old-file-only parts green.")
                .takes_value(true),
              Arg::with_name("old file")
                .help("The file to consider “old” for the purposes of finding differences.{n}DEng will interpret a ‘-’ here as \
                       standard input.")
                .required(true),
              Arg::with_name("new file")
                .help("The file to consider “new” for the purposes of finding differences.{n}DEng will interpret a ‘-’ here as \
                       standard input.")
                .required(true)])
      .get_matches();

  let mut registered_languages_vec: Vec<Box<Language>> = vec![Box::new(SimpleLinewise), Box::new(SimpleCharwise)];
  let raw_language_plugin_path = env::var_os("DENG_RAW_LANGUAGE_PLUGIN_PATH");
  for plugin in env::current_dir()
    .into_iter()
    .map(|d| d.join(".deng").join("languages").join("raw"))
    .chain(raw_language_plugin_path.as_ref().into_iter().flat_map(env::split_paths))
    .chain(env::home_dir().into_iter().map(|d| d.join(".deng").join("languages").join("raw")))
    .flat_map(|d| d.read_dir().into_iter())
    .flatten()
    .flatten()
    .map(|e| e.path())
    .filter(|p| {
      p.file_stem().and_then(|s| s.to_str()).map(|s| s.starts_with(DLL_PREFIX)) == Some(true) &&
      p.extension().map(|s| s == DLL_EXTENSION) == Some(true)
    })
    .flat_map(|p| RawPluginLanguage::load(&p).into_iter()) {
    registered_languages_vec.push(Box::new(plugin));
  }
  let registered_languages: HashMap<String, Box<Language>> =
    registered_languages_vec.into_iter().map(|language| (language.name(), language)).unique_by(|nl| nl.0.clone()).collect();

  let mut registered_presentations_vec: Vec<Box<Presentation>> = vec![Box::new(BasicColored), Box::new(BasicStyled)];
  let raw_presentation_plugin_path = env::var_os("DENG_RAW_PRESENTATION_PLUGIN_PATH");
  for plugin in env::current_dir()
    .into_iter()
    .map(|d| d.join(".deng").join("presentations").join("raw"))
    .chain(raw_presentation_plugin_path.as_ref().into_iter().flat_map(env::split_paths))
    .chain(env::home_dir().into_iter().map(|d| d.join(".deng").join("presentations").join("raw")))
    .flat_map(|d| d.read_dir().into_iter())
    .flatten()
    .flatten()
    .map(|e| e.path())
    .filter(|p| {
      p.file_stem().and_then(|s| s.to_str()).map(|s| s.starts_with(DLL_PREFIX)) == Some(true) &&
      p.extension().map(|s| s == DLL_EXTENSION) == Some(true)
    })
    .flat_map(|p| RawPluginPresentation::load(&p).into_iter()) {
    registered_presentations_vec.push(Box::new(plugin));
  }
  let registered_presentations: HashMap<String, Box<Presentation>> =
    registered_presentations_vec.into_iter().map(|presentation| (presentation.name(), presentation)).unique_by(|np| np.0.clone()).collect();

  if arg_matches.is_present("show languages") {
    for language in registered_languages.values() {
      println!("{}:\t{}", language.name().bold(), language.description());
    }
    return;
  }

  if arg_matches.is_present("show presentations") {
    for presentation in registered_presentations.values() {
      println!("{}:\t{}", presentation.name().bold(), presentation.description());
    }
    return;
  }

  let language_name = arg_matches.value_of("language name").unwrap_or("simple-linewise");
  let language = registered_languages.get(language_name).expect("could not find language");

  let presentation_name = arg_matches.value_of("presentation name").unwrap_or("basic-colored");
  let presentation = registered_presentations.get(presentation_name).expect("could not find presentation");

  let (old_file, new_file) = resolve_files(arg_matches.value_of_os("old file").unwrap(),
                                           arg_matches.value_of_os("new file").unwrap());

  presentation.present(language.diff(old_file, new_file));
}

fn resolve_files(old_file_arg: &OsStr, new_file_arg: &OsStr) -> (String, String) {
  let old_file_path = handle_stdin_notation(old_file_arg).map(canonicalize_path);
  let new_file_path = handle_stdin_notation(new_file_arg).map(canonicalize_path);
  let old_file = old_file_path.clone()
                              .map(|path| read_whole_file(fs::File::open(path).expect("error opening file")))
                              .unwrap_or_else(|| read_whole_file(io::stdin()));
  let new_file;
  if old_file_path == new_file_path.clone() {
    new_file = old_file.clone();
  } else {
    new_file = new_file_path.map(|path| read_whole_file(fs::File::open(path).expect("error opening file")))
                            .unwrap_or_else(|| read_whole_file(io::stdin()));
  }
  return (old_file, new_file);
}

fn handle_stdin_notation(arg: &OsStr) -> Option<&OsStr> {
  if arg == "-" {
    return None;
  } else {
    return Some(arg);
  }
}

fn canonicalize_path(path: &OsStr) -> PathBuf { fs::canonicalize(path).expect("error locating file") }

fn read_whole_file<F: Read>(mut file: F) -> String {
  let mut result = String::new();
  file.read_to_string(&mut result).expect("error reading file");
  return result;
}
<commit_msg>Fix regression due to pending stabilization of Iterator::flatten<commit_after>// main.rs
// Copyright 2016 Alexander Altman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::io;
use std::io::prelude::*;
use std::fs;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::env;
use std::env::consts::{DLL_EXTENSION, DLL_PREFIX};

extern crate itertools;
use itertools::*;

#[macro_use]
extern crate clap;
use clap::Arg;

extern crate colored;
use colored::*;

extern crate difference_engine;
use difference_engine::*;

fn main() {
  let arg_matches =
    clap::App::new("DEng, the Difference Engine")
      .version(crate_version!())
      .author("Alexander Altman")
      .about("An extensible language-aware diff")
      .settings(&[clap::AppSettings::ColoredHelp])
      .args(&[Arg::with_name("show languages")
                .long("show-languages")
                .short("L")
                .help("Lists all of the languages currently supported by DEng")
                .conflicts_with_all(&["show presentations", "language name", "presentation name", "old file", "new file"]),
              Arg::with_name("show presentations")
                .long("show-presentations")
                .short("P")
                .help("Lists all of the presentations currently supported by DEng")
                .conflicts_with_all(&["show languages", "language name", "presentation name", "old file", "new file"]),
              Arg::with_name("language name")
                .long("language")
                .short("l")
                .help("The language to use when examining the supplied files for differences.{n}If this option isn't provided, DEng \
                       will perform a naïve line-by-line diff.")
                .takes_value(true),
              Arg::with_name("presentation name")
                .long("presentation")
                .short("p")
                .help("The presentation to use when outputting the calculated diff.{n}If this option isn't provided, DEng will color \
                       new-file-only parts red and old-file-only parts green.")
                .takes_value(true),
              Arg::with_name("old file")
                .help("The file to consider “old” for the purposes of finding differences.{n}DEng will interpret a ‘-’ here as \
                       standard input.")
                .required(true),
              Arg::with_name("new file")
                .help("The file to consider “new” for the purposes of finding differences.{n}DEng will interpret a ‘-’ here as \
                       standard input.")
                .required(true)])
      .get_matches();

  let mut registered_languages_vec: Vec<Box<Language>> = vec![Box::new(SimpleLinewise), Box::new(SimpleCharwise)];
  let raw_language_plugin_path = env::var_os("DENG_RAW_LANGUAGE_PLUGIN_PATH");
  for plugin in Itertools::flatten(Itertools::flatten(env::current_dir()
      .into_iter()
      .map(|d| d.join(".deng").join("languages").join("raw"))
      .chain(raw_language_plugin_path.as_ref().into_iter().flat_map(env::split_paths))
      .chain(env::home_dir().into_iter().map(|d| d.join(".deng").join("languages").join("raw")))
      .flat_map(|d| d.read_dir().into_iter())
    ))
    .map(|e| e.path())
    .filter(|p| {
      p.file_stem().and_then(|s| s.to_str()).map(|s| s.starts_with(DLL_PREFIX)) == Some(true) &&
      p.extension().map(|s| s == DLL_EXTENSION) == Some(true)
    })
    .flat_map(|p| RawPluginLanguage::load(&p).into_iter()) {
    registered_languages_vec.push(Box::new(plugin));
  }
  let registered_languages: HashMap<String, Box<Language>> =
    registered_languages_vec.into_iter().map(|language| (language.name(), language)).unique_by(|nl| nl.0.clone()).collect();

  let mut registered_presentations_vec: Vec<Box<Presentation>> = vec![Box::new(BasicColored), Box::new(BasicStyled)];
  let raw_presentation_plugin_path = env::var_os("DENG_RAW_PRESENTATION_PLUGIN_PATH");
  for plugin in env::current_dir()
    .into_iter()
    .map(|d| d.join(".deng").join("presentations").join("raw"))
    .chain(raw_presentation_plugin_path.as_ref().into_iter().flat_map(env::split_paths))
    .chain(env::home_dir().into_iter().map(|d| d.join(".deng").join("presentations").join("raw")))
    .flat_map(|d| d.read_dir().into_iter())
    .flatten()
    .flatten()
    .map(|e| e.path())
    .filter(|p| {
      p.file_stem().and_then(|s| s.to_str()).map(|s| s.starts_with(DLL_PREFIX)) == Some(true) &&
      p.extension().map(|s| s == DLL_EXTENSION) == Some(true)
    })
    .flat_map(|p| RawPluginPresentation::load(&p).into_iter()) {
    registered_presentations_vec.push(Box::new(plugin));
  }
  let registered_presentations: HashMap<String, Box<Presentation>> =
    registered_presentations_vec.into_iter().map(|presentation| (presentation.name(), presentation)).unique_by(|np| np.0.clone()).collect();

  if arg_matches.is_present("show languages") {
    for language in registered_languages.values() {
      println!("{}:\t{}", language.name().bold(), language.description());
    }
    return;
  }

  if arg_matches.is_present("show presentations") {
    for presentation in registered_presentations.values() {
      println!("{}:\t{}", presentation.name().bold(), presentation.description());
    }
    return;
  }

  let language_name = arg_matches.value_of("language name").unwrap_or("simple-linewise");
  let language = registered_languages.get(language_name).expect("could not find language");

  let presentation_name = arg_matches.value_of("presentation name").unwrap_or("basic-colored");
  let presentation = registered_presentations.get(presentation_name).expect("could not find presentation");

  let (old_file, new_file) = resolve_files(arg_matches.value_of_os("old file").unwrap(),
                                           arg_matches.value_of_os("new file").unwrap());

  presentation.present(language.diff(old_file, new_file));
}

fn resolve_files(old_file_arg: &OsStr, new_file_arg: &OsStr) -> (String, String) {
  let old_file_path = handle_stdin_notation(old_file_arg).map(canonicalize_path);
  let new_file_path = handle_stdin_notation(new_file_arg).map(canonicalize_path);
  let old_file = old_file_path.clone()
                              .map(|path| read_whole_file(fs::File::open(path).expect("error opening file")))
                              .unwrap_or_else(|| read_whole_file(io::stdin()));
  let new_file;
  if old_file_path == new_file_path.clone() {
    new_file = old_file.clone();
  } else {
    new_file = new_file_path.map(|path| read_whole_file(fs::File::open(path).expect("error opening file")))
                            .unwrap_or_else(|| read_whole_file(io::stdin()));
  }
  return (old_file, new_file);
}

fn handle_stdin_notation(arg: &OsStr) -> Option<&OsStr> {
  if arg == "-" {
    return None;
  } else {
    return Some(arg);
  }
}

fn canonicalize_path(path: &OsStr) -> PathBuf { fs::canonicalize(path).expect("error locating file") }

fn read_whole_file<F: Read>(mut file: F) -> String {
  let mut result = String::new();
  file.read_to_string(&mut result).expect("error reading file");
  return result;
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write; // need it to flush stdout
use std::env;
use std::path::PathBuf;
use std::process;
use std::process::{Stdio, Command};

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! print_err {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            print_err!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            print_err!(why);
        }
    }
}

fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "exit" => {
            println!("So long, and thanks for all the fish!");
            process::exit(0);
        }
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                print_err!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for popularing CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {
        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&' {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a spcae before it right now
            cmdline.bg = true;
            break;
        } else if i == 0 {
            cmdline.cmd = each.trim().to_string();
        } else {
            cmdline.args.push(each.trim().to_string());
        }
    }
}

fn main() {

    // main shell loop
    loop {

        let mut cmdline: CommandLine = CommandLine {
            cmd: String::new(),
            args: Vec::new(),
            bg: false
        };

        // print prompt
        print!("{}", get_prompt());
        if let Err(why) = io::stdout().flush() {
            print_err!(why);
            continue;
        }

        // read input into our String. if bytes_read is 0, we've hit EOF
        // and should exit. if there was an error, print the
        // error message and restart loop
        match io::stdin().read_line(&mut cmdline.cmd) {
            Ok(bytes_read) =>
                // Exit on EOF (Ctrl-d, end of script)
                if bytes_read == 0 {
                    println!("");
                    break;
                },
            Err(why) => {
                print_err!(why);
                continue;
            }
        }

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<commit_msg>Minor fix<commit_after>use std::io;
use std::io::Write; // need it to flush stdout
use std::env;
use std::path::PathBuf;
use std::process;
use std::process::{Stdio, Command};

static BUILTINS: [&'static str; 3] = ["exit", "cd", "pwd"];

struct CommandLine {
    // command name
    cmd: String,
    // arguments, starting directly with the first actual argument
    args: Vec<String>,
    // whether to execute as background process
    bg: bool
}

// probaby doesn't need to be a macro
macro_rules! print_err {
    ($msg:expr) => (println!("relish: {}", $msg));
}

/*
 * get_pwd - returns String containing pwd or "???" if there was an error
 */
fn get_pwd() -> String {
    match env::current_dir() {
        Ok(pwd) => {
            pwd.to_string_lossy().to_string()
        }
        Err(_) => {
            "???".to_string()
        }
    }
}

/*
 * execute - execute shell command line based on input CommandLine
 */
fn execute(cmdline: &CommandLine) {
    let mut _cmd = Command::new(&cmdline.cmd);
    let cmd = _cmd.args(&cmdline.args);

    if cmdline.bg {
        if let Err(why) = cmd.spawn() {
            print_err!(why);
        }
    } else {
        if let Err(why) = cmd.stdout(Stdio::inherit())
                             .stderr(Stdio::inherit())
                             .output() {
            print_err!(why);
        }
    }
}

fn builtin(cmdline: &CommandLine) {
    match &cmdline.cmd[..] {
        "exit" => {
            println!("So long, and thanks for all the fish!");
            process::exit(0);
        }
        "cd" => {
            // get dir to change to based on the length of cmdline.args
            let dir = if cmdline.args.len() == 0 {
                env::home_dir().unwrap_or(PathBuf::from("."))
            } else {
                // if they say `cd -`
                if cmdline.args[0] == "-" {
                    // return $OLDPWD, or "." if it's not available
                    PathBuf::from(&env::var("OLDPWD")
                                             .unwrap_or(".".to_string()))
                } else {
                    // create PathBuf from what they actually said
                    PathBuf::from(&cmdline.args[0])
                }
            };

            // set $OLDPWD
            env::set_var("OLDPWD", &env::current_dir()
                                        .unwrap_or(PathBuf::from(".".to_string())));
            // change directory
            if let Err(why) = env::set_current_dir(&dir) {
                print_err!(why);
            }
        }
        "pwd" => println!("{}", get_pwd()),
        _ => {}
    }
}

/*
 * get_prompt - generate and return shell prompt
 */
fn get_prompt() -> String {
    // get username
    let username = env::var("USER").unwrap_or("???".to_string());

    // get hostname
    let hostname = Command::new("/bin/hostname").output().unwrap();
    let hostname = String::from_utf8_lossy(&hostname.stdout);
    let hostname = hostname.trim();

    format!("{}@{} {} $ ", username, hostname, get_pwd())
}

/*
 * preprocess - main parsing routine responsible for populating CommandLine
 * struct
 */
fn preprocess(cmdline: &mut CommandLine) {
    let tmp = cmdline.cmd.clone();
    // TODO: this is awful, refactor to not use a loop
    for (i, each) in tmp.split(' ').enumerate() {
        if each.trim() == "" {
            // eat extra tabs/spaces
            continue;
        } else if each.trim().chars().nth(0).unwrap() == '#' {
            // stop parsing if there's a comment
            // ok to use unwrap because we've guaranteed input isn't empty
            break;
        } else if each.trim().chars().nth(0).unwrap() == '&' {
            // background process, ignoring rest of input
            // TODO: probably shouldn't just ignore rest of input. also,
            // the & has to have a space before it right now
            cmdline.bg = true;
            break;
        } else if i == 0 {
            cmdline.cmd = each.trim().to_string();
        } else {
            cmdline.args.push(each.trim().to_string());
        }
    }
}

fn main() {

    // main shell loop
    loop {

        let mut cmdline: CommandLine = CommandLine {
            cmd: String::new(),
            args: Vec::new(),
            bg: false
        };

        // print prompt
        print!("{}", get_prompt());
        if let Err(why) = io::stdout().flush() {
            print_err!(why);
            continue;
        }

        // read input into our String. if bytes_read is 0, we've hit EOF
        // and should exit. if there was an error, print the
        // error message and restart loop
        match io::stdin().read_line(&mut cmdline.cmd) {
            Ok(bytes_read) =>
                // Exit on EOF (Ctrl-d, end of script)
                if bytes_read == 0 {
                    println!("");
                    break;
                },
            Err(why) => {
                print_err!(why);
                continue;
            }
        }

        // check if blank/comment
        cmdline.cmd = cmdline.cmd.trim().to_string();
        match cmdline.cmd.chars().nth(0) {
            Some(first) =>
                if first == '#' {
                    continue
                },
            None => continue // empty string
        }

        // parse
        preprocess(&mut cmdline);

        // handle builtins
        if BUILTINS.contains(&&cmdline.cmd[..]) {
            builtin(&cmdline)
        } else {
            execute(&cmdline);
        }
    }
}
<|endoftext|>


<commit_before>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::fs::File;

mod utils;
use self::utils::logger;

// shorthand to display program usage
macro_rules! print_usage {
    ($prog:ident, $opts:ident) => {{
        print!("{}", $opts.usage(&format!("Usage: {} [-h] [-v] [-o OUTPUT] INPUT", $prog)));
    }}
}

fn main() {
    //early init

    //let _ = SimpleLogger::init(LogLevelFilter::Info);
    let _ = logger::CombinedLogger::init(
        vec![
            logger::FileLogger::new(logger::LogLevelFilter::Trace, File::create("zwreec.log").unwrap()),
            logger::TermLogger::new(logger::LogLevelFilter::Info),
        ]
    );

    info!("main started");

    // handling commandline parameters
    let args: Vec<String> = env::args().collect();
    let ref program = args[0];

    // define options
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("v", "verbose", "be more verbose");
    opts.optopt("o", "", "name of the output file", "FILE");

    let parsed_opts = match opts.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(f) => {
            // parsing error
            // display usage and return
            println!("{}", f.to_string());
            print_usage!(program, opts);
            // TODO: figure out a way to set exit code
            return;
        }
    };

    // examinate options
    if parsed_opts.opt_present("h") {
        // parsed "-h|--help"
        // display usage and return
        print_usage!(program, opts);
        return;
    }

    if parsed_opts.opt_present("v") {
        // parsed "-v|--verbose"
        // set loglevel to verbose
        // utils::log::LOG_LEVEL = utils::log::LogLevel::VERBOSE;
    }

    let outfile = if let Some(file) = parsed_opts.opt_str("o") {
        // parsed "-o FILE"
        // set of to filename
        file
    } else {
        // NOTE: string manipulation in rust is stil weird.
        let mut s = String::new();
        s.push_str("a.out");
        s
    };

    let infile = if parsed_opts.free.len() == 1 {
         // check number of 'free' parameter
         // one free parameter is the input file name
         parsed_opts.free[0].clone()
    } else {
        println!("Input file name missing");
        print_usage!(program, opts);
        // TODO: figure out a way to set exit code
        return;
    };

    // call library
    zwreec::compile(&infile, &outfile);

    // only for testing
    debug!("(1) {}", zwreec::frontend::temp_hello());
    debug!("(2) {}", zwreec::backend::temp_hello());
    debug!("(3) {}", zwreec::file::temp_hello());

    info!("main finished");
}
<commit_msg>Add CLI Arguments to control the new logger<commit_after>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::vec::Vec;
use std::fs::File;
use std::io::Write;

mod utils;
use self::utils::logger;

// shorthand to display program usage
macro_rules! print_usage {
    ($prog:ident, $opts:ident) => {{
        print_stderr!("{}", $opts.usage(&format!("Usage: {} [-h] [-vq] [-l [LOGFILE]] [-o OUTPUT] INPUT", $prog)));
    }}
}

// Found in:
// http://stackoverflow.com/a/27590832
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    //early init

    // handling commandline parameters
    let args: Vec<String> = env::args().collect();
    let ref program = args[0];
    let mut loggers: Vec<Box<logger::SharedLogger>> = vec![];

    // define options
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "display this help and exit");
    opts.optflagmulti("v", "verbose", "be more verbose. can be used multiple times.");
    opts.optflag("q", "quiet", "be quiet");
    opts.optflagopt("l", "logfile", "specify log file (default zwreec.log)", "LOGFILE");
    opts.optopt("o", "", "name of the output file", "FILE");

    let parsed_opts = match opts.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(f) => {
            // parsing error
            // display usage and return
            print_stderr!("{}\n", f.to_string());
            print_usage!(program, opts);
            // TODO: figure out a way to set exit code
            return;
        }
    };

    // examinate options
    if parsed_opts.opt_present("h") {
        // parsed "-h|--help"
        // display usage and return
        print_usage!(program, opts);
        return;
    }

    if parsed_opts.opt_present("v") {
        // parsed "-v|--verbose"
        // set loglevel to verbose
        loggers.push(logger::TermLogger::new(
                match parsed_opts.opt_count("v") {
                    1 => logger::LogLevelFilter::Info,
                    2 => logger::LogLevelFilter::Debug,
                    _ => logger::LogLevelFilter::Trace,
                }));
    } else if parsed_opts.opt_present("q") {
        // parsed "-q|--quiet"
        // set loglevel to error
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Error));
    } else {
        // default
        // set loglevel to warn
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Warn));
    }

    if parsed_opts.opt_present("l") {
        // parsed "-l|--logfile"
        // sets a logger to output to logfile
        let name = if let Some(n) = parsed_opts.opt_str("l") {
            n
        } else {
            "zwreec.log".to_string()
        };
        loggers.push(logger::FileLogger::new(
                        logger::LogLevelFilter::Trace,
                        File::create(name).unwrap())
            );
    }

    let outfile = if let Some(file) = parsed_opts.opt_str("o") {
        // parsed "-o FILE"
        // set of to filename
        file
    } else {
        // NOTE: string manipulation in rust is stil weird.
        let mut s = String::new();
        s.push_str("a.out");
        s
    };

    let infile = if parsed_opts.free.len() == 1 {
         // check number of 'free' parameter
         // one free parameter is the input file name
         parsed_opts.free[0].clone()
    } else {
        print_stderr!("Input file name missing\n");
        print_usage!(program, opts);
        // TODO: figure out a way to set exit code
        return;
    };

    // activate logger
    // NOTE: I am not sure, if there is a *good* way to do this earlier

    //let _ = SimpleLogger::init(LogLevelFilter::Info);
    let _ = logger::CombinedLogger::init(loggers);

    debug!("parsed command line options");
    info!("main started");
    warn!("WARN");

    // call library
    zwreec::compile(&infile, &outfile);

    // only for testing
    debug!("(1) {}", zwreec::frontend::temp_hello());
    debug!("(2) {}", zwreec::backend::temp_hello());
    debug!("(3) {}", zwreec::file::temp_hello());

    info!("main finished");
}
<|endoftext|>


<commit_before>extern crate bueller;
extern crate mio;

use bueller::protocol::Packet;
use bueller::protocol::Question;
use bueller::protocol::Resource;
use mio::udp::UdpSocket;
use std::io::Read;
use std::io;
use std::net::SocketAddr;
use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::sync::Arc;

const RESPONSE: mio::Token = mio::Token(0);
const QUERY: mio::Token = mio::Token(1);

struct Recurse {
    server: UdpSocket,
    upstream: SocketAddr,
}

impl Recurse {
    fn new(server: UdpSocket) -> Recurse {
        let upstream = "8.8.8.8:53".parse().unwrap();
        Recurse {
            server: server,
            upstream: upstream
        }
    }
}

impl mio::Handler for Recurse {
    type Timeout = ();
    type Message = Vec<u8>;

    fn ready(&mut self, event_loop: &mut mio::EventLoop<Recurse>, token: mio::Token, events: mio::EventSet) {
        println!("ready...");
        match token {
            RESPONSE => {
                if(events.is_readable()) {
                    let mut recv_buf = Vec::with_capacity(1024);
                    match self.server.recv_from(&mut recv_buf) {
                        Ok(addr) => {
                            println!("Got a response from {:?}", addr);
                            println!("{:?}", recv_buf);
                            event_loop.shutdown();
                        }
                        Err(e) => {
                            println!("recv_from() failed: {}", e);
                            event_loop.shutdown();
                        }
                    }
                }
            }
            t => { panic!("Invalid token: {:?}", t); }
        }
    }
}

fn main() {
    println!("Init...");

    let mut event_loop = mio::EventLoop::new().unwrap();

    println!("Binding socket...");
    let address = "0.0.0.0:5300".parse().unwrap();
    let listener = UdpSocket::bound(&address).unwrap();
    event_loop.register(&listener, RESPONSE);

    println!("Sending query ...");
    let mut buffer = Vec::new();
    let num = io::stdin().read_to_end(&mut buffer).ok().unwrap();
    println!("Read {} bytes", num);
    let upstream = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(8,8,8,8), 53));
    listener.send_to(&mut io::Cursor::new(buffer), &upstream);
    let mut server = Recurse::new(listener);
    println!("Running...");
    event_loop.run(&mut server);
}
<commit_msg>Run a query, albeit one externally composed.<commit_after>extern crate bueller;
extern crate mio;

use bueller::protocol::Packet;
use bueller::protocol::Header;
use bueller::protocol::Question;
use bueller::protocol::Resource;
use mio::udp::UdpSocket;
use std::io::Read;
use std::io;
use std::net::SocketAddr;
use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::sync::Arc;

const RESPONSE: mio::Token = mio::Token(0);
const QUERY: mio::Token = mio::Token(1);

struct Recurse {
    server: UdpSocket,
    upstream: SocketAddr,
}

impl Recurse {
    fn new(server: UdpSocket) -> Recurse {
        let upstream = "8.8.8.8:53".parse().unwrap();
        Recurse {
            server: server,
            upstream: upstream
        }
    }
}

impl mio::Handler for Recurse {
    type Timeout = ();
    type Message = Vec<u8>;

    fn ready(&mut self, event_loop: &mut mio::EventLoop<Recurse>, token: mio::Token, events: mio::EventSet) {
        println!("ready...");
        match token {
            RESPONSE => {
                if(events.is_readable()) {
                    let mut recv_buf = Vec::with_capacity(1024);
                    match self.server.recv_from(&mut recv_buf) {
                        Ok(addr) => {
                            println!("Got a response from {:?}", addr);
                            println!("{:?}", recv_buf);
                            let mut packet = Packet::new(&recv_buf[..]);
                            println!("Packet {:?}", packet);
                            let header = packet.next::<Header>();
                            println!("Header {:?}", header);
                            for qdcount in header.qd() {
                                for q in 0..qdcount {
                                    let query = packet.next::<Question>();
                                    println!("Question {}: {:?}", q, query);
                                }
                            }
                            for ancount in header.an() {
                                for a in 0..ancount {
                                    let answer = packet.next::<Resource>();
                                    println!("Answer {}: {:?}", a, answer);
                                }
                            }
                            event_loop.shutdown();
                        }
                        Err(e) => {
                            println!("recv_from() failed: {}", e);
                            event_loop.shutdown();
                        }
                    }
                }
            }
            t => { panic!("Invalid token: {:?}", t); }
        }
    }
}

fn main() {
    println!("Init...");

    let mut event_loop = mio::EventLoop::new().unwrap();

    println!("Binding socket...");
    let address = "0.0.0.0:5300".parse().unwrap();
    let listener = UdpSocket::bound(&address).unwrap();
    event_loop.register(&listener, RESPONSE, mio::EventSet::readable(), mio::PollOpt::level());

    println!("Sending query ...");
    let mut buffer = Vec::new();
    let num = io::stdin().read_to_end(&mut buffer).ok().unwrap();
    println!("Read {} bytes", num);
    let upstream = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(8,8,8,8), 53));
    listener.send_to(&mut io::Cursor::new(buffer), &upstream);
    let mut server = Recurse::new(listener);
    println!("Running...");
    event_loop.run(&mut server);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate clap;

extern crate qrcode;
extern crate termion;
extern crate image;
extern crate regex;

use clap::{App, Arg, SubCommand, AppSettings};
use qrcode::{QrCode, EcLevel};
use termion::color;

mod payloads;

const WIFI_COMMAND: &'static str = "wifi";
const MAIL_COMMAND: &'static str = "mail";
// const SMS_COMMAND: &'static str = "sms";
// const MMS_COMMAND: &'static str = "mms";
// const GEO_COMMAND: &'static str = "geo";
const PHONE_COMMAND: &'static str = "phone";
// const SKYPE_COMMAND: &'static str = "skype";
const URL_COMMAND: &'static str = "url";
// const BOOKMARK_COMMAND: &'static str = "bookmark";
// const BITCOIN_COMMAND: &'static str = "bitcoin";
// const GIRO_COMMAND: &'static str = "giro";
// const CALENDAR_COMMAND: &'static str = "calendar";

/*TODO: add arguments for:
- ec Level
- size of qr code
- implement different types of qr payloads
*/
fn main() {
        .arg(Arg::with_name("safe_zone") //TODO: change this into an off switch
    let app = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .global_setting(AppSettings::SubcommandsNegateReqs)
            .global(true)
            .required(false)
            .short("s")
            .long("safe-zone")
            .help("Sets wether the safe zone around the code should be drawn or not.")
            .takes_value(false)
            )
            //TODO: subcmds are not working like expected, if you have one the system assumes you have many
        .arg(Arg::with_name("error")
            .global(true)
            .short("e").long("error")
            .help("Set the desired error correction level")
            .takes_value(true)
            .value_name("LEVEL")
            .possible_values(&["L", "M", "Q", "H"])
            .default_value("H"))
        .arg(Arg::with_name("INPUT")
            .help("The input string to use")
            .required(true))
        .subcommand(SubCommand::with_name(WIFI_COMMAND)
            .about("formats to a wifi access string")
            .arg(Arg::with_name("ssid").required(true))
            .arg(Arg::with_name("pwd").required(true))
            .arg(Arg::with_name("mode")
                .possible_values(&["WEP", "WPA", "nopass"])
                .default_value("WPA")
                .value_name("MODE"))
            .arg(Arg::with_name("hidden")
                .required(false)
                .possible_values(&["true", "false"])
                .default_value("false")
                .value_name("HIDDEN")))
        .subcommand(SubCommand::with_name(MAIL_COMMAND)
            .about("formats to a mail adress string")
            .arg(Arg::with_name("receiver").required(true))
            .arg(Arg::with_name("subject"))
            .arg(Arg::with_name("message"))
            .arg(Arg::with_name("encoding")
                .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                .default_value("MAILTO")
                .value_name("ENCODING")))
        .subcommand(SubCommand::with_name(URL_COMMAND)
            .about("formats to an URL")
            .arg(Arg::with_name("url")
                .required(true)
                .value_name("URL")))
        .subcommand(SubCommand::with_name(PHONE_COMMAND)
            .about("formats to a phone number")
            .arg(Arg::with_name("number")
                .required(true)
                .value_name("NUMBER"))
        );

    let matches = app.get_matches();

    // deduce the string payload
    let payload = get_payload(&matches);
    // what error level can we expect? always defaults to "H"
    let error: EcLevel = match matches.value_of("error").unwrap() {
        "L" => EcLevel::L,
        "M" => EcLevel::M,
        "Q" => EcLevel::Q,
        &_ => EcLevel::H,
    };
    let code = QrCode::with_error_correction_level(payload, error).unwrap();
// deduces wich kind of string we are going to encode
fn get_payload(matches: &clap::ArgMatches) -> String {
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        return payloads::wifi_string(sub.value_of("ssid").unwrap(),
                                     sub.value_of("pwd").unwrap(),
                                     &auth,
                                     sub.value_of("hidden").unwrap() == "true");
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        return payloads::mail_string(sub.value_of("receiver").unwrap(),
                                     sub.value_of("subject").unwrap(),
                                     sub.value_of("message").unwrap(),
                                     &encoding);
    } else if let Some(sub) = matches.subcommand_matches(URL_COMMAND) {
        return payloads::url_string(sub.value_of("url").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(PHONE_COMMAND) {
        return payloads::phone_string(sub.value_of("phone").unwrap());
    } else {
        return String::from(matches.value_of("INPUT").unwrap());
    }
}

    let safe: bool = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };

    let bit_array = code.to_colors();

    let w = code.width();
    let wide = w + 6;

    //Draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    for (i, item) in bit_array.iter().enumerate() {
        //left safe zone
        if safe && i % w == 0 {
            print!("{}      ", color::Bg(color::LightWhite));
        }

        if *item == qrcode::types::Color::Dark {
            print!("{}  ", color::Bg(color::Black));
        } else {
            print!("{}  ", color::Bg(color::LightWhite));
        }

        if (i + 1) % w == 0 {
            if safe {
                //draw right safe zone
                println!("{}      {}",
                         color::Bg(color::LightWhite),
                         color::Bg(color::Reset));
            } else {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    //Draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }
}
<commit_msg>added saving to a file and refactored methods a bit<commit_after>#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate clap;

extern crate qrcode;
extern crate termion;
extern crate image;
extern crate regex;

use clap::{App, Arg, SubCommand, AppSettings};
use qrcode::{QrCode, EcLevel};
use termion::color;
use image::GrayImage;

mod payloads;

const WIFI_COMMAND: &'static str = "wifi";
const MAIL_COMMAND: &'static str = "mail";
// const SMS_COMMAND: &'static str = "sms";
// const MMS_COMMAND: &'static str = "mms";
// const GEO_COMMAND: &'static str = "geo";
const PHONE_COMMAND: &'static str = "phone";
// const SKYPE_COMMAND: &'static str = "skype";
const URL_COMMAND: &'static str = "url";
// const BOOKMARK_COMMAND: &'static str = "bookmark";
// const BITCOIN_COMMAND: &'static str = "bitcoin";
// const GIRO_COMMAND: &'static str = "giro";
// const CALENDAR_COMMAND: &'static str = "calendar";

/*TODO: add arguments for:
- ec Level
- size of qr code
- implement different types of qr payloads
*/
fn main() {
        .arg(Arg::with_name("safe_zone") //TODO: change this into an off switch
    let app = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .global_setting(AppSettings::SubcommandsNegateReqs)
            .global(true)
            .required(false)
            .short("s")
            .long("safe-zone")
            .help("Sets wether the safe zone around the code should be drawn or not.")
            .takes_value(false)
            )
            //TODO: subcmds are not working like expected, if you have one the system assumes you have many
        .arg(Arg::with_name("output")
            .global(true)
            .short("o").long("output")
            .help("Prints the QR-Code to a file. The image format is derived from the file extension. Currently only jpeg and png files are supported.")
            .takes_value(true)
            .value_name("FILE")
            .multiple(false))
        .arg(Arg::with_name("error")
            .global(true)
            .short("e").long("error")
            .help("Set the desired error correction level")
            .takes_value(true)
            .value_name("LEVEL")
            .possible_values(&["L", "M", "Q", "H"])
            .default_value("H"))
        .arg(Arg::with_name("INPUT")
            .help("The input string to use")
            .required(true))
        .subcommand(SubCommand::with_name(WIFI_COMMAND)
            .about("formats to a wifi access string")
            .arg(Arg::with_name("ssid").required(true))
            .arg(Arg::with_name("pwd").required(true))
            .arg(Arg::with_name("mode")
                .possible_values(&["WEP", "WPA", "nopass"])
                .default_value("WPA")
                .value_name("MODE"))
            .arg(Arg::with_name("hidden")
                .required(false)
                .possible_values(&["true", "false"])
                .default_value("false")
                .value_name("HIDDEN")))
        .subcommand(SubCommand::with_name(MAIL_COMMAND)
            .about("formats to a mail adress string")
            .arg(Arg::with_name("receiver").required(true))
            .arg(Arg::with_name("subject"))
            .arg(Arg::with_name("message"))
            .arg(Arg::with_name("encoding")
                .possible_values(&["MAILTO", "MATMSG", "SMTP"])
                .default_value("MAILTO")
                .value_name("ENCODING")))
        .subcommand(SubCommand::with_name(URL_COMMAND)
            .about("formats to an URL")
            .arg(Arg::with_name("url")
                .required(true)
                .value_name("URL")))
        .subcommand(SubCommand::with_name(PHONE_COMMAND)
            .about("formats to a phone number")
            .arg(Arg::with_name("number")
                .required(true)
                .value_name("NUMBER"))
        );

    let matches = app.get_matches();

    // deduce the string payload
    let payload = get_payload(&matches);
    // what error level can we expect? always defaults to "H"
    let error: EcLevel = match matches.value_of("error").unwrap() {
        "L" => EcLevel::L,
        "M" => EcLevel::M,
        "Q" => EcLevel::Q,
        &_ => EcLevel::H,
    };
    let code = QrCode::with_error_correction_level(payload, error).unwrap();

    // are we drawing to the terminal or to a file?
    match matches.occurrences_of("output") {
        1 => save(&code, safe, matches.value_of("output").unwrap()),
        _ => draw(&code, safe),
    }
}

// deduces wich kind of string we are going to encode
fn get_payload(matches: &clap::ArgMatches) -> String {
    if let Some(sub) = matches.subcommand_matches(WIFI_COMMAND) {
        let auth = match sub.value_of("mode") {
            Some("WEP") => payloads::Authentication::WEP,
            Some("WPA") => payloads::Authentication::WPA,
            _ => payloads::Authentication::nopass,
        };
        return payloads::wifi_string(sub.value_of("ssid").unwrap(),
                                     sub.value_of("pwd").unwrap(),
                                     &auth,
                                     sub.value_of("hidden").unwrap() == "true");
    } else if let Some(sub) = matches.subcommand_matches(MAIL_COMMAND) {
        let encoding = match sub.value_of("encoding") {
            Some("MATMSG") => payloads::MailEncoding::MATMSG,
            Some("SMTP") => payloads::MailEncoding::SMTP,
            _ => payloads::MailEncoding::MAILTO,
        };
        return payloads::mail_string(sub.value_of("receiver").unwrap(),
                                     sub.value_of("subject").unwrap(),
                                     sub.value_of("message").unwrap(),
                                     &encoding);
    } else if let Some(sub) = matches.subcommand_matches(URL_COMMAND) {
        return payloads::url_string(sub.value_of("url").unwrap());
    } else if let Some(sub) = matches.subcommand_matches(PHONE_COMMAND) {
        return payloads::phone_string(sub.value_of("phone").unwrap());
    } else {
        return String::from(matches.value_of("INPUT").unwrap());
    }
}

    let safe: bool = match matches.occurrences_of("safe_zone") {
        0 => true,
        _ => false,
    };
// save to a file at the path
fn save(code: &QrCode, safe: bool, path: &str) {
    // render to a image struct
    let image: GrayImage = code.render().quiet_zone(safe).to_image();

    // save the image
    match image.save(path) {
        Ok(..) => println!("Image successfully saved to: {:?}", path),
        Err(e) => println!("Tried to create file but there was a problem: {:?}",
            if let Some(inner_err) = e.get_ref() { inner_err.to_string() } else { e.to_string() }),
    };
}

// draw to the terminal
fn draw(code: &QrCode, safe: bool) {
    // get "bit" array
    let bit_array = code.to_vec();

    let w = code.width();
    let wide = w + 6;

    //Draw the first white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    for (i, item) in bit_array.iter().enumerate() {
        //left safe zone
        if safe && i % w == 0 {
            print!("{}      ", color::Bg(color::LightWhite));
        }

        if *item == qrcode::types::Color::Dark {
            print!("{}  ", color::Bg(color::Black));
        } else {
            print!("{}  ", color::Bg(color::LightWhite));
        }

        if (i + 1) % w == 0 {
            if safe {
                //draw right safe zone
                println!("{}      {}",
                         color::Bg(color::LightWhite),
                         color::Bg(color::Reset));
            } else {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }

    //Draw the last white safe zone
    if safe {
        for a in 1..(wide * 3) + 1 {
            print!("{}  ", color::Bg(color::LightWhite));
            if a % wide == 0 {
                println!("{}", color::Bg(color::Reset));
            }
        }
    }
}
<|endoftext|>


<commit_before>#![warn(clippy::all)]

#[macro_use]
extern crate serenity;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::io::Read;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "]";
#[allow(clippy::unreadable_literal)]
const WESTMANN: UserId = UserId(229154015626264577);
#[allow(clippy::unreadable_literal)]
const FALCH: UserId = UserId(165877785544491008);
#[allow(clippy::unreadable_literal)]
const MEMES: ChannelId = ChannelId(306454829738491904);
#[allow(clippy::unreadable_literal)]
const FALCHATS: GuildId = GuildId(189120762659995648);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("falchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2018")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, msg, args) {
    if msg.author.id == FALCH {
        ctx.set_game(Game::playing(&args.join(" ")));
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(seticon(_ctx, msg, args) {
    let s = args.join("/");

    if msg.author.id == FALCH {
        let img = {
            let client = hyper::Client::new();
            let mut resp = client.get(&format!("http://dev.lfalch.com/{}.png", s)).send()?;
            if !resp.status.is_success() {
                msg.reply("No success")?;
                return Ok(());
            }

            let mut v = Vec::new();

            resp.read_to_end(&mut v)?;

            let b64 = base64::encode(&v);
            let ext = "png";

            format!("data:image/{};base64,{}", ext, b64)
        };

        FALCHATS.edit(|e| e.icon(Some(&img)))?;
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(&(args.join(" ") + "\n")) {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(pdgqz(ctx, msg, _args) {
    let mut pdqz = ctx.data.lock();
    let pdqz = pdqz.get_mut::<PdgqzDisalloweds>().unwrap();

    if let Some(i) = pdqz.iter().position(|ch| ch == &msg.channel_id) {
        pdqz.remove(i);
    } else {
        pdqz.push(msg.channel_id);
    }
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }?;
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct PdgqzDisalloweds;

impl Key for PdgqzDisalloweds {
    type Value = Vec<ChannelId>;
}

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

#[derive(Default)]
struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler::default());

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("pdgqz", pdgqz)
        .on("seximal", seximal)
        .on("seticon", seticon)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
        data.insert::<PdgqzDisalloweds>(Vec::new());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        {
            if ctx.data.lock().get::<PdgqzDisalloweds>().unwrap().contains(&msg.channel_id) {
                let filter = |c: char| {
                    let c = c.to_lowercase().next().unwrap();
                     c == 'p' || c == 'd' || c == 'g' || c == 'q' || c == 'z'
                };
                if msg.content.chars().any(filter) {
                    let s = msg.content.chars().filter(|c| !filter(*c)).collect::<String>();
                    if !s.is_empty() {
                        msg.channel_id.say(s).unwrap();
                    }
                }
            }
        }
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "wt", "thunder", "tankspil";; "Jeg hader World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use crate::RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Ok(d) = operation.parse::<f64>() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    stack.push(res);
    Ok(())
}

fn stalch_run(s: &str) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<commit_msg>Fix wt-joke<commit_after>#![warn(clippy::all)]

#[macro_use]
extern crate serenity;

use std::io;
use stalch::{run_with_state, InOuter, State, Result as StalchResult};

use std::env;
use std::io::Read;
use std::result::Result as StdResult;
use typemap::Key;

use rand::Rng;
use rand::thread_rng;

use serenity::prelude::*;
use serenity::model::*;
use serenity::Result;
use serenity::utils;

use serenity::framework::StandardFramework;

const PREFIX: &str = "]";
#[allow(clippy::unreadable_literal)]
const WESTMANN: UserId = UserId(229154015626264577);
#[allow(clippy::unreadable_literal)]
const FALCH: UserId = UserId(165877785544491008);
#[allow(clippy::unreadable_literal)]
const MEMES: ChannelId = ChannelId(306454829738491904);
#[allow(clippy::unreadable_literal)]
const FALCHATS: GuildId = GuildId(189120762659995648);

command!(info(_ctx, msg, _args) {
    msg.channel_id.send_message(|cm| {
        cm.embed(|e| {
            e.title("falchbot")
             .colour(utils::Colour::blue())
             .description("(c) LFalch.com 2018")
             .footer(|f| f.text(serenity::constants::USER_AGENT))
        })
    }).unwrap();
});

command!(setgame(ctx, msg, args) {
    if msg.author.id == FALCH {
        ctx.set_game(Game::playing(&args.join(" ")));
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(seticon(_ctx, msg, args) {
    let s = args.join("/");

    if msg.author.id == FALCH {
        let img = {
            let client = hyper::Client::new();
            let mut resp = client.get(&format!("http://dev.lfalch.com/{}.png", s)).send()?;
            if !resp.status.is_success() {
                msg.reply("No success")?;
                return Ok(());
            }

            let mut v = Vec::new();

            resp.read_to_end(&mut v)?;

            let b64 = base64::encode(&v);
            let ext = "png";

            format!("data:image/{};base64,{}", ext, b64)
        };

        FALCHATS.edit(|e| e.icon(Some(&img)))?;
    } else {
        msg.reply("Unauthorised")?;
    }
});

command!(rpn(_ctx, msg, args) {
    match calculate(&*args) {
        Ok(r) => msg.reply(&format!("Result: {}", r)),
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(stalch(_ctx, msg, args) {
    match stalch_run(&(args.join(" ") + "\n")) {
        Ok((r, s)) => {
            if r.is_empty() {
                msg.reply(&format!("Stack:\n```\n{}\n```", s))
            } else {
                msg.reply(&format!("Output:\n```\n{}\n```", r))
            }
        }
        Err(e) => msg.reply(&format!("Error: {:?}", e))
    }?;
});

command!(pdgqz(ctx, msg, _args) {
    let mut pdqz = ctx.data.lock();
    let pdqz = pdqz.get_mut::<PdgqzDisalloweds>().unwrap();

    if let Some(i) = pdqz.iter().position(|ch| ch == &msg.channel_id) {
        pdqz.remove(i);
    } else {
        pdqz.push(msg.channel_id);
    }
});

command!(seximal(_ctx, msg, args) {
    let s = args.join("");
    match seximal::to_seximal_words(&s) {
        Ok(ref s) => msg.reply(s),
        Err(_) => msg.reply("Malformed number")
    }?;
});

const CSGO_MSGS: [&str; 6] = [
    "Vi varmer op med en comp!",
    "Jeg er på!",
    "Jeg er mere til Call of Duty ..",
    "Сука блядь!",
    "-skyder en bot for at få dens Bizon-",
    "Mongoskrald!"
];

const BEARTOOTH: [&str; 3] = [
    "I’m not useless! I’m just the king of excuses!",
    "One life and one decision! Make sure it ends with you still living!",
    "Lorteskat på T-shirts."
];

const RESPONSES: [&str; 4] = [
    "Undskyld, kan ikke snakke lige nu :(",
    "Hey, kan jeg ringe igen senere?",
    "Hva' så, din noob!? :P",
    "Ad, hvem er du?"
];

const REDALERT: [&str; 4] = [
    "Your base is under a salt!",
    "Det gamle lortespil?",
    "Jeg er mere til CSGO.",
    "\"Mine depleted\" ..."
];

struct PdgqzDisalloweds;

impl Key for PdgqzDisalloweds {
    type Value = Vec<ChannelId>;
}

struct BotUser;

impl Key for BotUser {
    type Value = String;
}

#[derive(Default)]
struct Handler;

fn main() {
    println!("{} in {}", WESTMANN, MEMES);

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");
    let mut client = Client::new(&token, Handler::default());

    client.with_framework(StandardFramework::new()
        .configure(|c| c.prefix(PREFIX))
        .command("ping", |c| c.exec_str("Pong!"))
        .on("info", info)
        .on("setgame", setgame)
        .on("rpn", rpn)
        .on("stalch", stalch)
        .on("pdgqz", pdgqz)
        .on("seximal", seximal)
        .on("seticon", seticon)
    );

    {
        let mut data = client.data.lock();
        data.insert::<BotUser>(String::default());
        data.insert::<PdgqzDisalloweds>(Vec::new());
    }

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

macro_rules! joke {
    ($s:expr; $($trigger:expr),+; $bl:block) => (
        if $($s.contains($trigger))||* $bl
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+;; $joke:expr) => (
        joke!($s; $($trigger),*; {
            $channel_id.say($joke).unwrap();
        })
    );
    ($s:expr, $channel_id:expr; $($trigger:expr),+; $jokes:expr) => (
        joke!($s; $($trigger),*; {
            send_random($channel_id, &$jokes).unwrap();
        })
    );
}

impl EventHandler for Handler {
    fn on_ready(&self, ctx: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
        println!("Guilds:");
        for name in ready.guilds.iter().map(|g| g.id().get().unwrap().name) {
            println!("    {}", name);
        }
        {
            let mut data = ctx.data.lock();
            *data.get_mut::<BotUser>().unwrap() = ready.user.tag();
        }
    }

    fn on_message(&self, ctx: Context, msg: Message) {
        if msg.author.bot {
            return
        }
        {
            if ctx.data.lock().get::<PdgqzDisalloweds>().unwrap().contains(&msg.channel_id) {
                let filter = |c: char| {
                    let c = c.to_lowercase().next().unwrap();
                     c == 'p' || c == 'd' || c == 'g' || c == 'q' || c == 'z'
                };
                if msg.content.chars().any(filter) {
                    let s = msg.content.chars().filter(|c| !filter(*c)).collect::<String>();
                    if !s.is_empty() {
                        msg.channel_id.say(s).unwrap();
                    }
                }
            }
        }
        if msg.channel_id == MEMES && msg.author.id == WESTMANN && msg.attachments.iter().any(|a| a.width.is_some()) {
            msg.channel_id.say("Den er gammel!").unwrap();
        }
        let s: String = msg.content.chars()
        .filter(|c| c.is_alphanumeric())
        .flat_map(|c|c.to_lowercase())
        .collect();

        joke!(s, msg.channel_id; "css", "source";; "Hvor er mine skins!?");
        joke!(s, msg.channel_id; "csgo", "counterstrike", "globaloffensive"; CSGO_MSGS);
        joke!(s, msg.channel_id; "mc", "minecraft";; "MINECRAFT!");
        joke!(s, msg.channel_id; "beartooth"; BEARTOOTH);
        joke!(s, msg.channel_id; "rep";; "Rep mig!");
        joke!(s, msg.channel_id; "ftl";; "Zoltan shield OP");
        joke!(s, msg.channel_id; "bindingofisaac";; "Mom OP");
        joke!(s, msg.channel_id; "meme";; "krydrede migmig'er");
        joke!(s, msg.channel_id; "gunsoficarus";; "Spillere online: 85");
        joke!(s, msg.channel_id; "doom";; "Rip and tear!");
        joke!(s, msg.channel_id; "dyinglight";; "Det dér Left 4 Dead-spil?");
        joke!(s, msg.channel_id; "report";; "ReviewBrah");
        joke!(s; "english"; {
            msg.channel_id.send_message(|cm| {
                cm.embed(|e| {
                    e.image("http://dev.lfalch.com/english.jpg")
                })
            }).unwrap();
        });
        joke!(s, msg.channel_id; "warthunder", "thunder", "tankspil";; "Jeg elsker World of Tanks!");
        joke!(s, msg.channel_id; "ra3", "redalert"; REDALERT);
        joke!(s, msg.channel_id; "rusland", "russia", "росси", "russisk",
        "russian", "русск", "russer";; "Communism is the ultimate goal of socialism.");

        let user = {
            ctx.data.lock().get::<BotUser>().unwrap().clone()
        };
        if msg.mentions.iter().map(|u| u.tag()).any(|u| u == user) {
            send_random(msg.channel_id, &RESPONSES).unwrap();
        }
    }
}

fn send_random(chl: ChannelId, list: &[&str]) -> Result<Message> {
    let i = thread_rng().gen_range(0, list.len());
    chl.say(list[i])
}

#[derive(Debug, Copy, Clone)]
pub enum RpnError<'a> {
    StackTooSmall,
    UnknownOperator(&'a str)
}

use crate::RpnError::*;

pub fn calculate<'a, T: IntoIterator<Item=&'a String>>(operations: T) -> StdResult<f64, RpnError<'a>> {
    let mut stack = Vec::new();

    for operation in operations {
        if let Ok(d) = operation.parse::<f64>() {
            stack.push(d)
        }else{
            calc(operation, &mut stack)?
        }
    }

    stack.pop().ok_or(StackTooSmall)
}

fn calc<'a>(op: &'a str, stack: &mut Vec<f64>) -> StdResult<(), RpnError<'a>>{
    let res = match (stack.pop(), stack.pop()){
        (Some(op1), Some(op2)) => match op{
            "+"|"add" => op2 + op1,
            "-"|"sub" => op2 - op1,
            "/"|"div" => op2 / op1,
            "*"|"mul" => op2 * op1,
            "^"|"pow" => op2.powf(op1),
            "log" => op2.log(op1),
            "hypot" => op2.hypot(op1),
            "%"|"rem" => op2 % op1,
            "|"|"or" => (op2 as i64 | op1 as i64) as f64,
            "&"|"and" => (op2 as i64 & op1 as i64) as f64,
            "xor" => (op2  as i64 ^ op1 as i64) as f64,
            _ => return Err(UnknownOperator(op))
        },
        _ => return Err(StackTooSmall)
    };
    stack.push(res);
    Ok(())
}

fn stalch_run(s: &str) -> StalchResult<(String, String)> {
    let mut state = State::new();
    let mut io = InOuter::new(Vec::new(), io::repeat(b'\n'));

    run_with_state(s.as_bytes(), &mut state, &mut io)?;

    let (output, _) = io.extract();

    let s = String::from_utf8(output).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    Ok((s, format!("{:?}", state.stack())))
}
<|endoftext|>