<commit_before>use redox::Box;
use redox::fs::File;
use redox::io::*;
use redox::mem;
use redox::ops::DerefMut;
use redox::slice;
use redox::syscall::sys_yield;
use redox::String;
use redox::ToString;
use redox::to_num::ToNum;
use redox::Vec;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: isize,
    /// The y coordinate of the window
    y: isize,
    /// The width of the window
    w: usize,
    /// The height of the window
    h: usize,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Some(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:///{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Some(file) => Some(box Window {
                x: x,
                y: y,
                w: w,
                h: h,
                t: title.to_string(),
                file: file,
                font: font,
                data: vec![0; w * h * 4],
            }),
            None => None
        }
    }

    //TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Some(path) = self.file.path() {
            //orbital://x/y/w/h/t
            let parts: Vec<&str> = path.split('/').collect();
            if let Some(x) = parts.get(3) {
                self.x = x.to_num_signed();
            }
            if let Some(y) = parts.get(4) {
                self.y = y.to_num_signed();
            }
            if let Some(w) = parts.get(5) {
                self.w = w.to_num();
            }
            if let Some(h) = parts.get(6) {
                self.h = h.to_num();
            }
        }
    }

    /// Get x
    //TODO: Sync with window movements
    pub fn x(&self) -> isize {
        self.x
    }

    /// Get y
    //TODO: Sync with window movements
    pub fn y(&self) -> isize {
        self.y
    }

    /// Get width
    pub fn width(&self) -> usize {
        self.w
    }

    /// Get height
    pub fn height(&self) -> usize {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        //TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: isize, y: isize, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as isize && y < self.h as isize {
            let offset = y as usize * self.w + x as usize;
            self.data[offset] = color.data;
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: isize, y: isize, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as isize, y + row as isize, color);
                }
            }
            offset += 1;
        }
    }

    //TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, color: Color) {
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    //TODO: Improve speed
    pub fn image(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    //TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = Event::new();
        let event_ptr: *mut Event = &mut event;
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Some(0) => unsafe { sys_yield() },
                Some(_) => return Some(event),
                None => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.seek(SeekFrom::Start(0));
        let to_write: &[u8] = unsafe{ mem::transmute::<&[u32],&[u8]>(&self.data) };
        self.file.write(to_write);
        return self.file.sync();
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter {
            window: self,
        }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<commit_msg>Do not use confusing mem::transmute<commit_after>use redox::Box;
use redox::fs::File;
use redox::io::*;
use redox::mem;
use redox::ops::DerefMut;
use redox::slice;
use redox::syscall::sys_yield;
use redox::String;
use redox::ToString;
use redox::to_num::ToNum;
use redox::Vec;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: isize,
    /// The y coordinate of the window
    y: isize,
    /// The width of the window
    w: usize,
    /// The height of the window
    h: usize,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: isize, y: isize, w: usize, h: usize, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Some(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:///{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Some(file) => Some(box Window {
                x: x,
                y: y,
                w: w,
                h: h,
                t: title.to_string(),
                file: file,
                font: font,
                data: vec![0; w * h * 4],
            }),
            None => None
        }
    }

    //TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Some(path) = self.file.path() {
            //orbital://x/y/w/h/t
            let parts: Vec<&str> = path.split('/').collect();
            if let Some(x) = parts.get(3) {
                self.x = x.to_num_signed();
            }
            if let Some(y) = parts.get(4) {
                self.y = y.to_num_signed();
            }
            if let Some(w) = parts.get(5) {
                self.w = w.to_num();
            }
            if let Some(h) = parts.get(6) {
                self.h = h.to_num();
            }
        }
    }

    /// Get x
    //TODO: Sync with window movements
    pub fn x(&self) -> isize {
        self.x
    }

    /// Get y
    //TODO: Sync with window movements
    pub fn y(&self) -> isize {
        self.y
    }

    /// Get width
    pub fn width(&self) -> usize {
        self.w
    }

    /// Get height
    pub fn height(&self) -> usize {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        //TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: isize, y: isize, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as isize && y < self.h as isize {
            let offset = y as usize * self.w + x as usize;
            self.data[offset] = color.data;
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: isize, y: isize, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as isize, y + row as isize, color);
                }
            }
            offset += 1;
        }
    }

    //TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, color: Color) {
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    //TODO: Improve speed
    pub fn image(&mut self, start_x: isize, start_y: isize, w: usize, h: usize, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as isize {
            for x in start_x..start_x + w as isize {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    //TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = Event::new();
        let event_ptr: *mut Event = &mut event;
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Some(0) => unsafe { sys_yield() },
                Some(_) => return Some(event),
                None => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.seek(SeekFrom::Start(0));
        self.file.write(& unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<u32>())
        });
        return self.file.sync();
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter {
            window: self,
        }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<|endoftext|>


<commit_before>extern mod opengles;   // FIXME: Should only be for tests.
use glut::{check_loop, create_window, destroy_window, init, init_display_mode, swap_buffers, GLint};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLclampf, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{get_uniform_location, link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use core::comm::{Chan, Port};
use libc::{c_int, c_uint};
use io::println;
use ptr::{addr_of, null};
use str::to_bytes;
use task::TaskBuilder;
use vec::raw::to_ptr;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(&po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup: Port<()> = Port();
        let wakeup_chan = Chan(&wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

*/
<commit_msg>Remove unused imports.<commit_after>extern mod opengles;   // FIXME: Should only be for tests.
use glut::{swap_buffers, GLint};
use self::opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, COMPILE_STATUS};
use self::opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, NO_ERROR, STATIC_DRAW};
use self::opengles::gl2::{TRIANGLE_STRIP, VERTEX_SHADER, GLenum};
use self::opengles::gl2::{GLsizei, GLuint, attach_shader, bind_buffer};
use self::opengles::gl2::{buffer_data, create_program, clear, clear_color};
use self::opengles::gl2::{compile_shader, create_shader, draw_arrays};
use self::opengles::gl2::{enable_vertex_attrib_array, gen_buffers};
use self::opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use self::opengles::gl2::{get_shader_info_log, get_shader_iv};
use self::opengles::gl2::{link_program, shader_source};
use self::opengles::gl2::{use_program, vertex_attrib_pointer_f32};

use core::libc::c_int;
use core::io::println;
use core::str::to_bytes;

fn fragment_shader_source() -> ~str {
    ~"
    #ifdef GLES2
        precision mediump float;
    #endif

        void main(void) {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    "
}

fn vertex_shader_source() -> ~str {
    ~"
        attribute vec3 aVertexPosition;

        /*uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;*/

        void main(void) {
            gl_Position = /*uPMatrix * uMVMatrix **/
                vec4(aVertexPosition, 1.0);
        }
    "
}

fn load_shader(source_str: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[to_bytes(source_str)]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader with error");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(get_shader_info_log(shader_id));
        fail!(~"failed to compile shader");
    }
    return shader_id;
}

struct ShaderProgram {
    program: GLuint,
    aVertexPosition: c_int,
    /*let uPMatrix: c_int;
    let uMVMatrix: c_int;*/
}

fn ShaderProgram(program: GLuint) -> ShaderProgram {
    let p = ShaderProgram {
        program : program,
        aVertexPosition : get_attrib_location(program, ~"aVertexPosition"),
        /*self.uPMatrix : get_uniform_location(program, "uPMatrix"),
        self.uMVMatrix : get_uniform_location(program, "uMVMatrix")*/
    };
    enable_vertex_attrib_array(p.aVertexPosition as GLuint);
    return p;
}

fn init_shaders() -> ShaderProgram {
    let vertex_shader = load_shader(vertex_shader_source(), VERTEX_SHADER);
    let fragment_shader = load_shader(fragment_shader_source(),
                                      FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);

    return ShaderProgram(program);
}

fn init_buffers() -> GLuint {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);
    let vertices = ~[
        0.0f32, 1.0f32, 0.0f32,
        1.0f32, 0.0f32, 0.0f32,
        0.0f32, 0.0f32, 0.0f32
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    return triangle_vertex_buffer;
}

fn draw_scene(shader_program: ShaderProgram, vertex_buffer: GLuint) {
    clear_color(0.0f32, 0.0f32, 1.0f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    vertex_attrib_pointer_f32(shader_program.aVertexPosition as GLuint,
                              3 as GLint, false, 0 as GLsizei, 0 as GLuint);
    draw_arrays(TRIANGLE_STRIP, 0 as GLint, 3 as GLint);
}

fn display_callback() {
    let program = init_shaders();
    let vertex_buffer = init_buffers();
    draw_scene(program, vertex_buffer);

    swap_buffers();
}

/*
#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = Port();
    let ch = Chan(&po);
    let _result_ch: Chan<()> = builder.spawn_listener(|_port| {
        init();
        init_display_mode(0 as c_uint);
        let window = create_window(~"Rust GLUT");
        display_func(display_callback);

        let wakeup: Port<()> = Port();
        let wakeup_chan = Chan(&wakeup);
        timer_func(1000, || send(wakeup_chan, ()));

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }
    });

    recv(po);
}

*/
<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;

use iron::method::Method;
use iron::prelude::*;
use iron::status::Status;
use mount::Mount;
use rand::Rng;
use staticfile::Static;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::time::Instant;

static CONFIG_FILE_NAME: &str = "find-reviewer.json";

#[derive(Debug, Deserialize, Eq, PartialEq)]
enum FindReviewerRequest {
    NeedReviewer { coder: String },
    HaveTimeForReview { reviewer: String },
    WillReview { review_id: u32 },
    WontReview { review_id: u32 },
}

#[derive(Debug, Eq, PartialEq, Serialize)]
enum FindReviewerResponse {
    Accepted {},
    NoReviewerNeeded {},
    AlreadyRegistered {},
    NeedsReviewer { coder: String, review_id: u32 },
    ReviewNotFound {},
}

type SharedApplication = Arc<Mutex<Application>>;

fn main() {
    let configuration = load_configuration();
    let application = SharedApplication::new(Mutex::new(Application::new(configuration)));

    let mut mount = Mount::new();
    mount
        .mount("/find-reviewer", {
            let application = application.clone();
            move |request: &mut Request| Ok(process_request(request, &application))
        })
        .mount("/", Static::new(Path::new("www")));

    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(1));
        application.lock().unwrap().process_timeouts();
    });

    Iron::new(mount).http("localhost:3000").unwrap();
}

fn load_configuration() -> ApplicationConfiguration {
    let config = File::open(CONFIG_FILE_NAME)
        .map(|open_file| serde_json::from_reader(open_file).expect(&format!("Could not parse {}", CONFIG_FILE_NAME)))
        .unwrap_or_else(|err| {
            println!("Could not read {}: {}\nFile will be created", CONFIG_FILE_NAME, err);
            ApplicationConfiguration::default()
        });

    File::create(CONFIG_FILE_NAME)
        .map(|created_file| {
            serde_json::to_writer_pretty(created_file, &config).expect(&format!("Could not serialize {}", CONFIG_FILE_NAME))
        })
        .unwrap_or_else(|err| println!("Could not write {}: {}", CONFIG_FILE_NAME, err));

    config
}

fn process_request(request: &mut Request, application: &SharedApplication) -> Response {
    if request.method != Method::Post {
        return Response::with((Status::BadRequest, "Must be a POST request"));
    }

    let parsed = match serde_json::from_reader(request.body.by_ref()) {
        Err(message) => return Response::with((Status::BadRequest, format!("JSON error: {}", message))),
        Ok(request) => request,
    };

    let response = dispatch_request(&mut application.lock().unwrap(), parsed);

    Response::with((Status::Ok, serde_json::to_string_pretty(&response).unwrap()))
}

fn dispatch_request<G: IdGenerator>(application: &mut Application<G>, request: FindReviewerRequest) -> FindReviewerResponse {
    match request {
        FindReviewerRequest::NeedReviewer { coder } => application.need_reviewer(coder),
        FindReviewerRequest::HaveTimeForReview { reviewer } => application.have_time_for_review(&reviewer),
        FindReviewerRequest::WillReview { review_id } => application.will_review(review_id),
        FindReviewerRequest::WontReview { review_id } => application.wont_review(review_id),
    }
}

struct Application {
    configuration: ApplicationConfiguration,
    waiting_coders: HashSet<String>,
    active_reviews: HashMap<u32, Review>,
}

#[derive(Serialize, Deserialize)]
struct ApplicationConfiguration {
    timeout: Duration,
    wip_limit: usize,
}

impl Default for ApplicationConfiguration {
    fn default() -> Self {
        ApplicationConfiguration {
            timeout: Duration::from_secs(30),
            wip_limit: 5,
        }
    }
}

#[derive(Clone)]
struct Review {
    pub coder: String,
    pub enqueued_coder: Option<String>,
    pub started: Instant,
}

impl Application {
    fn new(configuration: ApplicationConfiguration) -> Application {
        Application {
            configuration,
            waiting_coders: HashSet::new(),
            active_reviews: HashMap::new(),
        }
    }

    fn need_reviewer(&mut self, incoming_coder: String) -> FindReviewerResponse {
        if self.is_already_registered(&incoming_coder) {
            FindReviewerResponse::AlreadyRegistered {}
        } else if self.waiting_coders.len() >= self.configuration.wip_limit {
            let random_waiting_coder = self.waiting_coders.iter().next().unwrap().clone();
            self.start_review(random_waiting_coder, Some(incoming_coder))
        } else {
            self.waiting_coders.insert(incoming_coder);
            FindReviewerResponse::Accepted {}
        }
    }

    fn is_already_registered(&self, coder: &String) -> bool {
        self.waiting_coders.contains(coder) ||
            self.active_reviews
                .values()
                .any(|review| &review.coder == coder || review.enqueued_coder.as_ref() == Some(coder))
    }

    fn have_time_for_review(&mut self, incoming_reviewer: &String) -> FindReviewerResponse {
        let random_coder_except_incoming_reviewer = self.waiting_coders
            .iter()
            .filter(|&coder| coder != incoming_reviewer)
            .next()
            .cloned();
        match random_coder_except_incoming_reviewer {
            Some(coder) => self.start_review(coder, None),
            None => FindReviewerResponse::NoReviewerNeeded {},
        }
    }

    fn start_review(&mut self, coder: String, enqueued_coder: Option<String>) -> FindReviewerResponse {
        let review = Review {
            coder: coder.clone(),
            enqueued_coder,
            started: Instant::now(),
        };
        self.remove_coder(&coder);
        let review_id = self.insert_review(review);

        FindReviewerResponse::NeedsReviewer { coder, review_id }
    }

    fn generate_id(&mut self) -> u32 {
        loop {
            let id = rand::thread_rng().gen();
            if !self.active_reviews.contains_key(&id) {
                return id;
            }
        }
    }

    fn will_review(&mut self, review_id: u32) -> FindReviewerResponse {
        match self.active_reviews.remove(&review_id) {
            Some(review) => {
                review
                    .enqueued_coder
                    .map(|coder| self.waiting_coders.insert(coder));
                FindReviewerResponse::Accepted {}
            }
            None => FindReviewerResponse::ReviewNotFound {},
        }
    }

    fn wont_review(&mut self, review_id: u32) -> FindReviewerResponse {
        match self.active_reviews.remove(&review_id) {
            Some(review) => {
                self.waiting_coders.insert(review.coder);
                FindReviewerResponse::Accepted {}
            }
            None => FindReviewerResponse::ReviewNotFound {},
        }
    }

    fn remove_coder(&mut self, coder: &String) {
        self.waiting_coders.remove(coder);
    }

    fn insert_review(&mut self, review: Review) -> u32 {
        let id = self.generate_id();
        self.active_reviews.insert(id, review);
        id
    }

    fn process_timeouts(&mut self) {
        let now = Instant::now();
        let timed_out: Vec<_> = self.active_reviews
            .iter()
            .filter(|&(_, review)| (now - review.started) > self.configuration.timeout)
            .map(|(&id, _)| id)
            .collect();
        for review_id in timed_out {
            self.wont_review(review_id);
        }
    }
}

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

    #[test]
    fn add_coder_no_more_than_once() {
        let mut app = create_application();

        let resp = app.need_reviewer("coder1".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder1".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});

        let resp = app.need_reviewer("coder2".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder3".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder2".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});

        let resp = app.need_reviewer("coder3".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});
    }

    #[test]
    fn respect_wip_limit() {
        let mut application = create_application();
        let coder_set = (0..5).map(|x| format!("coder{}", x) ).collect::<HashSet<_>>();
        let coder_set_cloned = coder_set.clone();
        for coder in coder_set {
            let review_request = FindReviewerRequest::NeedReviewer {
                coder,
            };
            assert_eq!(dispatch_request(&mut application, review_request), FindReviewerResponse::Accepted {});
        }
        let answer = dispatch_request(
            &mut application,
            FindReviewerRequest::NeedReviewer {
                coder: format!("anothercoder"),
            },
        );
        match answer{
            FindReviewerResponse::NeedsReviewer {coder: coder_name,review_id: _} =>
                assert!(coder_set_cloned.iter().any(|x| *x==coder_name)),
            _ => panic!(),
        }
    }

    fn create_application() -> Application {
        Application::new(ApplicationConfiguration::default())
    }
}
<commit_msg>More idiomatic Rust<commit_after>extern crate iron;
extern crate mount;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;

use iron::method::Method;
use iron::prelude::*;
use iron::status::Status;
use mount::Mount;
use rand::Rng;
use staticfile::Static;
use std::collections::HashMap;
use std::collections::HashSet;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;
use std::time::Instant;

static CONFIG_FILE_NAME: &str = "find-reviewer.json";

#[derive(Debug, Deserialize, Eq, PartialEq)]
enum FindReviewerRequest {
    NeedReviewer { coder: String },
    HaveTimeForReview { reviewer: String },
    WillReview { review_id: u32 },
    WontReview { review_id: u32 },
}

#[derive(Debug, Eq, PartialEq, Serialize)]
enum FindReviewerResponse {
    Accepted {},
    NoReviewerNeeded {},
    AlreadyRegistered {},
    NeedsReviewer { coder: String, review_id: u32 },
    ReviewNotFound {},
}

type SharedApplication = Arc<Mutex<Application>>;

fn main() {
    let configuration = load_configuration();
    let application = SharedApplication::new(Mutex::new(Application::new(configuration)));

    let mut mount = Mount::new();
    mount
        .mount("/find-reviewer", {
            let application = application.clone();
            move |request: &mut Request| Ok(process_request(request, &application))
        })
        .mount("/", Static::new(Path::new("www")));

    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(1));
        application.lock().unwrap().process_timeouts();
    });

    Iron::new(mount).http("localhost:3000").unwrap();
}

fn load_configuration() -> ApplicationConfiguration {
    let config = File::open(CONFIG_FILE_NAME)
        .map(|open_file| serde_json::from_reader(open_file).expect(&format!("Could not parse {}", CONFIG_FILE_NAME)))
        .unwrap_or_else(|err| {
            println!("Could not read {}: {}\nFile will be created", CONFIG_FILE_NAME, err);
            ApplicationConfiguration::default()
        });

    File::create(CONFIG_FILE_NAME)
        .map(|created_file| {
            serde_json::to_writer_pretty(created_file, &config).expect(&format!("Could not serialize {}", CONFIG_FILE_NAME))
        })
        .unwrap_or_else(|err| println!("Could not write {}: {}", CONFIG_FILE_NAME, err));

    config
}

fn process_request(request: &mut Request, application: &SharedApplication) -> Response {
    if request.method != Method::Post {
        return Response::with((Status::BadRequest, "Must be a POST request"));
    }

    let parsed = match serde_json::from_reader(request.body.by_ref()) {
        Err(message) => return Response::with((Status::BadRequest, format!("JSON error: {}", message))),
        Ok(request) => request,
    };

    let response = dispatch_request(&mut application.lock().unwrap(), parsed);

    Response::with((Status::Ok, serde_json::to_string_pretty(&response).unwrap()))
}

fn dispatch_request<G: IdGenerator>(application: &mut Application<G>, request: FindReviewerRequest) -> FindReviewerResponse {
    match request {
        FindReviewerRequest::NeedReviewer { coder } => application.need_reviewer(coder),
        FindReviewerRequest::HaveTimeForReview { reviewer } => application.have_time_for_review(&reviewer),
        FindReviewerRequest::WillReview { review_id } => application.will_review(review_id),
        FindReviewerRequest::WontReview { review_id } => application.wont_review(review_id),
    }
}

struct Application {
    configuration: ApplicationConfiguration,
    waiting_coders: HashSet<String>,
    active_reviews: HashMap<u32, Review>,
}

#[derive(Serialize, Deserialize)]
struct ApplicationConfiguration {
    timeout: Duration,
    wip_limit: usize,
}

impl Default for ApplicationConfiguration {
    fn default() -> Self {
        ApplicationConfiguration {
            timeout: Duration::from_secs(30),
            wip_limit: 5,
        }
    }
}

#[derive(Clone)]
struct Review {
    pub coder: String,
    pub enqueued_coder: Option<String>,
    pub started: Instant,
}

impl Application {
    fn new(configuration: ApplicationConfiguration) -> Application {
        Application {
            configuration,
            waiting_coders: HashSet::new(),
            active_reviews: HashMap::new(),
        }
    }

    fn need_reviewer(&mut self, incoming_coder: String) -> FindReviewerResponse {
        if self.is_already_registered(&incoming_coder) {
            FindReviewerResponse::AlreadyRegistered {}
        } else if self.waiting_coders.len() >= self.configuration.wip_limit {
            let random_waiting_coder = self.waiting_coders.iter().next().unwrap().clone();
            self.start_review(random_waiting_coder, Some(incoming_coder))
        } else {
            self.waiting_coders.insert(incoming_coder);
            FindReviewerResponse::Accepted {}
        }
    }

    fn is_already_registered(&self, coder: &String) -> bool {
        self.waiting_coders.contains(coder) ||
            self.active_reviews
                .values()
                .any(|review| &review.coder == coder || review.enqueued_coder.as_ref() == Some(coder))
    }

    fn have_time_for_review(&mut self, incoming_reviewer: &String) -> FindReviewerResponse {
        let random_coder_except_incoming_reviewer = self.waiting_coders
            .iter()
            .filter(|&coder| coder != incoming_reviewer)
            .next()
            .cloned();
        match random_coder_except_incoming_reviewer {
            Some(coder) => self.start_review(coder, None),
            None => FindReviewerResponse::NoReviewerNeeded {},
        }
    }

    fn start_review(&mut self, coder: String, enqueued_coder: Option<String>) -> FindReviewerResponse {
        let review = Review {
            coder: coder.clone(),
            enqueued_coder,
            started: Instant::now(),
        };
        self.remove_coder(&coder);
        let review_id = self.insert_review(review);

        FindReviewerResponse::NeedsReviewer { coder, review_id }
    }

    fn generate_id(&mut self) -> u32 {
        loop {
            let id = rand::thread_rng().gen();
            if !self.active_reviews.contains_key(&id) {
                return id;
            }
        }
    }

    fn will_review(&mut self, review_id: u32) -> FindReviewerResponse {
        match self.active_reviews.remove(&review_id) {
            Some(review) => {
                review
                    .enqueued_coder
                    .map(|coder| self.waiting_coders.insert(coder));
                FindReviewerResponse::Accepted {}
            }
            None => FindReviewerResponse::ReviewNotFound {},
        }
    }

    fn wont_review(&mut self, review_id: u32) -> FindReviewerResponse {
        match self.active_reviews.remove(&review_id) {
            Some(review) => {
                self.waiting_coders.insert(review.coder);
                FindReviewerResponse::Accepted {}
            }
            None => FindReviewerResponse::ReviewNotFound {},
        }
    }

    fn remove_coder(&mut self, coder: &String) {
        self.waiting_coders.remove(coder);
    }

    fn insert_review(&mut self, review: Review) -> u32 {
        let id = self.generate_id();
        self.active_reviews.insert(id, review);
        id
    }

    fn process_timeouts(&mut self) {
        let now = Instant::now();
        let timed_out: Vec<_> = self.active_reviews
            .iter()
            .filter(|&(_, review)| (now - review.started) > self.configuration.timeout)
            .map(|(&id, _)| id)
            .collect();
        for review_id in timed_out {
            self.wont_review(review_id);
        }
    }
}

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

    #[test]
    fn add_coder_no_more_than_once() {
        let mut app = create_application();

        let resp = app.need_reviewer("coder1".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder1".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});

        let resp = app.need_reviewer("coder2".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder3".to_owned());
        assert_eq!(resp, FindReviewerResponse::Accepted {});

        let resp = app.need_reviewer("coder2".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});

        let resp = app.need_reviewer("coder3".to_owned());
        assert_eq!(resp, FindReviewerResponse::AlreadyRegistered {});
    }

    #[test]
    fn respect_wip_limit() {
        let mut application = create_application();
        let coders = (0..5)
            .map(|x| format!("coder{}", x))
            .collect::<HashSet<_>>();
        for coder in &coders {
            let request = create_need_reviewer_request(coder);
            assert_eq!(dispatch_request(&mut application, request), FindReviewerResponse::Accepted {});
        }
        let answer = dispatch_request(&mut application, create_need_reviewer_request("anothercoder"));
        match answer {
            FindReviewerResponse::NeedsReviewer {
                coder,
                review_id: _,
            } => assert!(coders.contains(&coder)),
            _ => panic!(),
        }
    }

    fn create_application() -> Application {
        Application::new(ApplicationConfiguration::default())
    }

    fn create_need_reviewer_request(coder: &str) -> FindReviewerRequest {
        FindReviewerRequest::NeedReviewer {
            coder: coder.into(),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>ScheduleTree limits don't need to be Clone<commit_after><|endoftext|>


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

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device, F> {
    /// Graphics device.
    pub device: D,
    /// Resource factory.
    pub factory: F,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device, F> ops::Deref for Graphics<D, F> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device, F> ops::DerefMut for Graphics<D, F> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device, F: device::Factory<D::Resources>> Graphics<D, F> {
    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ::ClearData, mask: ::Mask, frame: &::Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &::Frame<D::Resources>)
                -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
                     params: &'a T, frame: &::Frame<D::Resources>)
                     -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
        // self.factory.after_frame();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<D: device::Device, F> {
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<D, F>;
}

impl<
    D: device::Device,
    F: device::Factory<D::Resources>,
> DeviceExt<D, F> for (D, F) {
    fn into_graphics(mut self) -> Graphics<D, F> {
        let rend = self.1.create_renderer();
        Graphics {
            device: self.0,
            factory: self.1,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<commit_msg>Added Graphics::cleanup<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Device extension. Allows creating a renderer or converting into
//! a single-threaded wrapper.

use std::ops;
use device;
use render::{batch, Renderer};
use render::ext::factory::RenderFactory;
use render::shade::ShaderParam;

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D: device::Device, F> {
    /// Graphics device.
    pub device: D,
    /// Resource factory.
    pub factory: F,
    /// Renderer front-end.
    pub renderer: Renderer<D::Resources, D::CommandBuffer>,
    /// Hidden batch context.
    context: batch::Context<D::Resources>,
}

impl<D: device::Device, F> ops::Deref for Graphics<D, F> {
    type Target = batch::Context<D::Resources>;

    fn deref(&self) -> &batch::Context<D::Resources> {
        &self.context
    }
}

impl<D: device::Device, F> ops::DerefMut for Graphics<D, F> {
    fn deref_mut(&mut self) -> &mut batch::Context<D::Resources> {
        &mut self.context
    }
}

impl<D: device::Device, F: device::Factory<D::Resources>> Graphics<D, F> {
    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ::ClearData, mask: ::Mask, frame: &::Frame<D::Resources>) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a `RefBatch` batch.
    pub fn draw<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                batch: &'a batch::RefBatch<T>, frame: &::Frame<D::Resources>)
                -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&(batch, &self.context), frame)
    }

    /// Draw a `CoreBatch` batch.
    pub fn draw_core<'a, T: ShaderParam<Resources = D::Resources>>(&'a mut self,
                     core: &'a batch::CoreBatch<T>, slice: &'a ::Slice<D::Resources>,
                     params: &'a T, frame: &::Frame<D::Resources>)
                     -> Result<(), ::DrawError<batch::OutOfBounds>> {
        self.renderer.draw(&self.context.bind(core, slice, params), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }

    /// Cleanup resources after the frame.
    pub fn cleanup(&mut self) {
        self.device.after_frame();
        self.factory.cleanup();
    }
}

/// Backend extension trait for convenience methods
pub trait DeviceExt<D: device::Device, F> {
    /// Convert to single-threaded wrapper
    fn into_graphics(mut self) -> Graphics<D, F>;
}

impl<
    D: device::Device,
    F: device::Factory<D::Resources>,
> DeviceExt<D, F> for (D, F) {
    fn into_graphics(mut self) -> Graphics<D, F> {
        let rend = self.1.create_renderer();
        Graphics {
            device: self.0,
            factory: self.1,
            renderer: rend,
            context: batch::Context::new(),
        }
    }
}
<|endoftext|>


<commit_before>
pub type Matrix = Vec<Vec<usize>>;

pub fn search_matrix(ma : &Matrix, target : usize) -> bool {
    let yl = ma.len();
    match yl {
        0 => { false },
        //TODO BinarySearch
        1 => { ma[0].contains(&target) },
        _ => {
            let xl = ma[0].len();
            match xl {
                0 => { false },
                //TODO BinarySearch
                1 => { ma.iter().any(|col| col[0] == target) },
                _ => {
                    let ix = xl/2 - 1;
                    let iy = yl/2 - 1 ;
                    assert!(ix >= 0 && iy >= 0);
                    assert!(yl > iy+1);
                    assert!(xl > ix+1);

                    let upleft = ma[iy][ix];
                    let downright = ma[iy+1][ix+1];

                    if  upleft == target || downright == target {
                        return true;
                    } else if upleft > target {
                        let ma_upleft = split_ma(ma, 0, 0, ix+1, iy+1);
                         search_matrix(&ma_upleft, target)
                    } else if downright < target {
                        let ma_downRight = split_ma(ma, ix+1, iy+1, xl, yl);
                        search_matrix(&ma_downRight, target)
                    } else {
                        let ma_downLeft = split_ma(ma, 0, iy+1, ix+1, yl);
                        if search_matrix(&ma_downLeft, target) {
                            return true;
                        }
                        let ma_upRight = split_ma(ma, ix+1, 0, iy+1,  xl);
                        if search_matrix(&ma_upRight, target) {
                            return true;
                        }
                        return false;
                    }
                }
            }
        }
    }
}

pub fn split_ma(ma : &Matrix, start_x : usize, start_y : usize, end_x : usize, end_y : usize, ) -> Matrix {
    if end_y > ma.len() || start_y > end_y {
        panic!("invalid index");
    }
    let mut ret : Matrix = vec![];
    let mut iy = start_y;
    loop {
        if iy >= end_y {
            break;
        }

        ret.push(split_vec(&ma[iy], start_x, end_x));
        iy += 1;
    }
    return ret;
}

pub fn split_vec(col : &Vec<usize>, start_x : usize, end_x : usize) -> Vec<usize> {
    if end_x > col.len() || start_x > end_x {
        panic!("invalid index");
    }
    let mut subcol = vec![];
    let mut ix = start_x;

    loop {
        if ix >= end_x {
            break;
        }
        subcol.push(col[ix]);
        ix += 1;
    }
    return subcol;
}

#[test]
fn test_search_matrix() {
    let ma = vec![
      vec![1,   4,  7, 11, 15],
      vec![2,   5,  8, 12, 19],
      vec![3,   6,  9, 16, 22],
      vec![10, 13, 14, 17, 24],
      vec![18, 21, 23, 26, 30]
    ];
    assert!(search_matrix(&ma, 5));
    assert!(!search_matrix(&ma, 20));
    assert!(search_matrix(&ma, 16));
}

#[test]
fn test_split_vec() {
    let v = vec![1,   4,  7, 11, 15];
    assert_eq!(split_vec(&v, 1, 4), vec![4,  7, 11]);
    assert_eq!(split_vec(&v, 1, 2), vec![4]);
}

#[test]
fn test_split_ma() {
    let ma = vec![
      vec![1,   4,  7, 11, 15],
      vec![2,   5,  8, 12, 19],
      vec![3,   6,  9, 16, 22],
      vec![10, 13, 14, 17, 24],
      vec![18, 21, 23, 26, 30]
    ];
    let ret1 = vec![
    vec![   5,  8, 12],
    vec![  6,  9, 16],
    vec![ 13, 14, 17],
    ];
    let ret2 =  vec![
    vec![   5]
    ];
    assert_eq!(split_ma(&ma, 1, 1, 4, 4), ret1);
    assert_eq!(split_ma(&ma, 1, 1, 2, 2), ret2);
}
<commit_msg>240. m(logN) solution<commit_after>

// class Solution:
//     # @param {integer[][]} matrix
//     # @param {integer} target
//     # @return {boolean}
//     def searchMatrix(self, matrix, target):
//         colLength = len(matrix)
//         if colLength == 0:  return False
//         rowLength = len(matrix[0])
//         if rowLength == 0:  return False
//         leftElem = [matrix[i][0] for i in range(0,len(matrix))]
//         rightElem = [matrix[i][-1] for i in range(0,len(matrix))]
//         leftIndex = self.binSearch(leftElem, target)+1
//         rightIndex = self.binSearch(rightElem, target)
//         if leftIndex == 0 or rightIndex == len(matrix) - 1:
//             if target != matrix[-1][-1] and target != matrix[0][0]:
//                 return False
//             else:   return True
//         if leftIndex < rightIndex:  return False
//         if rightIndex >= 0 and matrix[rightIndex] == target:    return True
//         for i in xrange(rightIndex, leftIndex):
//             index = self.binSearch(matrix[i], target)
//             if index >= 0 and matrix[i][index] == target:   return True
//         return False

pub fn bin_search(ve : &Vec<usize>, target: usize, start : usize) -> usize {
    let l = ve.len();
    match l {
        0 => { return start; },
        1 | 2 | 3 => {
            let mut j = 0;
            for x in 0..l {
                if ve[x] > target {
                    break;
                } else {
                    j = x;
                }
            }
            return j+start;
        },
        _ => {
            let x = l/2;
            if ve[x] == target {
                return x+start;
            } else if ve[x] > target {
                if ve[x-1] <= target {
                    return x-1+start;
                } else {
                    let ve_left = split_vec(ve, 0, x);
                    return bin_search(&ve_left, target, start);
                }
            } else {
                    let ve_right = split_vec(ve, x+1, l);
                    return bin_search(&ve_right, target, start+x+1);
                }
            }
        }
    }

pub fn split_vec(col : &Vec<usize>, start_x : usize, end_x : usize) -> Vec<usize> {
    if end_x > col.len() || start_x > end_x {
        panic!("invalid index");
    }
    let mut subcol = vec![];
    let mut ix = start_x;

    loop {
        if ix >= end_x {
            break;
        }
        subcol.push(col[ix]);
        ix += 1;
    }
    return subcol;
}

// #[test]
// fn test_search_matrix() {
//     let ma = vec![
//       vec![1,   4,  7, 11, 15],
//       vec![2,   5,  8, 12, 19],
//       vec![3,   6,  9, 16, 22],
//       vec![10, 13, 14, 17, 24],
//       vec![18, 21, 23, 26, 30]
//     ];
//     assert!(search_matrix(&ma, 5));
//     assert!(!search_matrix(&ma, 20));
//     assert!(search_matrix(&ma, 16));
// }

#[test]
fn test_bin_search() {
    let ve = vec![1,  4,  7, 11, 15, 23, 34, 35, 41, 47, 55, 59, 80];
    assert_eq!(bin_search(&ve, 15, 0), 4);
    assert_eq!(bin_search(&ve, 39, 0), 7);
    assert_eq!(bin_search(&ve, 5, 0), 1);
}
<|endoftext|>


<commit_before>extern crate ppbert;
extern crate num;

use std::mem::transmute;

use num::bigint;
use num::bigint::ToBigInt;

use ppbert::parser;
use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};

fn p(bytes: &[u8]) -> Result<BertTerm> {
    let mut parser = parser::Parser::new(bytes.to_vec());
    parser.parse()
}

#[test]
fn magic_number() {
    assert!(p(&[131, 97, 0]).is_ok());
    assert!(p(&[130, 97, 0]).is_err());
    assert!(match p(&[130, 97, 0]) {
        Err(BertError::InvalidMagicNumber(_)) => true,
        _ => false
    });
}

#[test]
fn consume_all() {
    let extra: u8 = 42;
    assert!(p(&[131, 97, 0, extra]).is_err());
}

#[test]
fn small_integer() {
    for i in 0 .. 255_u8 {
        assert!(match p(&[131, 97, i]) {
            Ok(BertTerm::Int(j)) => i as i32 == j,
            _ => false
        });
    }
}

#[test]
fn integer() {
    for i in 0 .. 255_u8 {
        assert!(match p(&[131, 98, 0, 0, 0, i]) {
            Ok(BertTerm::Int(j)) => j == i as i32,
            _ => false
        });

            assert!(match p(&[131, 98, 0, 0, i, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 8,
            _ => false
        });

            assert!(match p(&[131, 98, 0, i, 0, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 16,
            _ => false
        });

            assert!(match p(&[131, 98, i, 0, 0, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 24,
            _ => false
        });
    }
}

#[test]
fn old_float() {
    assert!(match p(b"\x83\x6398.5\x00") {
        Ok(BertTerm::Float(f)) => f == 98.5,
        _ => false
    });

    assert!(match p(b"\x83\x63-23.5") {
        Ok(BertTerm::Float(f)) => f == -23.5,
        _ => false
    });

    assert!(p(b"\x83\x63abc").is_err());
}

#[test]
fn new_float() {
    let float_as_u64: u64 = unsafe { transmute(3.141592) };
    let bytes = &[
        131, 70,
        (float_as_u64 >> 56) as u8 & 0xff_u8,
        (float_as_u64 >> 48) as u8 & 0xff_u8,
        (float_as_u64 >> 40) as u8 & 0xff_u8,
        (float_as_u64 >> 32) as u8 & 0xff_u8,
        (float_as_u64 >> 24) as u8 & 0xff_u8,
        (float_as_u64 >> 16) as u8 & 0xff_u8,
        (float_as_u64 >> 8) as u8 & 0xff_u8,
        (float_as_u64 >> 0) as u8 & 0xff_u8
    ];
    assert!(match p(bytes) {
        Ok(BertTerm::Float(x)) => x == 3.141592,
        _ => false
    });
}

#[test]
fn atom() {
    // 2-byte atom
    assert!(match p(b"\x83\x64\x00\x04abcd") {
        Ok(BertTerm::Atom(ref s)) => s == "abcd",
        _ => false
    });

    // 1-byte atom
    assert!(match p(b"\x83\x73\x04abcd") {
        Ok(BertTerm::Atom(ref s)) => s == "abcd",
        _ => false
    });

    assert!(match p(b"\x83\x73\x04abc") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });

    assert!(match p(b"\x83\x73\x03abcd") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // latin1 (0xe9 = é)
    assert!(match p(b"\x83\x64\x00\x04caf\xe9") {
        Ok(BertTerm::Atom(ref s)) => s == "café",
        _ => false
    });

    assert!(match p(b"\x83\x73\x04caf\xe9") {
        Ok(BertTerm::Atom(ref s)) => s == "café",
        _ => false
    });
}

#[test]
fn atom_utf8() {
    let atom_name = "jérôme";
    let atom_bytes = atom_name.to_string().into_bytes();

    // 2-byte UTF-8 atom
    let mut bert: Vec<u8> = vec![131, 118, 0, atom_bytes.len() as u8];
    bert.extend(&atom_bytes);
    assert!(match p(&bert) {
        Ok(BertTerm::Atom(ref s)) => s == atom_name,
        _ => false
    });

    // 1-byte UTF-8 atom
    let mut bert: Vec<u8> = vec![131, 119, atom_bytes.len() as u8];
    bert.extend(&atom_bytes);
    assert!(match p(&bert) {
        Ok(BertTerm::Atom(ref s)) => s == atom_name,
        _ => false
    });

    // Not enough data
    let mut bert: Vec<u8> = vec![131, 119, (atom_bytes.len() + 1) as u8];
    bert.extend(&atom_bytes);
    println!("{:?}", bert);
    assert!(match p(&bert) {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });

    // Too much data
    let mut bert: Vec<u8> = vec![131, 119, (atom_bytes.len() - 1) as u8];
    bert.extend(&atom_bytes);
    println!("{:?}", bert);
    assert!(match p(&bert) {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });
}

#[test]
fn string() {
    assert!(match p(b"\x83\x6b\x00\x06foobar") {
        Ok(BertTerm::String(ref s)) => s == b"foobar",
        _ => false
    });

    // too many characters
    assert!(match p(b"\x83\x6b\x00\x02foo") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // not enough characters
    assert!(match p(b"\x83\x6b\x00\x04foo") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });
}

#[test]
fn binary() {
    assert!(match p(b"\x83\x6d\x00\x00\x00\x06foobar") {
        Ok(BertTerm::Binary(ref s)) => s == b"foobar",
        _ => false
    });

    // too many characters
    assert!(match p(b"\x83\x6d\x00\x00\x00\x02foo") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // not enough characters
    assert!(match p(b"\x83\x6d\x00\x00\x00\x04foo") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });
}

#[test]
fn nil() {
    assert!(match p(b"\x83\x6a") {
        Ok(BertTerm::Nil) => true,
        _ => false
    });
}

#[test]
fn list() {
    use ppbert::bertterm::BertTerm::*;
    // proper list
    let b = &[
        131, 108, 0, 0, 0, 4,        // four elements
        97, 16,                      // small int (16)
        98, 0, 0, 255, 255,          // int (65535)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
        107, 0, 3, b'd', b'e', b'f', // string (def)
        106                          // tail
    ];
    match p(b) {
        Ok(List(ref terms)) => {
            assert_eq!(4, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Int(0xffff) => true,
                _ => false
            });
            assert!(match terms[2] {
                Atom(ref s) => s == "abc",
                _ => false
            });
            assert!(match terms[3] {
                String(ref s) => s == b"def",
                _ => false
            });
        }
        _ => assert!(false)
    };

    // improper list
    let b = &[
        131, 108, 0, 0, 0, 4,        // four elements
        97, 16,                      // small int (16)
        98, 0, 0, 255, 255,          // int (65535)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
        107, 0, 3, b'd', b'e', b'f', // string (def)
        107, 0, 3, b'g', b'h', b'i'  // tail
    ];
    match p(b) {
        Ok(List(ref terms)) => {
            assert_eq!(5, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Int(0xffff) => true,
                _ => false
            });
            assert!(match terms[2] {
                Atom(ref s) => s == "abc",
                _ => false
            });
            assert!(match terms[3] {
                String(ref s) => s == b"def",
                _ => false
            });
            assert!(match terms[4] {
                String(ref s) => s == b"ghi",
                _ => false
            });
        }
        _ => assert!(false)
    };
}

#[test]
fn tuple() {
    use ppbert::bertterm::BertTerm::*;

    // small
    let b = &[
        131, 104, 2,                 // two elements
        97, 16,                      // small int (16)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
    ];

    match p(b) {
        Ok(Tuple(ref terms)) => {
            assert_eq!(2, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Atom(ref s) => s == "abc",
                _ => false
            });
        }
        _ => assert!(false)
    };

    // large
    let b = &[
        131, 105, 0, 0, 0, 2,        // two elements
        97, 16,                      // small int (16)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
    ];

    match p(b) {
        Ok(Tuple(ref terms)) => {
            assert_eq!(2, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Atom(ref s) => s == "abc",
                _ => false
            });
        }
        e => { println!("{:?}", e); assert!(false) }
    };
}

#[test]
fn bigint() {
    // small
    assert!(match p(&[131, 110, 1, 1, 10]) {
        Ok(BertTerm::BigInt(b)) => b == (-10).to_bigint().unwrap(),
        e => { println!("{:?}", e); false }
    });

    // large
    assert!(match p(&[131, 111, 0, 0, 0, 1, 0, 42]) {
        Ok(BertTerm::BigInt(b)) => b == (42).to_bigint().unwrap(),
        e => { println!("{:?}", e); false }
    });
}

#[test]
fn map() {
    let binary = &[
        131,
        116,
        0, 0, 0, 2, // two keys and values
        97, 0,      // keys[0] == 0
        100, 0, 4, b'z', b'e', b'r', b'o',
        97, 42,     // keys[1] == 42
        100, 0, 4, b'h', b'g', b't', b'g'
    ];
    assert!(match p(binary) {
        Ok(BertTerm::Map(ref keys, ref vals)) => {
            keys[0] == BertTerm::Int(0) &&
                keys[1] == BertTerm::Int(42) &&
                vals[0] == BertTerm::Atom("zero".to_string()) &&
                vals[1] == BertTerm::Atom("hgtg".to_string())
        }
        _ => false
    });
}
<commit_msg>Remove a f64 transmute<commit_after>extern crate ppbert;
extern crate num;

use num::bigint;
use num::bigint::ToBigInt;

use ppbert::parser;
use ppbert::bertterm::BertTerm;
use ppbert::error::{BertError, Result};

fn p(bytes: &[u8]) -> Result<BertTerm> {
    let mut parser = parser::Parser::new(bytes.to_vec());
    parser.parse()
}

#[test]
fn magic_number() {
    assert!(p(&[131, 97, 0]).is_ok());
    assert!(p(&[130, 97, 0]).is_err());
    assert!(match p(&[130, 97, 0]) {
        Err(BertError::InvalidMagicNumber(_)) => true,
        _ => false
    });
}

#[test]
fn consume_all() {
    let extra: u8 = 42;
    assert!(p(&[131, 97, 0, extra]).is_err());
}

#[test]
fn small_integer() {
    for i in 0 .. 255_u8 {
        assert!(match p(&[131, 97, i]) {
            Ok(BertTerm::Int(j)) => i as i32 == j,
            _ => false
        });
    }
}

#[test]
fn integer() {
    for i in 0 .. 255_u8 {
        assert!(match p(&[131, 98, 0, 0, 0, i]) {
            Ok(BertTerm::Int(j)) => j == i as i32,
            _ => false
        });

            assert!(match p(&[131, 98, 0, 0, i, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 8,
            _ => false
        });

            assert!(match p(&[131, 98, 0, i, 0, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 16,
            _ => false
        });

            assert!(match p(&[131, 98, i, 0, 0, 0]) {
            Ok(BertTerm::Int(j)) => j == (i as i32) << 24,
            _ => false
        });
    }
}

#[test]
fn old_float() {
    assert!(match p(b"\x83\x6398.5\x00") {
        Ok(BertTerm::Float(f)) => f == 98.5,
        _ => false
    });

    assert!(match p(b"\x83\x63-23.5") {
        Ok(BertTerm::Float(f)) => f == -23.5,
        _ => false
    });

    assert!(p(b"\x83\x63abc").is_err());
}

#[test]
fn new_float() {
    let pi: f64 = 3.141592;
    let float_as_u64: u64 = pi.to_bits();
    let bytes = &[
        131, 70,
        (float_as_u64 >> 56) as u8 & 0xff_u8,
        (float_as_u64 >> 48) as u8 & 0xff_u8,
        (float_as_u64 >> 40) as u8 & 0xff_u8,
        (float_as_u64 >> 32) as u8 & 0xff_u8,
        (float_as_u64 >> 24) as u8 & 0xff_u8,
        (float_as_u64 >> 16) as u8 & 0xff_u8,
        (float_as_u64 >> 8) as u8 & 0xff_u8,
        (float_as_u64 >> 0) as u8 & 0xff_u8
    ];
    assert!(match p(bytes) {
        Ok(BertTerm::Float(x)) => x == 3.141592,
        _ => false
    });
}

#[test]
fn atom() {
    // 2-byte atom
    assert!(match p(b"\x83\x64\x00\x04abcd") {
        Ok(BertTerm::Atom(ref s)) => s == "abcd",
        _ => false
    });

    // 1-byte atom
    assert!(match p(b"\x83\x73\x04abcd") {
        Ok(BertTerm::Atom(ref s)) => s == "abcd",
        _ => false
    });

    assert!(match p(b"\x83\x73\x04abc") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });

    assert!(match p(b"\x83\x73\x03abcd") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // latin1 (0xe9 = é)
    assert!(match p(b"\x83\x64\x00\x04caf\xe9") {
        Ok(BertTerm::Atom(ref s)) => s == "café",
        _ => false
    });

    assert!(match p(b"\x83\x73\x04caf\xe9") {
        Ok(BertTerm::Atom(ref s)) => s == "café",
        _ => false
    });
}

#[test]
fn atom_utf8() {
    let atom_name = "jérôme";
    let atom_bytes = atom_name.to_string().into_bytes();

    // 2-byte UTF-8 atom
    let mut bert: Vec<u8> = vec![131, 118, 0, atom_bytes.len() as u8];
    bert.extend(&atom_bytes);
    assert!(match p(&bert) {
        Ok(BertTerm::Atom(ref s)) => s == atom_name,
        _ => false
    });

    // 1-byte UTF-8 atom
    let mut bert: Vec<u8> = vec![131, 119, atom_bytes.len() as u8];
    bert.extend(&atom_bytes);
    assert!(match p(&bert) {
        Ok(BertTerm::Atom(ref s)) => s == atom_name,
        _ => false
    });

    // Not enough data
    let mut bert: Vec<u8> = vec![131, 119, (atom_bytes.len() + 1) as u8];
    bert.extend(&atom_bytes);
    println!("{:?}", bert);
    assert!(match p(&bert) {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });

    // Too much data
    let mut bert: Vec<u8> = vec![131, 119, (atom_bytes.len() - 1) as u8];
    bert.extend(&atom_bytes);
    println!("{:?}", bert);
    assert!(match p(&bert) {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });
}

#[test]
fn string() {
    assert!(match p(b"\x83\x6b\x00\x06foobar") {
        Ok(BertTerm::String(ref s)) => s == b"foobar",
        _ => false
    });

    // too many characters
    assert!(match p(b"\x83\x6b\x00\x02foo") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // not enough characters
    assert!(match p(b"\x83\x6b\x00\x04foo") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });
}

#[test]
fn binary() {
    assert!(match p(b"\x83\x6d\x00\x00\x00\x06foobar") {
        Ok(BertTerm::Binary(ref s)) => s == b"foobar",
        _ => false
    });

    // too many characters
    assert!(match p(b"\x83\x6d\x00\x00\x00\x02foo") {
        Err(BertError::ExtraData(_)) => true,
        _ => false
    });

    // not enough characters
    assert!(match p(b"\x83\x6d\x00\x00\x00\x04foo") {
        Err(BertError::NotEnoughData { .. }) => true,
        _ => false
    });
}

#[test]
fn nil() {
    assert!(match p(b"\x83\x6a") {
        Ok(BertTerm::Nil) => true,
        _ => false
    });
}

#[test]
fn list() {
    use ppbert::bertterm::BertTerm::*;
    // proper list
    let b = &[
        131, 108, 0, 0, 0, 4,        // four elements
        97, 16,                      // small int (16)
        98, 0, 0, 255, 255,          // int (65535)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
        107, 0, 3, b'd', b'e', b'f', // string (def)
        106                          // tail
    ];
    match p(b) {
        Ok(List(ref terms)) => {
            assert_eq!(4, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Int(0xffff) => true,
                _ => false
            });
            assert!(match terms[2] {
                Atom(ref s) => s == "abc",
                _ => false
            });
            assert!(match terms[3] {
                String(ref s) => s == b"def",
                _ => false
            });
        }
        _ => assert!(false)
    };

    // improper list
    let b = &[
        131, 108, 0, 0, 0, 4,        // four elements
        97, 16,                      // small int (16)
        98, 0, 0, 255, 255,          // int (65535)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
        107, 0, 3, b'd', b'e', b'f', // string (def)
        107, 0, 3, b'g', b'h', b'i'  // tail
    ];
    match p(b) {
        Ok(List(ref terms)) => {
            assert_eq!(5, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Int(0xffff) => true,
                _ => false
            });
            assert!(match terms[2] {
                Atom(ref s) => s == "abc",
                _ => false
            });
            assert!(match terms[3] {
                String(ref s) => s == b"def",
                _ => false
            });
            assert!(match terms[4] {
                String(ref s) => s == b"ghi",
                _ => false
            });
        }
        _ => assert!(false)
    };
}

#[test]
fn tuple() {
    use ppbert::bertterm::BertTerm::*;

    // small
    let b = &[
        131, 104, 2,                 // two elements
        97, 16,                      // small int (16)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
    ];

    match p(b) {
        Ok(Tuple(ref terms)) => {
            assert_eq!(2, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Atom(ref s) => s == "abc",
                _ => false
            });
        }
        _ => assert!(false)
    };

    // large
    let b = &[
        131, 105, 0, 0, 0, 2,        // two elements
        97, 16,                      // small int (16)
        100, 0, 3, b'a', b'b', b'c', // atom (abc)
    ];

    match p(b) {
        Ok(Tuple(ref terms)) => {
            assert_eq!(2, terms.len());
            assert!(match terms[0] {
                Int(16) => true,
                _ => false
            });
            assert!(match terms[1] {
                Atom(ref s) => s == "abc",
                _ => false
            });
        }
        e => { println!("{:?}", e); assert!(false) }
    };
}

#[test]
fn bigint() {
    // small
    assert!(match p(&[131, 110, 1, 1, 10]) {
        Ok(BertTerm::BigInt(b)) => b == (-10).to_bigint().unwrap(),
        e => { println!("{:?}", e); false }
    });

    // large
    assert!(match p(&[131, 111, 0, 0, 0, 1, 0, 42]) {
        Ok(BertTerm::BigInt(b)) => b == (42).to_bigint().unwrap(),
        e => { println!("{:?}", e); false }
    });
}

#[test]
fn map() {
    let binary = &[
        131,
        116,
        0, 0, 0, 2, // two keys and values
        97, 0,      // keys[0] == 0
        100, 0, 4, b'z', b'e', b'r', b'o',
        97, 42,     // keys[1] == 42
        100, 0, 4, b'h', b'g', b't', b'g'
    ];
    assert!(match p(binary) {
        Ok(BertTerm::Map(ref keys, ref vals)) => {
            keys[0] == BertTerm::Int(0) &&
                keys[1] == BertTerm::Int(42) &&
                vals[0] == BertTerm::Atom("zero".to_string()) &&
                vals[1] == BertTerm::Atom("hgtg".to_string())
        }
        _ => false
    });
}
<|endoftext|>


<commit_before>use serde_json;

use errors::wallet::WalletError;

use super::WalletRecord;
use super::wallet::Keys;
use super::storage::StorageIterator;
use super::encryption::{decrypt_tags};
use utils::crypto::chacha20poly1305_ietf::ChaCha20Poly1305IETF;

pub(super) struct WalletIterator {
    storage_iterator: Box<StorageIterator>,
    keys: Keys,
}

impl WalletIterator {
    pub fn new(storage_iter: Box<StorageIterator>, keys: &Keys) -> Self {
        WalletIterator {
            storage_iterator: storage_iter,
            keys: keys.clone(),
        }
    }

    pub fn next(&mut self) -> Result<Option<WalletRecord>, WalletError> {
        let next_storage_entity = self.storage_iterator.next()?;
        if let Some(next_storage_entity) = next_storage_entity {
            let decrypted_name = ChaCha20Poly1305IETF::decrypt(&next_storage_entity.name, &self.keys.name_key)?;
            let name = String::from_utf8(decrypted_name)?;

            let value = match next_storage_entity.value {
                None => None,
                Some(encrypted_value) => Some(encrypted_value.decrypt(&self.keys.value_key)?)
            };

            let tags = match decrypt_tags(&next_storage_entity.tags, &self.keys.tag_name_key, &self.keys.tag_value_key)? {
                None => None,
                Some(tags) => Some(serde_json::to_string(&tags)?)
            };

            Ok(Some(WalletRecord::new(name, None, value, tags)))
        } else { Ok(None) }
    }
}<commit_msg>Add TODO about keys copy.<commit_after>use serde_json;

use errors::wallet::WalletError;

use super::WalletRecord;
use super::wallet::Keys;
use super::storage::StorageIterator;
use super::encryption::{decrypt_tags};
use utils::crypto::chacha20poly1305_ietf::ChaCha20Poly1305IETF;

pub(super) struct WalletIterator {
    storage_iterator: Box<StorageIterator>,
    keys: Keys,
}

impl WalletIterator {
    pub fn new(storage_iter: Box<StorageIterator>, keys: &Keys) -> Self {
        WalletIterator {
            storage_iterator: storage_iter,
            keys: keys.clone() /* TODO FIXME: Avoid clone, especially for sensitive information. */,
        }
    }

    pub fn next(&mut self) -> Result<Option<WalletRecord>, WalletError> {
        let next_storage_entity = self.storage_iterator.next()?;
        if let Some(next_storage_entity) = next_storage_entity {
            let decrypted_name = ChaCha20Poly1305IETF::decrypt(&next_storage_entity.name, &self.keys.name_key)?;
            let name = String::from_utf8(decrypted_name)?;

            let value = match next_storage_entity.value {
                None => None,
                Some(encrypted_value) => Some(encrypted_value.decrypt(&self.keys.value_key)?)
            };

            let tags = match decrypt_tags(&next_storage_entity.tags, &self.keys.tag_name_key, &self.keys.tag_value_key)? {
                None => None,
                Some(tags) => Some(serde_json::to_string(&tags)?)
            };

            Ok(Some(WalletRecord::new(name, None, value, tags)))
        } else { Ok(None) }
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use futures::{future::try_join_all, lock::Mutex, TryFutureExt};
use iml_action_client::invoke_rust_agent;
use iml_postgres::{
    get_db_pool,
    sqlx::{self, Done, Executor, PgPool},
};
use iml_tracing::tracing;
use iml_wire_types::{
    db::{FidTaskQueue, LustreFid},
    AgentResult, FidError, FidItem, LustreClient, Task, TaskAction,
};
use std::{
    collections::{HashMap, HashSet},
    str::FromStr,
    sync::Arc,
    time::Duration,
};
use tokio::time;

pub mod error;

// Number of fids to chunk together
const FID_LIMIT: i64 = 2000;
// Number of seconds between cycles
const DELAY: Duration = Duration::from_secs(5);

async fn available_workers(
    pool: &PgPool,
    active: Arc<Mutex<HashSet<i32>>>,
) -> Result<Vec<LustreClient>, error::ImlTaskRunnerError> {
    let ids = active.lock().await;
    let ids: Vec<i32> = ids.iter().copied().collect();

    let clients = sqlx::query_as!(
        LustreClient,
        r#"
        SELECT * FROM chroma_core_lustreclientmount
        WHERE
            state = 'mounted'
            AND not_deleted = 't'
            AND id != ALL($1)
        "#,
        &ids
    )
    .fetch_all(pool)
    .await?;

    Ok(clients)
}

async fn tasks_per_worker(
    pool: &PgPool,
    worker: &LustreClient,
) -> Result<Vec<Task>, error::ImlTaskRunnerError> {
    let fs_id = sqlx::query!(
        "select id from chroma_core_managedfilesystem where name = $1 and not_deleted = 't'",
        &worker.filesystem
    )
    .fetch_optional(pool)
    .await?
    .map(|x| x.id);

    let fs_id = match fs_id {
        Some(x) => x,
        None => return Ok(vec![]),
    };

    let tasks = sqlx::query_as!(
        Task,
        r#"
        select * from chroma_core_task
        where
            filesystem_id = $1
            and state <> 'closed'
            and fids_total > fids_completed
            and (running_on_id is Null or running_on_id = $2)"#,
        fs_id,
        worker.host_id
    )
    .fetch_all(pool)
    .await?;

    Ok(tasks)
}

async fn worker_fqdn(
    pool: &PgPool,
    worker: &LustreClient,
) -> Result<String, error::ImlTaskRunnerError> {
    let fqdn = sqlx::query!(
        "SELECT fqdn FROM chroma_core_managedhost WHERE id = $1",
        worker.host_id
    )
    .fetch_one(pool)
    .await
    .map(|x| x.fqdn)?;

    Ok(fqdn)
}

async fn send_work(
    pg_pool: &PgPool,
    fqdn: &str,
    fsname: &str,
    task: &Task,
    host_id: i32,
) -> Result<i64, error::ImlTaskRunnerError> {
    let taskargs: HashMap<String, String> = serde_json::from_value(task.args.clone())?;

    // Setup running_on if unset
    if task.single_runner && task.running_on_id.is_none() {
        tracing::debug!(
            "Attempting to Set Task {} ({}) running_on to host {} ({})",
            task.name,
            task.id,
            fqdn,
            host_id
        );

        let cnt = sqlx::query!(
            r#"
            UPDATE chroma_core_task
            SET running_on_id = $1
                WHERE id = $2
                AND running_on_id is Null"#,
            host_id,
            task.id
        )
        .execute(pg_pool)
        .await?
        .rows_affected();

        if cnt == 1 {
            tracing::info!(
                "Set Task {} ({}) running on host {} ({})",
                task.name,
                task.id,
                fqdn,
                host_id
            );
        } else {
            tracing::debug!(
                "Failed to Set Task {} running_on to host {}: {}",
                task.name,
                fqdn,
                cnt
            );

            return Ok(0);
        }
    }

    tracing::debug!("send_work({}, {}, {})", fqdn, fsname, task.name);

    let mut trans = pg_pool.begin().await?;

    let rowlist = sqlx::query_as!(
        FidTaskQueue,
        r#"
        DELETE FROM chroma_core_fidtaskqueue
        WHERE id in (
            SELECT id FROM chroma_core_fidtaskqueue WHERE task_id = $1 LIMIT $2 FOR UPDATE SKIP LOCKED
        ) RETURNING id, fid as "fid: _", data, task_id"#,
        task.id, FID_LIMIT,
    )
        .fetch_all(&mut trans)
        .await?;

    tracing::debug!(
        "send_work({}, {}, {}) found {} fids",
        fqdn,
        fsname,
        task.name,
        rowlist.len()
    );

    if rowlist.is_empty() {
        return trans.commit().map_ok(|_| 0).err_into().await;
    }

    let fidlist: Vec<FidItem> = rowlist
        .into_iter()
        .map(|ft| FidItem {
            fid: ft.fid.to_string(),
            data: ft.data,
        })
        .collect();

    let completed = fidlist.len();
    let mut failed = 0;
    let args = TaskAction(fsname.to_string(), taskargs, fidlist);

    // send fids to actions runner
    // action names on Agents are "action.ACTION_NAME"
    for action in task.actions.iter().map(|a| format!("action.{}", a)) {
        match invoke_rust_agent(fqdn, &action, &args).await {
            Err(e) => {
                tracing::info!("Failed to send {} to {}: {:?}", &action, fqdn, e);
                return trans.rollback().map_ok(|_| 0).err_into().await;
            }
            Ok(res) => {
                let agent_result: AgentResult = serde_json::from_value(res)?;
                match agent_result {
                    Ok(data) => {
                        tracing::debug!("Success {} on {}: {:?}", &action, fqdn, data);
                        let errors: Vec<FidError> = serde_json::from_value(data)?;
                        failed += errors.len();

                        if task.keep_failed {
                            let task_id = task.id;
                            for err in errors.iter() {
                                let fid = LustreFid::from_str(&err.fid)
                                    .expect("FIXME: This needs proper error handling");

                                // #FIXME: This would be better as a bulk insert
                                if let Err(e) = trans
                                    .execute(
                                        sqlx::query!(
                                            r#"
                                                INSERT INTO chroma_core_fidtaskerror (fid, task_id, data, errno)
                                                VALUES ($1, $2, $3, $4)"#,
                                            fid as LustreFid,
                                            task_id,
                                            err.data,
                                            err.errno
                                        )
                                    )
                                    .await
                                {
                                    tracing::info!(
                                        "Failed to insert fid error ({} : {}): {}",
                                        err.fid,
                                        err.errno,
                                        e
                                    );
                                }
                            }
                        }
                    }
                    Err(err) => {
                        tracing::info!("Failed {} on {}: {}", &action, fqdn, err);
                        return trans.rollback().map_ok(|_| 0).err_into().await;
                    }
                }
            }
        }
    }

    trans.commit().await?;

    if completed > 0 || failed > 0 {
        sqlx::query!(
            r#"
            UPDATE chroma_core_task
            SET
                fids_completed = fids_completed + $1,
                fids_failed = fids_failed + $2
            WHERE id = $3"#,
            completed as i64,
            failed as i64,
            task.id
        )
        .execute(pg_pool)
        .await?;
    }

    Ok(completed as i64)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    iml_tracing::init();

    let pg_pool = get_db_pool(5).await?;
    let active_clients = Arc::new(Mutex::new(HashSet::new()));
    let mut interval = time::interval(DELAY);

    // Task Runner Loop
    loop {
        interval.tick().await;

        let workers = available_workers(&pg_pool, Arc::clone(&active_clients))
            .await
            .unwrap_or_default();

        active_clients
            .lock()
            .await
            .extend(workers.iter().map(|w| w.id));

        tokio::spawn({
            try_join_all(workers.into_iter().map(|worker| {
                let pg_pool = pg_pool.clone();
                let active_clients = Arc::clone(&active_clients);

                async move {
                    let tasks = tasks_per_worker(&pg_pool, &worker).await?;
                    let fqdn = worker_fqdn(&pg_pool, &worker).await?;
                    let host_id = worker.host_id;

                    let rc = try_join_all(tasks.into_iter().map(|task| {
                        let pg_pool = pg_pool.clone();
                        let fsname = &worker.filesystem;
                        let fqdn = &fqdn;

                        async move {
                            let mut count = 0;

                            loop {
                                let rc = send_work(&pg_pool, &fqdn, &fsname, &task, host_id)
                                    .await
                                    .map_err(|e| {
                                        tracing::warn!("send_work({}) failed {:?}", task.name, e);
                                        e
                                    })?;

                                count += 1;

                                if rc < FID_LIMIT || count > 10 {
                                    break;
                                }
                            }

                            Ok::<_, error::ImlTaskRunnerError>(())
                        }
                    }))
                    .await;

                    active_clients.lock().await.remove(&worker.id);

                    rc
                }
            }))
        });
    }
}
<commit_msg>Ensure active_workers are released (#2155)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use futures::{future::join_all, lock::Mutex, FutureExt, TryFutureExt};
use iml_action_client::invoke_rust_agent;
use iml_postgres::{
    get_db_pool,
    sqlx::{self, pool::PoolConnection, Done, Executor, PgPool, Postgres},
};
use iml_tracing::tracing;
use iml_wire_types::{
    db::{FidTaskQueue, LustreFid},
    AgentResult, FidError, FidItem, LustreClient, Task, TaskAction,
};
use std::{
    collections::{HashMap, HashSet},
    str::FromStr,
    sync::Arc,
    time::Duration,
};
use tokio::time;

pub mod error;

// Number of fids to chunk together
const FID_LIMIT: i64 = 2000;
// Number of seconds between cycles
const DELAY: Duration = Duration::from_secs(5);

async fn available_workers(
    conn: &mut PoolConnection<Postgres>,
    active: Arc<Mutex<HashSet<i32>>>,
) -> Result<Vec<LustreClient>, error::ImlTaskRunnerError> {
    let ids = active.lock().await;
    let ids: Vec<i32> = ids.iter().copied().collect();

    let clients = sqlx::query_as!(
        LustreClient,
        r#"
        SELECT * FROM chroma_core_lustreclientmount
        WHERE
            state = 'mounted'
            AND not_deleted = 't'
            AND id != ALL($1)
        "#,
        &ids
    )
    .fetch_all(conn)
    .await?;

    Ok(clients)
}

async fn tasks_per_worker(
    pool: &PgPool,
    worker: &LustreClient,
) -> Result<Vec<Task>, error::ImlTaskRunnerError> {
    let fs_id = sqlx::query!(
        "select id from chroma_core_managedfilesystem where name = $1 and not_deleted = 't'",
        &worker.filesystem
    )
    .fetch_optional(pool)
    .await?
    .map(|x| x.id);

    let fs_id = match fs_id {
        Some(x) => x,
        None => return Ok(vec![]),
    };

    let tasks = sqlx::query_as!(
        Task,
        r#"
        select * from chroma_core_task
        where
            filesystem_id = $1
            and state <> 'closed'
            and fids_total > fids_completed
            and (running_on_id is Null or running_on_id = $2)"#,
        fs_id,
        worker.host_id
    )
    .fetch_all(pool)
    .await?;

    Ok(tasks)
}

async fn worker_fqdn(
    pool: &PgPool,
    worker: &LustreClient,
) -> Result<String, error::ImlTaskRunnerError> {
    let fqdn = sqlx::query!(
        "SELECT fqdn FROM chroma_core_managedhost WHERE id = $1",
        worker.host_id
    )
    .fetch_one(pool)
    .await
    .map(|x| x.fqdn)?;

    Ok(fqdn)
}

async fn send_work(
    pg_pool: &PgPool,
    fqdn: &str,
    fsname: &str,
    task: &Task,
    host_id: i32,
) -> Result<i64, error::ImlTaskRunnerError> {
    let taskargs: HashMap<String, String> = serde_json::from_value(task.args.clone())?;

    // Setup running_on if unset
    if task.single_runner && task.running_on_id.is_none() {
        tracing::debug!(
            "Attempting to Set Task {} ({}) running_on to host {} ({})",
            task.name,
            task.id,
            fqdn,
            host_id
        );

        let cnt = sqlx::query!(
            r#"
            UPDATE chroma_core_task
            SET running_on_id = $1
                WHERE id = $2
                AND running_on_id is Null"#,
            host_id,
            task.id
        )
        .execute(pg_pool)
        .await?
        .rows_affected();

        if cnt == 1 {
            tracing::info!(
                "Set Task {} ({}) running on host {} ({})",
                task.name,
                task.id,
                fqdn,
                host_id
            );
        } else {
            tracing::debug!(
                "Failed to Set Task {} running_on to host {}: {}",
                task.name,
                fqdn,
                cnt
            );

            return Ok(0);
        }
    }

    tracing::debug!("send_work({}, {}, {})", fqdn, fsname, task.name);

    let mut trans = pg_pool.begin().await?;

    let rowlist = sqlx::query_as!(
        FidTaskQueue,
        r#"
        DELETE FROM chroma_core_fidtaskqueue
        WHERE id in (
            SELECT id FROM chroma_core_fidtaskqueue WHERE task_id = $1 LIMIT $2 FOR UPDATE SKIP LOCKED
        ) RETURNING id, fid as "fid: _", data, task_id"#,
        task.id, FID_LIMIT,
    )
        .fetch_all(&mut trans)
        .await?;

    tracing::debug!(
        "send_work({}, {}, {}) found {} fids",
        fqdn,
        fsname,
        task.name,
        rowlist.len()
    );

    if rowlist.is_empty() {
        return trans.commit().map_ok(|_| 0).err_into().await;
    }

    let fidlist: Vec<FidItem> = rowlist
        .into_iter()
        .map(|ft| FidItem {
            fid: ft.fid.to_string(),
            data: ft.data,
        })
        .collect();

    let completed = fidlist.len();
    let mut failed = 0;
    let args = TaskAction(fsname.to_string(), taskargs, fidlist);

    // send fids to actions runner
    // action names on Agents are "action.ACTION_NAME"
    for action in task.actions.iter().map(|a| format!("action.{}", a)) {
        match invoke_rust_agent(fqdn, &action, &args).await {
            Err(e) => {
                tracing::info!("Failed to send {} to {}: {:?}", &action, fqdn, e);

                return trans.rollback().map_ok(|_| 0).err_into().await;
            }
            Ok(res) => {
                let agent_result: AgentResult = serde_json::from_value(res)?;

                match agent_result {
                    Ok(data) => {
                        tracing::debug!("Success {} on {}: {:?}", action, fqdn, data);

                        let errors: Vec<FidError> = serde_json::from_value(data)?;
                        failed += errors.len();

                        if task.keep_failed {
                            let task_id = task.id;

                            for err in errors.iter() {
                                let fid = match LustreFid::from_str(&err.fid) {
                                    Ok(x) => x,
                                    Err(e) => {
                                        tracing::info!("Could not convert FidError {:?} to LustreFid. Error: {:?}", err, e);
                                        continue;
                                    }
                                };

                                // #FIXME: This would be better as a bulk insert
                                if let Err(e) = trans
                                    .execute(
                                        sqlx::query!(
                                            r#"
                                                INSERT INTO chroma_core_fidtaskerror (fid, task_id, data, errno)
                                                VALUES ($1, $2, $3, $4)"#,
                                            fid as LustreFid,
                                            task_id,
                                            err.data,
                                            err.errno
                                        )
                                    )
                                    .await
                                {
                                    tracing::info!(
                                        "Failed to insert fid error ({} : {}): {}",
                                        err.fid,
                                        err.errno,
                                        e
                                    );
                                }
                            }
                        }
                    }
                    Err(err) => {
                        tracing::info!("Failed {} on {}: {}", &action, fqdn, err);

                        return trans.rollback().map_ok(|_| 0).err_into().await;
                    }
                }
            }
        }
    }

    trans.commit().await?;

    if completed > 0 || failed > 0 {
        sqlx::query!(
            r#"
            UPDATE chroma_core_task
            SET
                fids_completed = fids_completed + $1,
                fids_failed = fids_failed + $2
            WHERE id = $3"#,
            completed as i64,
            failed as i64,
            task.id
        )
        .execute(pg_pool)
        .await?;
    }

    Ok(completed as i64)
}

async fn run_tasks(fqdn: &str, worker: &LustreClient, xs: Vec<Task>, pool: &PgPool) {
    let fsname = &worker.filesystem;
    let host_id = worker.host_id;

    let xs = xs.into_iter().map(|task| async move {
        for _ in 0..10_u8 {
            let rc = send_work(&pool, &fqdn, &fsname, &task, host_id)
                .inspect_err(|e| tracing::warn!("send_work({}) failed {:?}", task.name, e))
                .await?;

            if rc < FID_LIMIT {
                break;
            }
        }

        Ok::<_, error::ImlTaskRunnerError>(())
    });

    join_all(xs).await;
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    iml_tracing::init();

    let pg_pool = get_db_pool(5).await?;
    let active_clients = Arc::new(Mutex::new(HashSet::new()));
    let mut interval = time::interval(DELAY);

    // Task Runner Loop
    loop {
        interval.tick().await;

        let mut conn = match pg_pool.try_acquire() {
            Some(x) => x,
            None => {
                tracing::info!(
                    "Could not acquire connection (pool full), will try again next tick"
                );
                continue;
            }
        };

        let workers = available_workers(&mut conn, Arc::clone(&active_clients)).await?;
        drop(conn);

        {
            let mut x = active_clients.lock().await;

            x.extend(workers.iter().map(|w| w.id));

            tracing::debug!("Active Clients {:?}", x);
        }

        let xs = workers.into_iter().map(|worker| {
            let pg_pool = pg_pool.clone();
            let active_clients = Arc::clone(&active_clients);
            let active_clients2 = Arc::clone(&active_clients);
            let worker_id = worker.id;

            async move {
                let tasks = tasks_per_worker(&pg_pool, &worker).await?;
                let fqdn = worker_fqdn(&pg_pool, &worker).await?;

                run_tasks(&fqdn, &worker, tasks, &pg_pool).await;

                Ok::<_, error::ImlTaskRunnerError>(())
            }
            .then(move |x| async move {
                let mut c = active_clients2.lock().await;

                c.remove(&worker_id);

                tracing::debug!("Releasing Client {:?}. Active Clients {:?}", worker_id, c);

                x
            })
        });

        tokio::spawn(join_all(xs));
    }
}
<|endoftext|>