<commit_before>extern crate gl;
extern crate glfw;
extern crate imagefmt;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;
    in vec2 texcoord;

    out vec3 Color;
    out vec2 Texcoord;

    void main() {
        Color = color;
        Texcoord = texcoord;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;
    in vec2 Texcoord;

    out vec4 out_color;

    uniform sampler2D texKitten;
    uniform sampler2D texPuppy;
    uniform float time;

    void main() {
        float mix_factor = (sin(time * 3.0) + 1.0) / 2.0;
        vec4 colKitten = texture(texKitten, Texcoord);
        vec4 colPuppy = texture(texPuppy, Texcoord);
        out_color = mix(colKitten, colPuppy, mix_factor);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,

    // Texture.
    s: GLfloat, t: GLfloat,
}

static VERTICES: [Vertex; 4] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0, s: 0.0, t: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0, s: 1.0, t: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0, s: 1.0, t: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0, s: 0.0, t: 1.0 }, // Bottom-left
];

static ELEMENTS: [GLuint; 6] = [
    0, 1, 2, // Top-right triangle
    2, 3, 0, // Bottom-left triangle
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

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

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

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

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;
    let mut textures = [0; 2];

    unsafe {
        // Create a 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);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Create an element buffer object and copy the element data to it.
        gl::GenBuffers(1, &mut ebo);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                       mem::size_of_val(&ELEMENTS) as GLsizeiptr,
                       ELEMENTS.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint, ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (2 * mem::size_of::<GLfloat>()) as *const GLvoid);

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("texcoord"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (5 * mem::size_of::<GLfloat>()) as *const GLvoid);

        // Create and load textures.
        gl::GenTextures(2, textures.as_mut_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, textures[0]);
        let image = imagefmt::read("sample.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("texKitten")), 0);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);

        gl::ActiveTexture(gl::TEXTURE1);
        gl::BindTexture(gl::TEXTURE_2D, textures[1]);
        let image = imagefmt::read("sample2.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("texPuppy")), 1);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
    }

    let time_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("time")) };
    let time_start = time::precise_time_ns();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Update the `time` uniform.
            let time_now = time::precise_time_ns();
            let elapsed_seconds = (time_now - time_start) as f32 / 1e9;
            gl::Uniform1f(time_uniform, elapsed_seconds);

            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw the triangles described by the elements array.
            gl::DrawElements(gl::TRIANGLES, ELEMENTS.len() as GLint, gl::UNSIGNED_INT,
                             ptr::null());
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteTextures(2, textures.as_ptr());
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &ebo);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Add Vec4 and Mat4.<commit_after>extern crate gl;
extern crate glfw;
extern crate imagefmt;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;
use std::ptr;

#[derive(Copy, Clone, Debug, PartialEq)]
struct Vec4 {
    data: [GLfloat; 4]
}

impl Vec4 {
    fn zero() -> Self {
        Vec4 { data: [0.0, 0.0, 0.0, 0.0] }
    }

    fn x(&self) -> GLfloat { self.data[0] }
    fn y(&self) -> GLfloat { self.data[1] }
    fn z(&self) -> GLfloat { self.data[2] }
    fn w(&self) -> GLfloat { self.data[3] }
}

impl std::ops::Index<usize> for Vec4 {
    type Output = GLfloat;

    fn index(&self, i: usize) -> &GLfloat {
        &self.data[i]
    }
}

impl std::ops::IndexMut<usize> for Vec4 {
    fn index_mut(&mut self, i: usize) -> &mut GLfloat {
        &mut self.data[i]
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
struct Mat4 {
    data: [[GLfloat; 4]; 4]
}

impl Mat4 {
    fn zero() -> Self {
        Mat4 {
            data: [
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
                [0.0, 0.0, 0.0, 0.0],
            ]
        }
    }

    fn identity() -> Self {
        Mat4 {
            data: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    fn scale(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4 {
            data: [
                [x,   0.0, 0.0, 0.0],
                [0.0, y,   0.0, 0.0],
                [0.0, 0.0, z,   0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    fn translate(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4 {
            data: [
                [1.0, 0.0, 0.0, x  ],
                [0.0, 1.0, 0.0, y  ],
                [0.0, 0.0, 1.0, z  ],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    /// A matrix representing a rotation around the X-axis by the given angle (in radians).
    fn rotate_x(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4 {
            data: [
                [1.0, 0.0,  0.0, 0.0],
                [0.0, cos, -sin, 0.0],
                [0.0, sin,  cos, 0.0],
                [0.0, 0.0,  0.0, 1.0],
            ]
        }
    }

    /// A matrix representing a rotation around the Y-axis by the given angle (in radians).
    fn rotate_y(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4 {
            data: [
                [ cos, 0.0, sin, 0.0],
                [ 0.0, 1.0, 0.0, 0.0],
                [-sin, 0.0, cos, 0.0],
                [ 0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    /// A matrix representing a rotation around the Z-axis by the given angle (in radians).
    fn rotate_z(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4 {
            data: [
                [cos, -sin, 0.0, 0.0],
                [sin,  cos, 0.0, 0.0],
                [0.0,  0.0, 1.0, 0.0],
                [0.0,  0.0, 0.0, 1.0],
            ]
        }
    }
}

impl std::ops::Index<usize> for Mat4 {
    type Output = [GLfloat; 4];

    fn index(&self, i: usize) -> &[GLfloat; 4] {
        &self.data[i]
    }
}

impl std::ops::IndexMut<usize> for Mat4 {
    fn index_mut(&mut self, i: usize) -> &mut [GLfloat; 4] {
        &mut self.data[i]
    }
}

impl std::ops::Mul<Mat4> for Mat4 {
    type Output = Mat4;

    fn mul(self, other: Mat4) -> Mat4 {
        let mut result = Mat4::zero();

        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[i][k] * other[k][j];
                }
            }
        }

        result
    }
}

impl std::ops::Mul<Vec4> for Mat4 {
    type Output = Vec4;

    fn mul(self, vec: Vec4) -> Vec4 {
        let mut result = Vec4::zero();

        for i in 0..4 {
            for j in 0..4 {
                result[i] += self[i][j] * vec[j];
            }
        }

        result
    }
}

#[test]
fn test_math() {
    let scale = Mat4::scale(2.0, 2.0, 2.0);
    let trans = Mat4::translate(1.0, 2.0, 3.0);
    let combined = trans * scale;

    let orig = Vec4 { data: [3.0, 3.0, 3.0, 1.0] };
    let expected = Vec4 { data: [7.0, 8.0, 9.0, 1.0] };

    println!("{:?}", combined);
    assert_eq!(expected, combined * orig);
}

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;
    in vec2 texcoord;

    out vec3 Color;
    out vec2 Texcoord;

    void main() {
        Color = color;
        Texcoord = texcoord;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;
    in vec2 Texcoord;

    out vec4 out_color;

    uniform sampler2D texKitten;
    uniform sampler2D texPuppy;
    uniform float time;

    void main() {
        float mix_factor = (sin(time * 3.0) + 1.0) / 2.0;
        vec4 colKitten = texture(texKitten, Texcoord);
        vec4 colPuppy = texture(texPuppy, Texcoord);
        out_color = mix(colKitten, colPuppy, mix_factor);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,

    // Texture.
    s: GLfloat, t: GLfloat,
}

static VERTICES: [Vertex; 4] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0, s: 0.0, t: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0, s: 1.0, t: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0, s: 1.0, t: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0, s: 0.0, t: 1.0 }, // Bottom-left
];

static ELEMENTS: [GLuint; 6] = [
    0, 1, 2, // Top-right triangle
    2, 3, 0, // Bottom-left triangle
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

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

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

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

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;
    let mut ebo = 0;
    let mut textures = [0; 2];

    unsafe {
        // Create a 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);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Create an element buffer object and copy the element data to it.
        gl::GenBuffers(1, &mut ebo);
        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo);
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
                       mem::size_of_val(&ELEMENTS) as GLsizeiptr,
                       ELEMENTS.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint, ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (2 * mem::size_of::<GLfloat>()) as *const GLvoid);

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("texcoord"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                mem::size_of::<Vertex>() as GLint,
                                (5 * mem::size_of::<GLfloat>()) as *const GLvoid);

        // Create and load textures.
        gl::GenTextures(2, textures.as_mut_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        gl::BindTexture(gl::TEXTURE_2D, textures[0]);
        let image = imagefmt::read("sample.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("texKitten")), 0);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);

        gl::ActiveTexture(gl::TEXTURE1);
        gl::BindTexture(gl::TEXTURE_2D, textures[1]);
        let image = imagefmt::read("sample2.png", imagefmt::ColFmt::RGB).unwrap();
        gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, image.w as GLint, image.h as GLint,
                       0, gl::RGB, gl::UNSIGNED_BYTE, image.buf.as_ptr() as *const GLvoid);
        gl::Uniform1i(gl::GetUniformLocation(shader_program, gl_str!("texPuppy")), 1);

        gl::GenerateMipmap(gl::TEXTURE_2D);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
        gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER,
                          gl::LINEAR_MIPMAP_LINEAR as GLint);
    }

    let time_uniform = unsafe { gl::GetUniformLocation(shader_program, gl_str!("time")) };
    let time_start = time::precise_time_ns();

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Update the `time` uniform.
            let time_now = time::precise_time_ns();
            let elapsed_seconds = (time_now - time_start) as f32 / 1e9;
            gl::Uniform1f(time_uniform, elapsed_seconds);

            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw the triangles described by the elements array.
            gl::DrawElements(gl::TRIANGLES, ELEMENTS.len() as GLint, gl::UNSIGNED_INT,
                             ptr::null());
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteTextures(2, textures.as_ptr());
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &ebo);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>


<commit_before>#[crate_id(name="users", vers="1.0.0", author="KokaKiwi")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) KokaKiwi <kokakiwi@kokakiwi.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: whoami (GNU coreutils) 8.22 */

// Allow dead code here in order to keep all fields, constants here, for consistency.
#[allow(dead_code)];

extern mod extra;

use std::io::print;
use std::cast;
use std::libc;
use std::os;
use std::ptr;
use std::str;
use extra::getopts::groups;

static DEFAULT_FILE: &'static str = "/var/run/utmp";

static UT_LINESIZE: uint = 32;
static UT_NAMESIZE: uint = 32;
static UT_HOSTSIZE: uint = 256;

static EMPTY: libc::c_short = 0;
static RUN_LVL: libc::c_short = 1;
static BOOT_TIME: libc::c_short = 2;
static NEW_TIME: libc::c_short = 3;
static OLD_TIME: libc::c_short = 4;
static INIT_PROCESS: libc::c_short = 5;
static LOGIN_PROCESS: libc::c_short = 6;
static USER_PROCESS: libc::c_short = 7;
static DEAD_PROCESS: libc::c_short = 8;
static ACCOUNTING: libc::c_short = 9;

struct c_exit_status {
    e_termination: libc::c_short,
    e_exit: libc::c_short,
}

struct c_utmp {
    ut_type: libc::c_short,
    ut_pid: libc::pid_t,
    ut_line: [libc::c_char, ..UT_LINESIZE],
    ut_id: [libc::c_char, ..4],

    ut_user: [libc::c_char, ..UT_NAMESIZE],
    ut_host: [libc::c_char, ..UT_HOSTSIZE],
    ut_exit: c_exit_status,
    ut_session: libc::c_long,
    ut_tv: libc::timeval,

    ut_addr_v6: [libc::int32_t, ..4],
    __unused: [libc::c_char, ..20],
}

extern {
    fn getutent() -> *c_utmp;
    fn getutid(ut: *c_utmp) -> *c_utmp;
    fn getutline(ut: *c_utmp) -> *c_utmp;

    fn pututline(ut: *c_utmp) -> *c_utmp;

    fn setutent();
    fn endutent();

    fn utmpname(file: *libc::c_char) -> libc::c_int;
}

fn main() {
    let args = os::args();
    let program = args[0].as_slice();
    let opts = ~[
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_err_msg()),
    };

    if matches.opt_present("help") {
        println!("users 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {:s} [OPTION]... [FILE]", program);
        println!("");
        print(groups::usage("Output who is currently logged in according to FILE.", opts));
        return;
    }

    if matches.opt_present("version") {
        println!("users 1.0.0");
        return;
    }

    let mut filename = DEFAULT_FILE;
    if matches.free.len() > 0 {
        filename = matches.free[0].as_slice();
    }

    exec(filename);
}

fn exec(filename: &str) {
    filename.with_c_str(|filename| {
        unsafe {
            utmpname(filename);
        }
    });

    let mut users: ~[~str] = ~[];

    unsafe {
        setutent();

        loop {
            let line = getutent();

            if line == ptr::null() {
                break;
            }

            if (*line).ut_type == USER_PROCESS {
                let user = str::raw::from_c_str(cast::transmute(&(*line).ut_user));
                users.push(user);
            }
        }

        endutent();
    }

    users.sort();
    println!("{}", users.connect(" "));
}
<commit_msg>Test if there are users before printing them.<commit_after>#[crate_id(name="users", vers="1.0.0", author="KokaKiwi")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) KokaKiwi <kokakiwi@kokakiwi.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: whoami (GNU coreutils) 8.22 */

// Allow dead code here in order to keep all fields, constants here, for consistency.
#[allow(dead_code)];

extern mod extra;

use std::io::print;
use std::cast;
use std::libc;
use std::os;
use std::ptr;
use std::str;
use extra::getopts::groups;

static DEFAULT_FILE: &'static str = "/var/run/utmp";

static UT_LINESIZE: uint = 32;
static UT_NAMESIZE: uint = 32;
static UT_HOSTSIZE: uint = 256;

static EMPTY: libc::c_short = 0;
static RUN_LVL: libc::c_short = 1;
static BOOT_TIME: libc::c_short = 2;
static NEW_TIME: libc::c_short = 3;
static OLD_TIME: libc::c_short = 4;
static INIT_PROCESS: libc::c_short = 5;
static LOGIN_PROCESS: libc::c_short = 6;
static USER_PROCESS: libc::c_short = 7;
static DEAD_PROCESS: libc::c_short = 8;
static ACCOUNTING: libc::c_short = 9;

struct c_exit_status {
    e_termination: libc::c_short,
    e_exit: libc::c_short,
}

struct c_utmp {
    ut_type: libc::c_short,
    ut_pid: libc::pid_t,
    ut_line: [libc::c_char, ..UT_LINESIZE],
    ut_id: [libc::c_char, ..4],

    ut_user: [libc::c_char, ..UT_NAMESIZE],
    ut_host: [libc::c_char, ..UT_HOSTSIZE],
    ut_exit: c_exit_status,
    ut_session: libc::c_long,
    ut_tv: libc::timeval,

    ut_addr_v6: [libc::int32_t, ..4],
    __unused: [libc::c_char, ..20],
}

extern {
    fn getutent() -> *c_utmp;
    fn getutid(ut: *c_utmp) -> *c_utmp;
    fn getutline(ut: *c_utmp) -> *c_utmp;

    fn pututline(ut: *c_utmp) -> *c_utmp;

    fn setutent();
    fn endutent();

    fn utmpname(file: *libc::c_char) -> libc::c_int;
}

fn main() {
    let args = os::args();
    let program = args[0].as_slice();
    let opts = ~[
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_err_msg()),
    };

    if matches.opt_present("help") {
        println!("users 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {:s} [OPTION]... [FILE]", program);
        println!("");
        print(groups::usage("Output who is currently logged in according to FILE.", opts));
        return;
    }

    if matches.opt_present("version") {
        println!("users 1.0.0");
        return;
    }

    let mut filename = DEFAULT_FILE;
    if matches.free.len() > 0 {
        filename = matches.free[0].as_slice();
    }

    exec(filename);
}

fn exec(filename: &str) {
    filename.with_c_str(|filename| {
        unsafe {
            utmpname(filename);
        }
    });

    let mut users: ~[~str] = ~[];

    unsafe {
        setutent();

        loop {
            let line = getutent();

            if line == ptr::null() {
                break;
            }

            if (*line).ut_type == USER_PROCESS {
                let user = str::raw::from_c_str(cast::transmute(&(*line).ut_user));
                users.push(user);
            }
        }

        endutent();
    }

    if users.len() > 0 {
        users.sort();
        println!("{}", users.connect(" "));
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Scanner {
    position: isize,
    buffer: Vec<char>,
}

impl Scanner {
    pub fn new() -> Scanner {
        Scanner {
            position: -1,
            buffer: Vec::new(),
        }
    }

    pub fn from_str(string: &str) -> Scanner {
        let mut scanner = Scanner::new();
        scanner.push_str(string);
        scanner
    }

    pub fn len(&self) -> isize {
        self.buffer.len() as isize
    }

    pub fn push_str(&mut self, string: &str) {
        self.buffer.extend(string.chars());
    }

    pub fn get_char(&mut self) -> Option<char> {
        if self.position < self.len() - 1 {
            self.position += 1;

            if self.position < self.len() {
                let c = self.buffer[self.position as usize];
                return Some(c)
            }
        }

        None
    }

    pub fn unget_char(&mut self) -> Option<()> {
        if self.position >= 0 {
            self.position -= 1;
            Some(())
        }
        else {
            None
        }
    }
}

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

    #[test]
    fn new() {
        let scanner = Scanner::new();
        assert_eq!(scanner.len(), 0);
    }

    #[test]
    fn can_add_text() {
        let mut scanner = Scanner::new();
        let text = "This is some text";

        scanner.push_str(text);
        scanner.push_str(text);

        assert_eq!(scanner.len(), text.len() as isize * 2);
    }

    #[test]
    fn can_get_characters() {
        // A string with uppercase and lowercase letters where all are unique
        let text = "Total";
        let mut scanner = Scanner::from_str(text);

        for c in text.chars() {
            if let Some(next) = scanner.get_char() {
                assert!(next == c, format!("Got character `{}` instead of character `{}`", next, c));
            }
            else {
                panic!("Could not get expected number of characters. Stopped when expecting `{}`", c);
            }
        }
    }

    #[test]
    fn cannot_get_beyond_length() {
        let mut scanner = Scanner::new();
        assert!(scanner.get_char().is_none());

        scanner = Scanner::from_str("T");
        scanner.get_char();
        assert!(scanner.get_char().is_none());
        // try again just in case
        assert!(scanner.get_char().is_none());
    }

    #[test]
    fn can_unget_characters() {
        let mut scanner = Scanner::from_str("abc");
        // 1. Get up to the expected character
        // position -> 0
        scanner.get_char();
        // position -> 1
        let expected = scanner.get_char();

        // 2. Unget back to before any character
        // position -> 0
        scanner.unget_char().unwrap();
        // position -> -1
        scanner.unget_char().unwrap();

        // 3. Get up to the end
        // position -> 0
        scanner.get_char();
        // position -> 1
        scanner.get_char();
        // position -> 2
        scanner.get_char();

        // 4. Unget back to the expected character
        // position -> 1
        scanner.unget_char().unwrap();
        // position -> 0
        scanner.unget_char().unwrap();
        // position -> 1
        let actual = scanner.get_char();

        assert_eq!(expected, actual);
    }

    #[test]
    fn cannot_unget_before_start() {
        let mut scanner = Scanner::from_str("T");
        assert!(scanner.unget_char().is_none());
        scanner.get_char();
        assert!(!scanner.unget_char().is_none());
        assert!(scanner.unget_char().is_none());
        // Try again just in case
        assert!(scanner.unget_char().is_none());
    }
}

<commit_msg>Forcing an error in the scanner to be seen with a panic!() rather than possibly ignored<commit_after>use std::vec::Vec;

pub struct Scanner {
    position: isize,
    buffer: Vec<char>,
}

impl Scanner {
    pub fn new() -> Scanner {
        Scanner {
            position: -1,
            buffer: Vec::new(),
        }
    }

    pub fn from_str(string: &str) -> Scanner {
        let mut scanner = Scanner::new();
        scanner.push_str(string);
        scanner
    }

    pub fn len(&self) -> isize {
        self.buffer.len() as isize
    }

    pub fn push_str(&mut self, string: &str) {
        self.buffer.extend(string.chars());
    }

    pub fn get_char(&mut self) -> Option<char> {
        if self.position < self.len() - 1 {
            self.position += 1;

            if self.position < self.len() {
                let c = self.buffer[self.position as usize];
                return Some(c)
            }
        }

        None
    }

    pub fn unget_char(&mut self) {
        if self.position >= 0 {
            self.position -= 1;
        }
        else {
            panic!("No character to unget");
        }
    }
}

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

    #[test]
    fn new() {
        let scanner = Scanner::new();
        assert_eq!(scanner.len(), 0);
    }

    #[test]
    fn can_add_text() {
        let mut scanner = Scanner::new();
        let text = "This is some text";

        scanner.push_str(text);
        scanner.push_str(text);

        assert_eq!(scanner.len(), text.len() as isize * 2);
    }

    #[test]
    fn can_get_characters() {
        // A string with uppercase and lowercase letters where all are unique
        let text = "Total";
        let mut scanner = Scanner::from_str(text);

        for c in text.chars() {
            if let Some(next) = scanner.get_char() {
                assert!(next == c, format!("Got character `{}` instead of character `{}`", next, c));
            }
            else {
                panic!("Could not get expected number of characters. Stopped when expecting `{}`", c);
            }
        }
    }

    #[test]
    fn cannot_get_beyond_length() {
        let mut scanner = Scanner::new();
        assert!(scanner.get_char().is_none());

        scanner = Scanner::from_str("T");
        scanner.get_char();
        assert!(scanner.get_char().is_none());
        // try again just in case
        assert!(scanner.get_char().is_none());
    }

    #[test]
    fn can_unget_characters() {
        let mut scanner = Scanner::from_str("abc");
        // 1. Get up to the expected character
        // position -> 0
        scanner.get_char();
        // position -> 1
        let expected = scanner.get_char();

        // 2. Unget back to before any character
        // position -> 0
        scanner.unget_char();
        // position -> -1
        scanner.unget_char();

        // 3. Get up to the end
        // position -> 0
        scanner.get_char();
        // position -> 1
        scanner.get_char();
        // position -> 2
        scanner.get_char();

        // 4. Unget back to the expected character
        // position -> 1
        scanner.unget_char();
        // position -> 0
        scanner.unget_char();
        // position -> 1
        let actual = scanner.get_char();

        assert_eq!(expected, actual);
    }

    #[test]
    #[should_panic(expected = "unget")]
    fn cannot_unget_before_start() {
        let mut scanner = Scanner::from_str("T");
        // panic
        scanner.unget_char();
    }

    #[test]
    #[should_panic(expected = "unget")]
    fn cannot_unget_too_far() {
        let mut scanner = Scanner::from_str("T");

        scanner.get_char();
        scanner.unget_char();

        // panic
        scanner.unget_char();
    }
}

<|endoftext|>


<commit_before>// partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
//
// See project root for licensing information.
//

use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io;
use std::io::{Read, Write};

use crate::types::Token;

/// Implements a specialized storage to set and retrieve `Token` instances.
/// The `scope_hash` represents the signature of the scopes for which the given token
/// should be stored or retrieved.
/// For completeness, the underlying, sorted scopes are provided as well. They might be
/// useful for presentation to the user.
pub trait TokenStorage {
    type Error: 'static + Error + Send;

    /// If `token` is None, it is invalid or revoked and should be removed from storage.
    /// Otherwise, it should be saved.
    fn set(
        &mut self,
        scope_hash: u64,
        scopes: &Vec<&str>,
        token: Option<Token>,
    ) -> Result<(), Self::Error>;
    /// A `None` result indicates that there is no token for the given scope_hash.
    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, Self::Error>;
}

/// Calculate a hash value describing the scopes, and return a sorted Vec of the scopes.
pub fn hash_scopes<'a, I, T>(scopes: I) -> (u64, Vec<String>)
where
    T: AsRef<str> + Ord + 'a,
    I: IntoIterator<Item = &'a T>,
{
    let mut sv: Vec<&str> = scopes
        .into_iter()
        .map(|s| s.as_ref())
        .collect::<Vec<&str>>();
    sv.sort();
    let mut sh = DefaultHasher::new();
    &sv.hash(&mut sh);
    let sv = sv.iter().map(|s| s.to_string()).collect();
    (sh.finish(), sv)
}

/// A storage that remembers nothing.
#[derive(Default)]
pub struct NullStorage;
#[derive(Debug)]
pub struct NullError;

impl Error for NullError {
    fn description(&self) -> &str {
        "NULL"
    }
}

impl fmt::Display for NullError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "NULL-ERROR".fmt(f)
    }
}

impl TokenStorage for NullStorage {
    type Error = NullError;
    fn set(&mut self, _: u64, _: &Vec<&str>, _: Option<Token>) -> Result<(), NullError> {
        Ok(())
    }
    fn get(&self, _: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        Ok(None)
    }
}

/// A storage that remembers values for one session only.
#[derive(Debug, Default)]
pub struct MemoryStorage {
    pub tokens: HashMap<u64, Token>,
}

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

impl TokenStorage for MemoryStorage {
    type Error = NullError;

    fn set(
        &mut self,
        scope_hash: u64,
        _: &Vec<&str>,
        token: Option<Token>,
    ) -> Result<(), NullError> {
        match token {
            Some(t) => self.tokens.insert(scope_hash, t),
            None => self.tokens.remove(&scope_hash),
        };
        Ok(())
    }

    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        match self.tokens.get(&scope_hash) {
            Some(t) => Ok(Some(t.clone())),
            None => Ok(None),
        }
    }
}

/// A single stored token.
#[derive(Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub token: Token,
}

/// List of tokens in a JSON object
#[derive(Serialize, Deserialize)]
struct JSONTokens {
    pub tokens: Vec<JSONToken>,
}

/// Serializes tokens to a JSON file on disk.
#[derive(Default)]
pub struct DiskTokenStorage {
    location: String,
    tokens: HashMap<u64, Token>,
}

impl DiskTokenStorage {
    pub fn new<S: AsRef<str>>(location: S) -> Result<DiskTokenStorage, io::Error> {
        let mut dts = DiskTokenStorage {
            location: location.as_ref().to_owned(),
            tokens: HashMap::new(),
        };

        // best-effort
        let read_result = dts.load_from_file();

        match read_result {
            Result::Ok(()) => Result::Ok(dts),
            Result::Err(e) => {
                match e.kind() {
                    io::ErrorKind::NotFound => Result::Ok(dts), // File not found; ignore and create new one
                    _ => Result::Err(e),                        // e.g. PermissionDenied
                }
            }
        }
    }

    fn load_from_file(&mut self) -> Result<(), io::Error> {
        let mut f = fs::OpenOptions::new().read(true).open(&self.location)?;
        let mut contents = String::new();

        match f.read_to_string(&mut contents) {
            Result::Err(e) => return Result::Err(e),
            Result::Ok(_sz) => (),
        }

        let tokens: JSONTokens;

        match serde_json::from_str(&contents) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(t) => tokens = t,
        }

        for t in tokens.tokens {
            self.tokens.insert(t.hash, t.token);
        }
        return Result::Ok(());
    }

    pub fn dump_to_file(&mut self) -> Result<(), io::Error> {
        let mut jsontokens = JSONTokens { tokens: Vec::new() };

        for (hash, token) in self.tokens.iter() {
            jsontokens.tokens.push(JSONToken {
                hash: *hash,
                token: token.clone(),
            });
        }

        let serialized;;

        match serde_json::to_string(&jsontokens) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(s) => serialized = s,
        }

        let mut f = fs::OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(&self.location)?;
        f.write(serialized.as_ref()).map(|_| ())
    }
}

impl TokenStorage for DiskTokenStorage {
    type Error = io::Error;
    fn set(
        &mut self,
        scope_hash: u64,
        _: &Vec<&str>,
        token: Option<Token>,
    ) -> Result<(), Self::Error> {
        match token {
            None => {
                self.tokens.remove(&scope_hash);
                ()
            }
            Some(t) => {
                self.tokens.insert(scope_hash, t.clone());
                ()
            }
        }
        self.dump_to_file()
    }
    fn get(&self, scope_hash: u64, _: &Vec<&str>) -> Result<Option<Token>, Self::Error> {
        Result::Ok(self.tokens.get(&scope_hash).map(|tok| tok.clone()))
    }
}
<commit_msg>enable storage to only partially reference namespaces available for tokens<commit_after>// partially (c) 2016 Google Inc. (Lewin Bormann, lewinb@google.com)
//
// See project root for licensing information.
//

use std::collections::hash_map::DefaultHasher;
use std::error::Error;
use std::fmt;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io;
use std::io::{Read, Write};

use crate::types::Token;
use itertools::Itertools;

/// Implements a specialized storage to set and retrieve `Token` instances.
/// The `scope_hash` represents the signature of the scopes for which the given token
/// should be stored or retrieved.
/// For completeness, the underlying, sorted scopes are provided as well. They might be
/// useful for presentation to the user.
pub trait TokenStorage {
    type Error: 'static + Error + Send;

    /// If `token` is None, it is invalid or revoked and should be removed from storage.
    /// Otherwise, it should be saved.
    fn set(
        &mut self,
        scope_hash: u64,
        scopes: &Vec<&str>,
        token: Option<Token>,
    ) -> Result<(), Self::Error>;
    /// A `None` result indicates that there is no token for the given scope_hash.
    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, Self::Error>;
}

/// Calculate a hash value describing the scopes, and return a sorted Vec of the scopes.
pub fn hash_scopes<'a, I, T>(scopes: I) -> (u64, Vec<String>)
where
    T: AsRef<str> + Ord + 'a,
    I: IntoIterator<Item = &'a T>,
{
    let mut sv: Vec<&str> = scopes
        .into_iter()
        .map(|s| s.as_ref())
        .collect::<Vec<&str>>();
    sv.sort();
    let mut sh = DefaultHasher::new();
    &sv.hash(&mut sh);
    let sv = sv.iter().map(|s| s.to_string()).collect();
    (sh.finish(), sv)
}

/// A storage that remembers nothing.
#[derive(Default)]
pub struct NullStorage;

#[derive(Debug)]
pub struct NullError;

impl Error for NullError {
    fn description(&self) -> &str {
        "NULL"
    }
}

impl fmt::Display for NullError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "NULL-ERROR".fmt(f)
    }
}

impl TokenStorage for NullStorage {
    type Error = NullError;
    fn set(&mut self, _: u64, _: &Vec<&str>, _: Option<Token>) -> Result<(), NullError> {
        Ok(())
    }
    fn get(&self, _: u64, _: &Vec<&str>) -> Result<Option<Token>, NullError> {
        Ok(None)
    }
}

/// A storage that remembers values for one session only.
#[derive(Debug, Default)]
pub struct MemoryStorage {
    tokens: Vec<JSONToken>,
}

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

impl TokenStorage for MemoryStorage {
    type Error = NullError;

    fn set(&mut self,
           scope_hash: u64,
           scopes: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), NullError> {
        match token {
            Some(t) => {
                self.tokens.push(
                    JSONToken {
                        hash: scope_hash,
                        scopes: Some(scopes.iter().map(|x| x.to_string()).collect()),
                        token: t.clone(),
                    }
                );
                ()
            },
            None => {
                let matched = self.tokens.iter().find_position(|x| x.hash == scope_hash);
                if let Some((idx, _)) = matched {
                    self.tokens.remove(idx);
                }
            }
        };
        Ok(())
    }

    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, NullError> {
        let scopes: Vec<_> = scopes.iter().sorted().unique().collect();

        for t in &self.tokens {
            if let Some(token_scopes) = &t.scopes {
                let matched = token_scopes.iter().filter(|x| scopes.contains(&&&x[..])).count();
                if matched >= scopes.len() {
                    return Result::Ok(Some(t.token.clone()));
                }
            } else if scope_hash == t.hash {
                return Result::Ok(Some(t.token.clone()));
            }
        }
        Result::Ok(None)
    }
}

/// A single stored token.
#[derive(Debug, Clone, Serialize, Deserialize)]
struct JSONToken {
    pub hash: u64,
    pub scopes: Option<Vec<String>>,
    pub token: Token,
}

/// List of tokens in a JSON object
#[derive(Serialize, Deserialize)]
struct JSONTokens {
    pub tokens: Vec<JSONToken>,
}

/// Serializes tokens to a JSON file on disk.
#[derive(Default)]
pub struct DiskTokenStorage {
    location: String,
    tokens: Vec<JSONToken>,
}

impl DiskTokenStorage {
    pub fn new<S: AsRef<str>>(location: S) -> Result<DiskTokenStorage, io::Error> {
        let mut dts = DiskTokenStorage {
            location: location.as_ref().to_owned(),
            tokens: Vec::new(),
        };

        // best-effort
        let read_result = dts.load_from_file();

        match read_result {
            Result::Ok(()) => Result::Ok(dts),
            Result::Err(e) => {
                match e.kind() {
                    io::ErrorKind::NotFound => Result::Ok(dts), // File not found; ignore and create new one
                    _ => Result::Err(e),                        // e.g. PermissionDenied
                }
            }
        }
    }

    fn load_from_file(&mut self) -> Result<(), io::Error> {
        let mut f = fs::OpenOptions::new().read(true).open(&self.location)?;
        let mut contents = String::new();

        match f.read_to_string(&mut contents) {
            Result::Err(e) => return Result::Err(e),
            Result::Ok(_sz) => (),
        }

        let tokens: JSONTokens;

        match serde_json::from_str(&contents) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(t) => tokens = t,
        }

        for t in tokens.tokens {
            self.tokens.push(t);
        }
        return Result::Ok(());
    }

    pub fn dump_to_file(&mut self) -> Result<(), io::Error> {
        let mut jsontokens = JSONTokens { tokens: Vec::new() };

        for token in self.tokens.iter() {
            jsontokens.tokens.push((*token).clone());
        }

        let serialized;;

        match serde_json::to_string(&jsontokens) {
            Result::Err(e) => return Result::Err(io::Error::new(io::ErrorKind::InvalidData, e)),
            Result::Ok(s) => serialized = s,
        }

        let mut f = fs::OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(&self.location)?;
        f.write(serialized.as_ref()).map(|_| ())
    }
}

impl TokenStorage for DiskTokenStorage {
    type Error = io::Error;
    fn set(&mut self,
           scope_hash: u64,
           scopes: &Vec<&str>,
           token: Option<Token>)
           -> Result<(), Self::Error> {
        match token {
            None => {
                let matched = self.tokens.iter().find_position(|x| x.hash == scope_hash);
                if let Some((idx, _)) = matched {
                    self.tokens.remove(idx);
                }
                ()
            }
            Some(t) => {
                self.tokens.push(
                    JSONToken {
                        hash: scope_hash,
                        scopes: Some(scopes.iter().map(|x| x.to_string()).collect()),
                        token: t.clone(),
                    }
                );
                ()
            }
        }
        self.dump_to_file()
    }
    fn get(&self, scope_hash: u64, scopes: &Vec<&str>) -> Result<Option<Token>, Self::Error> {
        let scopes: Vec<_> = scopes.iter().sorted().unique().collect();

        for t in &self.tokens {
            if let Some(token_scopes) = &t.scopes {
                let matched = token_scopes.iter().filter(|x| scopes.contains(&&&x[..])).count();
                // we may have some of the tokens as denormalized (many namespaces repeated)
                if matched >= scopes.len() {
                    return Result::Ok(Some(t.token.clone()));
                }
            } else if scope_hash == t.hash {
                return Result::Ok(Some(t.token.clone()));
            }
        }
        Result::Ok(None)
    }
}
<|endoftext|>


<commit_before>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;

    const STD_OUT_HANDLE: u32 = -11i32 as u32;
    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // https://docs.microsoft.com/en-us/windows/console/getstdhandle
        let std_out_handle = GetStdHandle(STD_OUT_HANDLE);
        if std_out_handle == INVALID_HANDLE_VALUE
        {
            return Err(GetLastError());
        }

        // https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        if 0 == GetConsoleMode(std_out_handle, &mut console_mode)
        {
            return Err(GetLastError());
        }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            if 0 == SetConsoleMode(std_out_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
            {
                return Err(GetLastError());
            }
        }
    }

    return Ok(());
}
<commit_msg>fix enable_ansi_support() for redirected STDOUT<commit_after>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    // ref: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#EXAMPLE_OF_ENABLING_VIRTUAL_TERMINAL_PROCESSING @@ https://archive.is/L7wRJ#76%

    use std::ffi::OsStr;
    use std::iter::once;
    use std::os::windows::ffi::OsStrExt;
    use std::ptr::null_mut;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::fileapi::CreateFile2;
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;

    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // ref: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfile2
        // Using `CreateFile2("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected
        let console_out_name: Vec<u16> = OsStr::new("CONOUT$").encode_wide().chain(once(0)).collect();
        let console_handle = CreateFile2(
            console_out_name.as_ptr(),
            winapi::um::winnt::GENERIC_READ | winapi::um::winnt::GENERIC_WRITE,
            winapi::um::winnt::FILE_SHARE_WRITE,
            winapi::um::fileapi::OPEN_EXISTING,
            null_mut(),
        );
        if console_handle == INVALID_HANDLE_VALUE
        {
            return Err(GetLastError());
        }

        // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        if 0 == GetConsoleMode(console_handle, &mut console_mode)
        {
            return Err(GetLastError());
        }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            if 0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
            {
                return Err(GetLastError());
            }
        }
    }

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


<commit_before>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};

    const STD_OUT_HANDLE: u32 = -11i32 as u32;
    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // https://docs.microsoft.com/en-us/windows/console/getstdhandle
        let std_out_handle = GetStdHandle(STD_OUT_HANDLE);
        let error_code = GetLastError();
        if error_code != 0 { return Err(error_code); }

        // https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        GetConsoleMode(std_out_handle, &mut console_mode);
        let error_code = GetLastError();
        if error_code != 0 { return Err(error_code); }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            SetConsoleMode(std_out_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
            let error_code = GetLastError();
            if error_code != 0 { return Err(error_code); }
        }
    }

    return Ok(());
}
<commit_msg>fix https://github.com/ogham/rust-ansi-term/issues/42<commit_after>/// Enables ANSI code support on Windows 10.
///
/// This uses Windows API calls to alter the properties of the console that
/// the program is running in.
///
/// https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx
///
/// Returns a `Result` with the Windows error code if unsuccessful.
#[cfg(windows)]
pub fn enable_ansi_support() -> Result<(), u32> {
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::errhandlingapi::GetLastError;
    use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;

    const STD_OUT_HANDLE: u32 = -11i32 as u32;
    const ENABLE_VIRTUAL_TERMINAL_PROCESSING: u32 = 0x0004;

    unsafe {
        // https://docs.microsoft.com/en-us/windows/console/getstdhandle
        let std_out_handle = GetStdHandle(STD_OUT_HANDLE);
        if std_out_handle == INVALID_HANDLE_VALUE
        {
            return Err(GetLastError());
        }

        // https://docs.microsoft.com/en-us/windows/console/getconsolemode
        let mut console_mode: u32 = 0;
        if 0 == GetConsoleMode(std_out_handle, &mut console_mode)
        {
            return Err(GetLastError());
        }

        // VT processing not already enabled?
        if console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0 {
            // https://docs.microsoft.com/en-us/windows/console/setconsolemode
            if 0 == SetConsoleMode(std_out_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
            {
                return Err(GetLastError());
            }
        }
    }

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


<commit_before>use perl_xs::IV;
use perl_xs::G_DISCARD;

static mut counter: IV = 0;

struct Cnt;

impl Cnt {
    fn new() -> Cnt {
        unsafe { counter = 0 };
        Cnt
    }
    fn get() -> IV {
        unsafe { counter }
    }
}

impl Drop for Cnt {
    fn drop(&mut self) {
        unsafe { counter += 1 };
    }
}

xs! {
    package XSTest::Panic;

    sub test_panic(_ctx) {
        let _cnt = Cnt::new();
        panic!("Panic!\n");
    }

    sub test_croak(ctx) {
        let _cnt = Cnt::new();
        ctx.call_pv(cstr!("XSTest::dies"), G_DISCARD);
        xs_return!(ctx, 42 as IV);
    }

    sub unwind_counter(ctx) {
        xs_return!(ctx, Cnt::get());
    }
}
<commit_msg>Fix static variable name.<commit_after>use perl_xs::IV;
use perl_xs::G_DISCARD;

static mut COUNTER: IV = 0;

struct Cnt;

impl Cnt {
    fn new() -> Cnt {
        unsafe { COUNTER = 0 };
        Cnt
    }
    fn get() -> IV {
        unsafe { COUNTER }
    }
}

impl Drop for Cnt {
    fn drop(&mut self) {
        unsafe { COUNTER += 1 };
    }
}

xs! {
    package XSTest::Panic;

    sub test_panic(_ctx) {
        let _cnt = Cnt::new();
        panic!("Panic!\n");
    }

    sub test_croak(ctx) {
        let _cnt = Cnt::new();
        ctx.call_pv(cstr!("XSTest::dies"), G_DISCARD);
        xs_return!(ctx, 42 as IV);
    }

    sub unwind_counter(ctx) {
        xs_return!(ctx, Cnt::get());
    }
}
<|endoftext|>


<commit_before>
//! This temporary module generates types that wrap around the old API (winit v5 and below) and
//! expose the new API (winit v6 and above).
//!
//! This is temporary so that existing backends can smoothly transition. After all implementations
//! have finished transitionning, this module should disappear.

macro_rules! gen_api_transition {
    () => {
        pub struct EventsLoop {
            windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
            interrupted: ::std::sync::atomic::AtomicBool,
        }

        impl EventsLoop {
            pub fn new() -> EventsLoop {
                EventsLoop {
                    windows: ::std::sync::Mutex::new(vec![]),
                    interrupted: ::std::sync::atomic::AtomicBool::new(false),
                }
            }

            pub fn interrupt(&self) {
                self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
            }

            pub fn poll_events<F>(&self, mut callback: F)
                where F: FnMut(::Event)
            {
                let mut windows = self.windows.lock().unwrap();
                for window in windows.iter() {
                    for event in window.poll_events() {
                        callback(::Event::WindowEvent {
                            window_id: ::WindowId(WindowId(&**window as *const Window as usize)),
                            event: event,
                        })
                    }
                }
            }

            pub fn run_forever<F>(&self, mut callback: F)
                where F: FnMut(::Event)
            {
                self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);

                // Yeah that's a very bad implementation.
                loop {
                    self.poll_events(|e| callback(e));
                    ::std::thread::sleep_ms(5);
                    if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
                        break;
                    }
                }
            }
        }

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct WindowId(usize);

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct DeviceId;

        pub struct Window2 {
            pub window: ::std::sync::Arc<Window>,
            events_loop: ::std::sync::Weak<EventsLoop>,
        }

        impl ::std::ops::Deref for Window2 {
            type Target = Window;
            #[inline]
            fn deref(&self) -> &Window {
                &*self.window
            }
        }

        impl Window2 {
            pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
                       pl_attribs: &PlatformSpecificWindowBuilderAttributes)
                       -> Result<Window2, CreationError>
            {
                let win = ::std::sync::Arc::new(try!(Window::new(window, pl_attribs)));
                events_loop.windows.lock().unwrap().push(win.clone());
                Ok(Window2 {
                    window: win,
                    events_loop: ::std::sync::Arc::downgrade(&events_loop),
                })
            }

            #[inline]
            pub fn id(&self) -> WindowId {
                WindowId(&*self.window as *const Window as usize)
            }
        }

        impl Drop for Window2 {
            fn drop(&mut self) {
                if let Some(ev) = self.events_loop.upgrade() {
                    let mut windows = ev.windows.lock().unwrap();
                    windows.retain(|w| &**w as *const Window != &*self.window as *const _);
                }
            }
        }
    };
}
<commit_msg>Attempt to update api_transition to addition of EventsLoopProxy<commit_after>
//! This temporary module generates types that wrap around the old API (winit v5 and below) and
//! expose the new API (winit v6 and above).
//!
//! This is temporary so that existing backends can smoothly transition. After all implementations
//! have finished transitionning, this module should disappear.

macro_rules! gen_api_transition {
    () => {
        pub struct EventsLoop {
            windows: ::std::sync::Mutex<Vec<::std::sync::Arc<Window>>>,
            interrupted: ::std::sync::atomic::AtomicBool,
            awakened: ::std::sync::Arc<::std::sync::atomic::AtomicBool>,
        }

        pub struct EventsLoopProxy {
            awakened: ::std::sync::Weak<::std::sync::atomic::AtomicBool>,
        }

        impl EventsLoop {
            pub fn new() -> EventsLoop {
                EventsLoop {
                    windows: ::std::sync::Mutex::new(vec![]),
                    interrupted: ::std::sync::atomic::AtomicBool::new(false),
                    awakened: ::std::sync::Arc::new(::std::sync::atomic::AtomicBool::new(false)),
                }
            }

            pub fn interrupt(&self) {
                self.interrupted.store(true, ::std::sync::atomic::Ordering::Relaxed);
            }

            pub fn poll_events<F>(&self, mut callback: F)
                where F: FnMut(::Event)
            {
                if self.awakened.load(::std::sync::atomic::Ordering::Relaxed) {
                    self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);
                    callback(::Event::Awakened);
                }

                let mut windows = self.windows.lock().unwrap();
                for window in windows.iter() {
                    for event in window.poll_events() {
                        callback(::Event::WindowEvent {
                            window_id: ::WindowId(WindowId(&**window as *const Window as usize)),
                            event: event,
                        })
                    }
                }
            }

            pub fn run_forever<F>(&self, mut callback: F)
                where F: FnMut(::Event)
            {
                self.interrupted.store(false, ::std::sync::atomic::Ordering::Relaxed);
                self.awakened.store(false, ::std::sync::atomic::Ordering::Relaxed);

                // Yeah that's a very bad implementation.
                loop {
                    self.poll_events(|e| callback(e));
                    ::std::thread::sleep_ms(5);
                    if self.interrupted.load(::std::sync::atomic::Ordering::Relaxed) {
                        break;
                    }
                }
            }

            pub fn create_proxy(&self) -> EventsLoopProxy {
                EventsLoopProxy {
                    awakened: ::std::sync::Arc::downgrade(&self.awakened),
                }
            }
        }

        impl EventsLoopProxy {
            pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
                match self.awakened.upgrade() {
                    None => Err(::EventsLoopClosed),
                    Some(awakened) => {
                        awakened.store(true, ::std::sync::atomic::Ordering::Relaxed);
                        Ok(())
                    },
                }
            }
        }

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct WindowId(usize);

        #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct DeviceId;

        pub struct Window2 {
            pub window: ::std::sync::Arc<Window>,
            events_loop: ::std::sync::Weak<EventsLoop>,
        }

        impl ::std::ops::Deref for Window2 {
            type Target = Window;
            #[inline]
            fn deref(&self) -> &Window {
                &*self.window
            }
        }

        impl Window2 {
            pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
                       pl_attribs: &PlatformSpecificWindowBuilderAttributes)
                       -> Result<Window2, CreationError>
            {
                let win = ::std::sync::Arc::new(try!(Window::new(window, pl_attribs)));
                events_loop.windows.lock().unwrap().push(win.clone());
                Ok(Window2 {
                    window: win,
                    events_loop: ::std::sync::Arc::downgrade(&events_loop),
                })
            }

            #[inline]
            pub fn id(&self) -> WindowId {
                WindowId(&*self.window as *const Window as usize)
            }
        }

        impl Drop for Window2 {
            fn drop(&mut self) {
                if let Some(ev) = self.events_loop.upgrade() {
                    let mut windows = ev.windows.lock().unwrap();
                    windows.retain(|w| &**w as *const Window != &*self.window as *const _);
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>// partially borrowed from
// https://doc.rust-lang.org/std/slice/
// http://rustbyexample.com/array.html
use std::iter::FromIterator;

fn main() {
    // slicing a Vec
    let vec = vec![1, 2, 3];
    let int_slice = &vec[..];
    // coercing an array to a slice
    let str_slice: &[&str] = &["one", "two", "three"];

    let x = &mut [1, 2, 3];
    println!("x: {:?}", x);
    x[1] = 7;
    assert_eq!(x, &[1, 7, 3]);

    println!("x: {:?}", x);

    let mut arr1 = [1, 2];
    println!("arr1: {:?}", arr1);
    arr1[1] = 1;
    println!("arr1: {:?}", arr1);

    let mut vec1 = [1, 2];
    println!("vec1: {:?}", vec1);
    vec1[1] = 1;
    println!("vec1: {:?}", vec1);

    //let mut vec2 = vec![|&i| vec![0; i]; 7];
    let mut vec2 = vec![vec![0; 7]; 7];

    // how to create a ragged array
    let mut v = Vec::from_iter ((0..10) .map (|idx| vec![idx; idx * 2]));
    println!("v.len(): {} v[1].len(): {}", v.len(), v[1].len());
    println!("v: {:?}", v);
    // prints
    // v: [[], [1, 1], [2, 2, 2, 2], [3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 4],
    // [5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
    // [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
    // [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
    // [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]]

    let v22 = v[2][2];
    println!("v22: {}", v22)
}
<commit_msg>a small contribution to `array_vec_demo`.<commit_after>// partially borrowed from
// https://doc.rust-lang.org/std/slice/
// http://rustbyexample.com/array.html
use std::iter::FromIterator;
use std::cmp::Ordering;

fn main() {
    // slicing a Vec
    let vec = vec![1, 2, 3];
    let int_slice = &vec[..];
    // coercing an array to a slice
    let str_slice: &[&str] = &["one", "two", "three"];

    let x = &mut [1, 2, 3];
    println!("x: {:?}", x);
    x[1] = 7;
    assert_eq!(x, &[1, 7, 3]);

    println!("x: {:?}", x);

    let mut arr1 = [1, 2];
    println!("arr1: {:?}", arr1);
    arr1[1] = 1;
    println!("arr1: {:?}", arr1);

    let mut vec1 = [1, 2];
    println!("vec1: {:?}", vec1);
    vec1[1] = 1;
    println!("vec1: {:?}", vec1);

    //let mut vec2 = vec![|&i| vec![0; i]; 7];
    let mut vec2 = vec![vec![0; 7]; 7];

    // how to create a ragged array
    let mut v = Vec::from_iter ((0..10) .map (|idx| vec![idx; idx * 2]));
    println!("v.len(): {} v[1].len(): {}", v.len(), v[1].len());
    println!("v: {:?}", v);
    // prints
    // v: [[], [1, 1], [2, 2, 2, 2], [3, 3, 3, 3, 3, 3], [4, 4, 4, 4, 4, 4, 4, 4],
    // [5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
    // [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
    // [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
    // [9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9]]

    let v22 = v[2][2];
    println!("v22: {}", v22);

    // fill a non-equidistant array
    let dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * dx).cos().abs() ) );
    println!("x: {:?}", x);

    // x.sort(); // error: the trait `core::cmp::Ord` is not implemented for the type `f64` [E0277]
    x.sort_by(|&x,&y| if x < y { Ordering::Less } else if x > y { Ordering::Greater } else { Ordering::Equal } );
    println!("ordered x: {:?}", x);
}
<|endoftext|>


<commit_before>use generator::*;

#[derive(Debug)]
enum Action {
    Play(&'static str),
    Stop,
}

#[derive(Debug, Clone, Copy)]
enum State {
    Playing,
    Stopped,
}

use crate::Action::*;
use crate::State::*;

fn main() {
    let mut cd_player = Gn::new_scoped(|mut s| {
        let mut state = Stopped;
        loop {
            match state {
                Stopped => match s.get_yield() {
                    Some(Play(t)) => {
                        println!("I'm playing {}", t);
                        state = Playing;
                    }
                    Some(Stop) => println!("I'm already stopped"),
                    _ => unreachable!("some thing wrong"),
                },

                Playing => match s.get_yield() {
                    Some(Stop) => {
                        println!("I'm stopped");
                        state = Stopped;
                    }
                    Some(Play(_)) => println!("should first stop"),
                    _ => unreachable!("some thing wrong"),
                },
            }

            s.yield_with(state);
        }
    });

    for _ in 0..1000 {
        cd_player.send(Play("hello world"));
        cd_player.send(Play("hello another day"));
        cd_player.send(Stop);
        cd_player.send(Stop);
        cd_player.send(Play("hello another day"));
        cd_player.send(Stop);
    }
}
<commit_msg>:pencil: fix cd example release bug<commit_after>use generator::*;

#[derive(Debug)]
enum Action {
    Play(&'static str),
    Stop,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum State {
    Playing,
    Stopped,
}

use crate::Action::*;
use crate::State::*;

fn main() {
    let mut cd_player = Gn::new_scoped(|mut s| {
        let mut state = Stopped;
        loop {
            // println!("{:?}", *state);
            // in release mod without this there is bugs!!!!! (rustc 1.59.0 (9d1b2106e 2022-02-23))
            std::sync::atomic::compiler_fence(std::sync::atomic::Ordering::AcqRel);

            match state {
                Stopped => match s.get_yield() {
                    Some(Play(t)) => {
                        println!("I'm playing {}", t);
                        state = Playing;
                    }
                    Some(Stop) => println!("I'm already stopped"),
                    _ => unreachable!("some thing wrong"),
                },

                Playing => match s.get_yield() {
                    Some(Stop) => {
                        println!("I'm stopped");
                        state = Stopped;
                    }
                    Some(Play(_)) => println!("should first stop"),
                    _ => unreachable!("some thing wrong"),
                },
            }

            s.yield_with(state);
        }
    });

    for _ in 0..1000 {
        let ret = cd_player.send(Play("hello world"));
        assert_eq!(ret, Playing);
        let ret = cd_player.send(Play("hello another day"));
        assert_eq!(ret, Playing);
        let ret = cd_player.send(Stop);
        assert_eq!(ret, Stopped);
        let ret = cd_player.send(Stop);
        assert_eq!(ret, Stopped);
        let ret = cd_player.send(Play("hello another day"));
        assert_eq!(ret, Playing);
        let ret = cd_player.send(Stop);
        assert_eq!(ret, Stopped);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::time::{Duration, Instant};
use std::mem;
use std::io::{stderr, Write};
use std::iter::repeat;
use std::collections::{HashSet};
use std::default::Default;
use std::iter::FromIterator;
use std::sync::RwLock;
use lazy_static::lazy_static;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::set_filter;
/// use ra_prof::Filter;
/// let max_depth = 2;
/// let allowed = vec!["profile1".to_string(), "profile2".to_string()];
/// let f = Filter::new( max_depth, allowed );
/// set_filter(f);
/// ```
///
pub fn set_filter(f: Filter) {
    let set = HashSet::from_iter(f.allowed.iter().cloned());
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData { depth: f.depth, allowed: set, version: old.version + 1 };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// #Example
/// ```
/// use ra_prof::profile;
/// use ra_prof::set_filter;
/// use ra_prof::Filter;
///
/// let allowed = vec!["profile1".to_string(), "profile2".to_string()];
/// let f = Filter::new(2, allowed);
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
///
pub fn profile(desc: &str) -> Profiler {
    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.len() == 0 {
            match FILTER.try_read() {
                Ok(f) => {
                    if f.version > stack.filter_data.version {
                        stack.filter_data = f.clone();
                    }
                }
                Err(_) => (),
            };
        }
        let desc_str = desc.to_string();
        if desc_str.is_empty() {
            Profiler { desc: None }
        } else if stack.starts.len() < stack.filter_data.depth
            && stack.filter_data.allowed.contains(&desc_str)
        {
            stack.starts.push(Instant::now());
            Profiler { desc: Some(desc_str) }
        } else {
            Profiler { desc: None }
        }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
}

impl Filter {
    pub fn new(depth: usize, allowed: Vec<String>) -> Filter {
        Filter { depth, allowed }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
}

lazy_static! {
    static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default());
}

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        print(0, &stack.messages, &mut stdout.lock());
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(lvl: usize, msgs: &[Message], out: &mut impl Write) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl + 1).collect::<String>();
    for (i, &Message { level: l, duration: dur, message: ref msg }) in msgs.iter().enumerate() {
        if l != lvl {
            continue;
        }
        writeln!(out, "{} {:6}ms - {}", indent, dur.as_millis(), msg)
            .expect("printing profiling info to stdout");

        print(lvl + 1, &msgs[last..i], out);
        last = i;
    }
}

#[cfg(test)]
mod tests {

    use super::profile;
    use super::set_filter;
    use super::Filter;

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s);
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }
}
<commit_msg>fast path for disabled profiler<commit_after>use std::cell::RefCell;
use std::time::{Duration, Instant};
use std::mem;
use std::io::{stderr, Write};
use std::iter::repeat;
use std::collections::{HashSet};
use std::default::Default;
use std::iter::FromIterator;
use std::sync::{RwLock, atomic::{AtomicBool, Ordering}};
use lazy_static::lazy_static;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::set_filter;
/// use ra_prof::Filter;
/// let max_depth = 2;
/// let allowed = vec!["profile1".to_string(), "profile2".to_string()];
/// let f = Filter::new( max_depth, allowed );
/// set_filter(f);
/// ```
///
pub fn set_filter(f: Filter) {
    PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
    let set = HashSet::from_iter(f.allowed.iter().cloned());
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData { depth: f.depth, allowed: set, version: old.version + 1 };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// #Example
/// ```
/// use ra_prof::profile;
/// use ra_prof::set_filter;
/// use ra_prof::Filter;
///
/// let allowed = vec!["profile1".to_string(), "profile2".to_string()];
/// let f = Filter::new(2, allowed);
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
///
pub fn profile(desc: &str) -> Profiler {
    assert!(!desc.is_empty());
    if !PROFILING_ENABLED.load(Ordering::Relaxed) {
        return Profiler { desc: None };
    }

    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.len() == 0 {
            match FILTER.try_read() {
                Ok(f) => {
                    if f.version > stack.filter_data.version {
                        stack.filter_data = f.clone();
                    }
                }
                Err(_) => (),
            };
        }

        if stack.starts.len() > stack.filter_data.depth {
            return Profiler { desc: None };
        }

        if stack.filter_data.allowed.is_empty() || stack.filter_data.allowed.contains(desc) {
            stack.starts.push(Instant::now());
            Profiler { desc: Some(desc.to_string()) }
        } else {
            Profiler { desc: None }
        }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
}

impl Filter {
    pub fn new(depth: usize, allowed: Vec<String>) -> Filter {
        Filter { depth, allowed }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);

lazy_static! {
    static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default());
}

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        print(0, &stack.messages, &mut stdout.lock());
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(lvl: usize, msgs: &[Message], out: &mut impl Write) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl + 1).collect::<String>();
    for (i, &Message { level: l, duration: dur, message: ref msg }) in msgs.iter().enumerate() {
        if l != lvl {
            continue;
        }
        writeln!(out, "{} {:6}ms - {}", indent, dur.as_millis(), msg)
            .expect("printing profiling info to stdout");

        print(lvl + 1, &msgs[last..i], out);
        last = i;
    }
}

#[cfg(test)]
mod tests {

    use super::profile;
    use super::set_filter;
    use super::Filter;

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s);
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }
}
<|endoftext|>


<commit_before>use actix_web::http::{header, Method, StatusCode};
use actix_web::{
    fs, middleware, server, App, HttpRequest, HttpResponse, Result
};
use serde_derive::Deserialize;

// NOTE: Recompile the server everytime gallery.json is changed
static GALLERY_JSON: &'static str = include_str!("../static/gallery.json");

const USE_RUST_IMPL: bool = true;

#[derive(Deserialize)]
struct Piece {
    id: u32,
    name: String,
//    image: String,
}

/// favicon handler
fn favicon(_req: &HttpRequest) -> Result<fs::NamedFile> {
    if USE_RUST_IMPL {
        Ok(fs::NamedFile::open("client/sen-client/www/favicon.ico")?)
    } else {
        Ok(fs::NamedFile::open("client/www/assets/favicon.ico")?)
    }
}

fn gallery(req: &HttpRequest) -> Result<HttpResponse> {
    println!("{:?}", req);

    // response
    Ok(HttpResponse::build(StatusCode::OK)
        .content_type("application/json")
        .body(GALLERY_JSON))
}

fn get_piece_name_from_id(gallery: &Vec<Piece>, id: u32) -> Option<String> {
    let res: Option<&Piece> = gallery.iter().find(|&piece| piece.id == id);

    match res {
        Some(r) => Some(r.name.clone()),
        None => None
    }
}

fn gallery_item(req: &HttpRequest) -> Result<fs::NamedFile> {
    // println!("{:?}", req);
    let g: Vec<Piece> = serde_json::from_str(GALLERY_JSON).unwrap();
    let param_id = req.match_info().get("id").unwrap();
    let id: u32 = std::str::FromStr::from_str(param_id).unwrap();
    let name = get_piece_name_from_id(&g, id).unwrap();
    let path = ["server/static/seni", &name].join("/");
    let path_with_ext = [path, "seni".to_string()].join(".");

    Ok(fs::NamedFile::open(path_with_ext)?)
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=debug"); // info
//    ::std::env::set_var("RUST_BACKTRACE", "1");
    env_logger::init();

    let matches = clap::App::new("Seni Server")
        .version("0.1.0")
        .author("Inderjit Gill <email@indy.io>")
        .about("AppServer for Seni")
        .arg(
            clap::Arg::with_name("port")
                .short("p")
                .long("port")
                .help("The port number")
                .takes_value(true),
        ).get_matches();

    let port = matches.value_of("port").unwrap_or("8080");
    let bind_addr = ["127.0.0.1", port].join(":");
    println!("bind_addr is {}", bind_addr);

    let sys = actix::System::new("seni-server");

    if USE_RUST_IMPL {
        println!("hello from the RUST_IMPL");
    } else {
        println!("using the older C_IMPL");
    }

    let home = if USE_RUST_IMPL {
        "client/sen-client/www"
    } else {
        "client/www/assets"
    };

    server::new(move || {
        App::new()
        // enable logger
            .middleware(middleware::Logger::default())
        // register favicon
            .resource("/favicon", |r| r.f(favicon))
        // static files
            .resource("/gallery", |r| r.f(gallery))
            .resource("/gallery/{id}", |r| r.method(Method::GET).f(gallery_item))
        // redirect
            .resource("/", |r| r.method(Method::GET).f(|_req| {
                HttpResponse::Found()
                    .header(header::LOCATION, "/index.html")
                    .finish()
            }))
        // static files
            .handler("/dist", fs::StaticFiles::new("client/www/dist").unwrap())
            .handler("/", fs::StaticFiles::new(home).unwrap())
    }).bind(bind_addr)
        .unwrap()
        .shutdown_timeout(1)
        .start();

    let _ = sys.run();
}
<commit_msg>server: c comman line switch<commit_after>use actix_web::http::{header, Method, StatusCode};
use actix_web::{fs, middleware, server, App, HttpRequest, HttpResponse, Result};
use serde_derive::Deserialize;

// NOTE: Recompile the server everytime gallery.json is changed
static GALLERY_JSON: &'static str = include_str!("../static/gallery.json");

#[derive(Deserialize)]
struct Piece {
    id: u32,
    name: String,
    //    image: String,
}

/// favicon handler
// fn favicon_rust(_req: &HttpRequest) -> Result<fs::NamedFile> {
//     Ok(fs::NamedFile::open("client/sen-client/www/favicon.ico")?)
// }

fn favicon_c(_req: &HttpRequest) -> Result<fs::NamedFile> {
    Ok(fs::NamedFile::open("client/www/assets/favicon.ico")?)
}

fn gallery(req: &HttpRequest) -> Result<HttpResponse> {
    println!("{:?}", req);

    // response
    Ok(HttpResponse::build(StatusCode::OK)
        .content_type("application/json")
        .body(GALLERY_JSON))
}

fn get_piece_name_from_id(gallery: &Vec<Piece>, id: u32) -> Option<String> {
    let res: Option<&Piece> = gallery.iter().find(|&piece| piece.id == id);

    match res {
        Some(r) => Some(r.name.clone()),
        None => None,
    }
}

fn gallery_item(req: &HttpRequest) -> Result<fs::NamedFile> {
    // println!("{:?}", req);
    let g: Vec<Piece> = serde_json::from_str(GALLERY_JSON).unwrap();
    let param_id = req.match_info().get("id").unwrap();
    let id: u32 = std::str::FromStr::from_str(param_id).unwrap();
    let name = get_piece_name_from_id(&g, id).unwrap();
    let path = ["server/static/seni", &name].join("/");
    let path_with_ext = [path, "seni".to_string()].join(".");

    Ok(fs::NamedFile::open(path_with_ext)?)
}

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=debug"); // info
                                                        //    ::std::env::set_var("RUST_BACKTRACE", "1");
    env_logger::init();

    let matches = clap::App::new("Seni Server")
        .version("0.1.0")
        .author("Inderjit Gill <email@indy.io>")
        .about("AppServer for Seni")
        .arg(
            clap::Arg::with_name("port")
                .short("p")
                .long("port")
                .help("The port number")
                .takes_value(true),
        )
        .arg(
            clap::Arg::with_name("c-client")
                .short("c")
                .multiple(false)
                .help("use C version of client"),
        )
        .get_matches();

    let using_c = matches.is_present("c-client");

    let port = matches.value_of("port").unwrap_or("8080");
    let bind_addr = ["127.0.0.1", port].join(":");
    println!("bind_addr is {}", bind_addr);

    let sys = actix::System::new("seni-server");

    if using_c {
        println!("using the older C_IMPL");
    } else {
        println!("hello from the RUST_IMPL");
    }

    let home = if using_c {
        "client/www/assets"
    } else {
        "client/sen-client/www"
    };

    server::new(move || {
        App::new()
            // enable logger
            .middleware(middleware::Logger::default())
            // register favicon
            .resource("/favicon", |r| r.f(favicon_c))
            // static files
            .resource("/gallery", |r| r.f(gallery))
            .resource("/gallery/{id}", |r| r.method(Method::GET).f(gallery_item))
            // redirect
            .resource("/", |r| {
                r.method(Method::GET).f(|_req| {
                    HttpResponse::Found()
                        .header(header::LOCATION, "/index.html")
                        .finish()
                })
            })
            // static files
            .handler("/dist", fs::StaticFiles::new("client/www/dist").unwrap())
            .handler("/", fs::StaticFiles::new(home).unwrap())
    })
    .bind(bind_addr)
    .unwrap()
    .shutdown_timeout(1)
    .start();

    let _ = sys.run();
}
<|endoftext|>