<commit_before>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

#[license = "BSD"];

#[allow(deprecated_owned_vector)];
#[allow(dead_code)];

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use num::complex::{Cmplx, Complex64};

use std::num::{sin};

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

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

static vertex_shader_source: &'static str = "

#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

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

static fragment_shader_source: &'static str = "

#version 150

in vec3 Color;
out vec4 outColor;

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

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

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

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

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
        };

        let (width, height) =  wc.window.get_framebuffer_size();

        gl2::viewport(0, 0, width as i32, height as i32);

        println!("Viewport: {} x {}", width, height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create v.shader failed");
        }

        gl2::shader_source(wc.vertex_shader, [vertex_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.v err 0x{:x}", err);
        }

        gl2::compile_shader(wc.vertex_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.f err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            fail!("glCompileShader.v err 0x{:x}: {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create f.shader failed");
        }

        gl2::shader_source(wc.fragment_shader, [fragment_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.f -> 0x{:x}", err);
        }

        gl2::compile_shader(wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.v err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            fail!("glCompileShader.f err 0x{:x}: {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        if wc.shader_program == 0 {
            fail!("glCreateProgram failed");
        }

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glAttachShader err 0x{:x}", err);
        }

        gl2::link_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glLinkProgram err 0x{:x}", err);
        }

        let status = gl2::get_program_iv(wc.shader_program, gl2::LINK_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.shader_program);
            fail!("glLinkProgram err {}: {}", status, log);
        }

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            let log = gl2::get_program_info_log(wc.shader_program);
            fail!("glUseProgram error: {}", log);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            fail!("attrib err = {:x}", err);
        }

        wc
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
        gl2::uniform_3f(self.uni_color, (sin(time * 4.0f32 as f64) as f32 + 1.0f32) / 2.0f32, 0.0f32, 0.0f32);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {

            glfw::CloseEvent => println!("Time: {}, Window close requested.", time),

            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

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

struct MandelEngine {
    re0: f32,
    re1: f32,
    im0: f32,
    im1: f32,
    delta: f32,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { re0: -2.0, re1: 2.0, im0: -2.0, im1: 2.0, delta: 0.1 }
    }

    // Evalute entire region
    fn process(&self) {
        println!("+++ process: re: {}..{} im: {}..{}", self.re0, self.re1, self.im0, self.im1);
        // @todo range_step doesn't work for floats :( It needs CheckedAdd for f32. So we do loops manually.
        let mut re = self.re0;
        while re < self.re1 {
            let mut im = self.im0;
            while im < self.im1 {
                let z = Cmplx::new(re as f64, im as f64);
                println!("z={}+{}i, c={}", re, im, self.mandel(z));
                im += self.delta;
            }
            re += self.delta;
        }
        println!("--- process");
    }

    // Evaluate a single point
    fn mandel(&self, z: Complex64) -> uint {
        let maxiter: uint = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

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

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        let engine = MandelEngine::new();
        native::task::spawn( proc() { engine.process(); });

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
            win_ctrl.draw();
        }
    });
}
<commit_msg>Add start of Escape Time Algorithm<commit_after>//============================================================================
//
// A simple Mandelbrot image generator in Rust
//
// Copyright (c) 2014 Gavin Baker <gavinb@antonym.org>
// Published under the MIT license
//
// Packages required:
//
// - OpenGLES
// - GLFW
// - cgmath
//
//============================================================================

#[license = "BSD"];

#[allow(deprecated_owned_vector)];
#[allow(dead_code)];

extern crate native;
extern crate num;

extern crate opengles;
extern crate glfw;
extern crate cgmath;

use opengles::gl2;

use cgmath::vector::Vec3;
use cgmath::aabb::Aabb3;

use num::complex::{Cmplx, Complex64};

use std::num::{sin};

type Vec3f = Vec3<f32>;
type AABB3f = Aabb3<f32>;

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

static vertex_shader_source: &'static str = "

#version 150

in vec2 position;
in vec3 color;

out vec3 Color;

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

static fragment_shader_source: &'static str = "

#version 150

in vec3 Color;
out vec4 outColor;

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

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

struct ErrorContext;
impl glfw::ErrorCallback for ErrorContext {
    fn call(&self, _: glfw::Error, description: ~str) {
        println!("GLFW Error: {:s}", description);
    }
}

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

struct WindowController<'a> {
    window: &'a glfw::Window,
    vertices: ~[f32],
    vao: ~[gl2::GLuint],
    vbo: ~[gl2::GLuint],
    vertex_shader: gl2::GLuint,
    fragment_shader: gl2::GLuint,
    shader_program: gl2::GLuint,
    uni_color: gl2::GLint,
    buffer_width: uint,
    buffer_height: uint,
}

impl<'a> WindowController<'a> {
    fn new(window: &'a glfw::Window) -> WindowController<'a> {
        let mut wc = WindowController { window: window,
                                        vao: ~[0],
                                        vbo: ~[0],
                                        vertices: ~[],
                                        vertex_shader: 0,
                                        fragment_shader: 0,
                                        shader_program: 0,
                                        uni_color: 0,
                                        buffer_width: 0,
                                        buffer_height: 0,
        };

        let (w, h) =  wc.window.get_framebuffer_size();
        wc.buffer_width = w as uint;
        wc.buffer_height = h as uint;

        gl2::viewport(0, 0, wc.buffer_width as i32, wc.buffer_height as i32);

        println!("Viewport: {} x {}", wc.buffer_width, wc.buffer_height);

        wc.vertices = ~[
            0.0,  0.5, 1.0, 0.0, 0.0,
            0.5, -0.5, 0.0, 1.0, 0.0,
            -0.5, -0.5, 0.0, 0.0, 1.0,
            ];

        // VAO

        wc.vao = gl2::gen_vertex_arrays(1);
        gl2::bind_vertex_array(wc.vao[0]);

        // VBO

        wc.vbo = gl2::gen_buffers(1);
        gl2::bind_buffer(gl2::ARRAY_BUFFER, wc.vbo[0]);
        gl2::buffer_data(gl2::ARRAY_BUFFER, wc.vertices, gl2::STATIC_DRAW);

        // Vertex Shader

        wc.vertex_shader = gl2::create_shader(gl2::VERTEX_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create v.shader failed");
        }

        gl2::shader_source(wc.vertex_shader, [vertex_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.v err 0x{:x}", err);
        }

        gl2::compile_shader(wc.vertex_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.f err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.vertex_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.vertex_shader);
            fail!("glCompileShader.v err 0x{:x}: {}", status, log);
        }

        // Fragment Shader

        wc.fragment_shader = gl2::create_shader(gl2::FRAGMENT_SHADER);

        if wc.vertex_shader == 0 {
            fail!("Create f.shader failed");
        }

        gl2::shader_source(wc.fragment_shader, [fragment_shader_source.to_owned().as_bytes()]);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glShaderSource.f -> 0x{:x}", err);
        }

        gl2::compile_shader(wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glCompileShader.v err 0x{:x}", err);
        }

        let status = gl2::get_shader_iv(wc.fragment_shader, gl2::COMPILE_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.fragment_shader);
            fail!("glCompileShader.f err 0x{:x}: {}", status, log);
        }

        // Link

        wc.shader_program = gl2::create_program();

        if wc.shader_program == 0 {
            fail!("glCreateProgram failed");
        }

        gl2::attach_shader(wc.shader_program, wc.vertex_shader);
        gl2::attach_shader(wc.shader_program, wc.fragment_shader);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glAttachShader err 0x{:x}", err);
        }

        gl2::link_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            fail!("glLinkProgram err 0x{:x}", err);
        }

        let status = gl2::get_program_iv(wc.shader_program, gl2::LINK_STATUS);

        if status != gl2::TRUE as i32 {
            let log = gl2::get_shader_info_log(wc.shader_program);
            fail!("glLinkProgram err {}: {}", status, log);
        }

        gl2::use_program(wc.shader_program);

        let err = gl2::get_error();
        if err != 0 {
            let log = gl2::get_program_info_log(wc.shader_program);
            fail!("glUseProgram error: {}", log);
        }

        // Attributes

        let pos_attrib = gl2::get_attrib_location(wc.shader_program, "position");
        gl2::enable_vertex_attrib_array(pos_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(pos_attrib as gl2::GLuint, 2, false, 5*4, 0);

        let col_attrib = gl2::get_attrib_location(wc.shader_program, "color");
        gl2::enable_vertex_attrib_array(col_attrib as gl2::GLuint);
        gl2::vertex_attrib_pointer_f32(col_attrib as gl2::GLuint, 3, false, 5*4, 2*4);

        // Uniforms

        wc.uni_color = gl2::get_uniform_location(wc.shader_program, "triangleColor");

        let err = gl2::get_error();
        if err != 0 {
            fail!("attrib err = {:x}", err);
        }

        wc
    }

    // Rescale pixel coord (x,y) into cspace
    fn scale_coords(&self, x: uint, y: uint) -> (f32, f32) {
        let x0 = -2.5f32;
        let x1 =  1.0f32;
        let y0 = -1.0f32;
        let y1 =  1.0f32;

        let xx = (x as f32) / (self.buffer_width  as f32) * (x1-x0) + x0;
        let yy = (y as f32) / (self.buffer_height as f32) * (y1-y0) + y0;

        (xx, yy)
    }

    fn draw(&self) {

        // Clear

        gl2::clear_color(0.4, 0.4, 0.4, 1.0);
        gl2::clear(gl2::COLOR_BUFFER_BIT);

        // Animate

        let time = glfw::get_time();
        gl2::uniform_3f(self.uni_color, (sin(time * 4.0f32 as f64) as f32 + 1.0f32) / 2.0f32, 0.0f32, 0.0f32);

        // Draw!

        gl2::draw_arrays(gl2::TRIANGLES, 0, 3);

        let err = gl2::get_error();
        if err != 0 {
            println!("draw err = 0x{:x}", err);
        }

        self.window.swap_buffers();
    }

    fn uninit(&mut self) {

        // Cleanup

        gl2::delete_program(self.shader_program);
        gl2::delete_shader(self.fragment_shader);
        gl2::delete_shader(self.vertex_shader);

        gl2::delete_buffers(self.vbo);

        // @todo Missing from bindings
        //gl2::delete_vertex_arrays(vao);
    }

    fn handle_window_event(&self, window: &glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
        match event {

            glfw::CloseEvent => println!("Time: {}, Window close requested.", time),

            glfw::KeyEvent(key, scancode, action, mods) => {
                println!("Time: {}, Key: {}, ScanCode: {}, Action: {}, Modifiers: [{}]", time, key, scancode, action, mods);
                match (key, action) {
                    (glfw::KeyEscape, glfw::Press) => window.set_should_close(true),
                    (glfw::KeyR, glfw::Press) => {
                        // Resize should cause the window to "refresh"
                        let (window_width, window_height) = window.get_size();
                        window.set_size(window_width + 1, window_height);
                        window.set_size(window_width, window_height);
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

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

struct MandelEngine {
    buffer_width: uint,
    buffer_height: uint,
}

impl MandelEngine {

    fn new() -> MandelEngine {
        MandelEngine { buffer_width: 640,
                       buffer_height: 480,
        }
    }

    // Rescale pixel coord (x,y) into cspace
    fn scale_coords(&self, x: uint, y: uint) -> (f32, f32) {
        let x0 = -2.5f32;
        let x1 =  1.0f32;
        let y0 = -1.0f32;
        let y1 =  1.0f32;

        let xx = (x as f32) / (self.buffer_width  as f32) * (x1-x0) + x0;
        let yy = (y as f32) / (self.buffer_height as f32) * (y1-y0) + y0;

        (xx, yy)
    }

    // Evalute entire region
    fn process(&self) {

        let max_iteration = 1000;

        println!("+++ process");

        // Process each pixel
        for py in range(0, self.buffer_height) {
            for px in range(0, self.buffer_width) {

                // Project pixels into Mandelbrot domain
                let (x0, y0) = self.scale_coords(px, py);

                println!("({},{}) -> ({}, {})", px, py, x0, y0);

                let mut x = 0.0f32;
                let mut y = 0.0f32;
                let mut iteration = 0;

                // Iterate!
                while (x*x + y*y < 2.0*2.0) && (iteration < max_iteration) {
                    let xtemp = x*x - y*y + x0;
                    y = 2.0*x*y + y0;
                    x = xtemp;

                    iteration += 1;
                }

                // Colour and plot
                //color = palette[iteration];
                //plot[px][py] = colour;
            }
        }

        println!("--- process");
    }

    // Evaluate a single point
    fn mandel(&self, z: Complex64) -> uint {
        let maxiter: uint = 80;
        let mut c: Complex64 = z;
        for n in range(0, maxiter) {
            if c.norm() > 2.0 {
                return n;
            }
            c = c*c+z;
        }
        return maxiter;
    }
}

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

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {

    println!("GLFW version: {:s}", glfw::get_version_string());

    glfw::start(proc() {

        glfw::window_hint::context_version_major(3);
        glfw::window_hint::context_version_minor(2);
        glfw::window_hint::opengl_forward_compat(true);
        glfw::window_hint::opengl_profile(glfw::OpenGlCoreProfile);
        glfw::window_hint::resizable(false);

        let window = glfw::Window::create(640, 480,
                                          "MandelRust",
                                          glfw::Windowed)
            .expect("Failed to create GLFW window.");

        window.make_context_current();

        let win_ctrl = ~WindowController::new(&window);

        let engine = MandelEngine::new();
        native::task::spawn( proc() { engine.process(); });

        while !window.should_close() {
            glfw::poll_events();
            for event in window.flush_events() {
                win_ctrl.handle_window_event(&window, event);
            }
            win_ctrl.draw();
        }
    });
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::io::{self, Write};

use rmp::encode::{write_nil, write_bool, write_uint, write_sint, write_f32, write_f64, write_str,
                  write_bin, write_array_len, write_map_len, write_ext_meta, ValueWriteError};

use Value;

#[derive(Debug)]
pub enum Error {
    /// I/O error while writing marker.
    InvalidMarkerWrite(io::Error),
    /// I/O error while writing data.
    InvalidDataWrite(io::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidMarkerWrite(..) => "invalid marker write",
            Error::InvalidDataWrite(..) => "invalid data write",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::InvalidMarkerWrite(ref err) => Some(err),
            Error::InvalidDataWrite(ref err) => Some(err),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        error::Error::description(self).fmt(f)
    }
}

impl From<ValueWriteError> for Error {
    fn from(err: ValueWriteError) -> Error {
        match err {
            ValueWriteError::InvalidMarkerWrite(err) => Error::InvalidMarkerWrite(err),
            ValueWriteError::InvalidDataWrite(err) => Error::InvalidDataWrite(err),
        }
    }
}

/// Encodes and attempts to write the most efficient representation of the given Value.
///
/// # Note
///
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
/// operation is retried.
pub fn write_value<W>(wr: &mut W, val: &Value) -> Result<(), Error>
    where W: Write
{
    match *val {
        Value::Nil => {
            write_nil(wr).map_err(|err| Error::InvalidMarkerWrite(err))?;
        }
        Value::Boolean(val) => {
            write_bool(wr, val).map_err(|err| Error::InvalidMarkerWrite(err))?;
        }
        Value::U64(val) => {
            write_uint(wr, val)?;
        }
        Value::I64(val) => {
            write_sint(wr, val)?;
        }
        Value::F32(val) => {
            write_f32(wr, val)?;
        }
        Value::F64(val) => {
            write_f64(wr, val)?;
        }
        Value::String(ref val) => {
            write_str(wr, &val)?;
        }
        Value::Binary(ref val) => {
            write_bin(wr, &val)?;
        }
        Value::Array(ref vec) => {
            write_array_len(wr, vec.len() as u32)?;
            for v in vec {
                write_value(wr, v)?;
            }
        }
        Value::Map(ref map) => {
            write_map_len(wr, map.len() as u32)?;
            for &(ref key, ref val) in map {
                write_value(wr, key)?;
                write_value(wr, val)?;
            }
        }
        Value::Ext(ty, ref data) => {
            write_ext_meta(wr, data.len() as u32, ty)?;
            wr.write_all(data)
                .map_err(|err| ValueWriteError::InvalidDataWrite(err))?;
        }
    }

    Ok(())
}
<commit_msg>refactor: reexport instead of conversion<commit_after>use std::io::Write;

use rmp::encode::{write_nil, write_bool, write_uint, write_sint, write_f32, write_f64, write_str,
                  write_bin, write_array_len, write_map_len, write_ext_meta};

pub use rmp::encode::ValueWriteError as Error;

use Value;

/// Encodes and attempts to write the most efficient representation of the given Value.
///
/// # Note
///
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
/// operation is retried.
pub fn write_value<W>(wr: &mut W, val: &Value) -> Result<(), Error>
    where W: Write
{
    match *val {
        Value::Nil => {
            write_nil(wr).map_err(|err| Error::InvalidMarkerWrite(err))?;
        }
        Value::Boolean(val) => {
            write_bool(wr, val).map_err(|err| Error::InvalidMarkerWrite(err))?;
        }
        Value::U64(val) => {
            write_uint(wr, val)?;
        }
        Value::I64(val) => {
            write_sint(wr, val)?;
        }
        Value::F32(val) => {
            write_f32(wr, val)?;
        }
        Value::F64(val) => {
            write_f64(wr, val)?;
        }
        Value::String(ref val) => {
            write_str(wr, &val)?;
        }
        Value::Binary(ref val) => {
            write_bin(wr, &val)?;
        }
        Value::Array(ref vec) => {
            write_array_len(wr, vec.len() as u32)?;
            for v in vec {
                write_value(wr, v)?;
            }
        }
        Value::Map(ref map) => {
            write_map_len(wr, map.len() as u32)?;
            for &(ref key, ref val) in map {
                write_value(wr, key)?;
                write_value(wr, val)?;
            }
        }
        Value::Ext(ty, ref data) => {
            write_ext_meta(wr, data.len() as u32, ty)?;
            wr.write_all(data).map_err(|err| Error::InvalidDataWrite(err))?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Program points.

use entity_map::EntityRef;
use ir::{Ebb, Inst};
use std::fmt;
use std::u32;
use std::cmp;

/// A `ProgramPoint` represents a position in a function where the live range of an SSA value can
/// begin or end. It can be either:
///
/// 1. An instruction or
/// 2. An EBB header.
///
/// This corresponds more or less to the lines in the textual representation of Cretonne IL.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct ProgramPoint(u32);

impl From<Inst> for ProgramPoint {
    fn from(inst: Inst) -> ProgramPoint {
        let idx = inst.index();
        assert!(idx < (u32::MAX / 2) as usize);
        ProgramPoint((idx * 2) as u32)
    }
}

impl From<Ebb> for ProgramPoint {
    fn from(ebb: Ebb) -> ProgramPoint {
        let idx = ebb.index();
        assert!(idx < (u32::MAX / 2) as usize);
        ProgramPoint((idx * 2 + 1) as u32)
    }
}

/// An expanded program point directly exposes the variants, but takes twice the space to
/// represent.
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum ExpandedProgramPoint {
    /// An instruction in the function.
    Inst(Inst),
    /// An EBB header.
    Ebb(Ebb),
}

impl From<Inst> for ExpandedProgramPoint {
    fn from(inst: Inst) -> ExpandedProgramPoint {
        ExpandedProgramPoint::Inst(inst)
    }
}

impl From<Ebb> for ExpandedProgramPoint {
    fn from(ebb: Ebb) -> ExpandedProgramPoint {
        ExpandedProgramPoint::Ebb(ebb)
    }
}

impl From<ProgramPoint> for ExpandedProgramPoint {
    fn from(pp: ProgramPoint) -> ExpandedProgramPoint {
        if pp.0 & 1 == 0 {
            ExpandedProgramPoint::Inst(Inst::new((pp.0 / 2) as usize))
        } else {
            ExpandedProgramPoint::Ebb(Ebb::new((pp.0 / 2) as usize))
        }
    }
}

impl fmt::Display for ProgramPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (*self).into() {
            ExpandedProgramPoint::Inst(x) => write!(f, "{}", x),
            ExpandedProgramPoint::Ebb(x) => write!(f, "{}", x),
        }
    }
}

impl fmt::Debug for ProgramPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ProgramPoint({})", self)
    }
}

/// Context for ordering program points.
///
/// `ProgramPoint` objects don't carry enough information to be ordered independently, they need a
/// context providing the program order.
pub trait ProgramOrder {
    /// Compare the program points `a` and `b` relative to this program order.
    ///
    /// Return `Less` if `a` appears in the program before `b`.
    ///
    /// This is declared as a generic such that it can be called with `Inst` and `Ebb` arguments
    /// directly. Depending on the implementation, there is a good chance performance will be
    /// improved for those cases where the type of either argument is known statically.
    fn cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
        where A: Into<ExpandedProgramPoint>,
              B: Into<ExpandedProgramPoint>;

    /// Is the range from `inst` to `ebb` just the gap between consecutive EBBs?
    ///
    /// This returns true if `inst` is the terminator in the EBB immediately before `ebb`.
    fn is_ebb_gap(&self, inst: Inst, ebb: Ebb) -> bool;
}

#[cfg(test)]
mod tests {
    use super::*;
    use entity_map::EntityRef;
    use ir::{Inst, Ebb};

    #[test]
    fn convert() {
        let i5 = Inst::new(5);
        let b3 = Ebb::new(3);

        let pp1: ProgramPoint = i5.into();
        let pp2: ProgramPoint = b3.into();

        assert_eq!(pp1.to_string(), "inst5");
        assert_eq!(pp2.to_string(), "ebb3");
    }
}
<commit_msg>Implement a conversion from ValueDef into ProgramPoint.<commit_after>//! Program points.

use entity_map::EntityRef;
use ir::{Ebb, Inst, ValueDef};
use std::fmt;
use std::u32;
use std::cmp;

/// A `ProgramPoint` represents a position in a function where the live range of an SSA value can
/// begin or end. It can be either:
///
/// 1. An instruction or
/// 2. An EBB header.
///
/// This corresponds more or less to the lines in the textual representation of Cretonne IL.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct ProgramPoint(u32);

impl From<Inst> for ProgramPoint {
    fn from(inst: Inst) -> ProgramPoint {
        let idx = inst.index();
        assert!(idx < (u32::MAX / 2) as usize);
        ProgramPoint((idx * 2) as u32)
    }
}

impl From<Ebb> for ProgramPoint {
    fn from(ebb: Ebb) -> ProgramPoint {
        let idx = ebb.index();
        assert!(idx < (u32::MAX / 2) as usize);
        ProgramPoint((idx * 2 + 1) as u32)
    }
}

impl From<ValueDef> for ProgramPoint {
    fn from(def: ValueDef) -> ProgramPoint {
        match def {
            ValueDef::Res(inst, _) => inst.into(),
            ValueDef::Arg(ebb, _) => ebb.into(),
        }
    }
}

/// An expanded program point directly exposes the variants, but takes twice the space to
/// represent.
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum ExpandedProgramPoint {
    /// An instruction in the function.
    Inst(Inst),
    /// An EBB header.
    Ebb(Ebb),
}

impl From<Inst> for ExpandedProgramPoint {
    fn from(inst: Inst) -> ExpandedProgramPoint {
        ExpandedProgramPoint::Inst(inst)
    }
}

impl From<Ebb> for ExpandedProgramPoint {
    fn from(ebb: Ebb) -> ExpandedProgramPoint {
        ExpandedProgramPoint::Ebb(ebb)
    }
}

impl From<ProgramPoint> for ExpandedProgramPoint {
    fn from(pp: ProgramPoint) -> ExpandedProgramPoint {
        if pp.0 & 1 == 0 {
            ExpandedProgramPoint::Inst(Inst::new((pp.0 / 2) as usize))
        } else {
            ExpandedProgramPoint::Ebb(Ebb::new((pp.0 / 2) as usize))
        }
    }
}

impl fmt::Display for ProgramPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match (*self).into() {
            ExpandedProgramPoint::Inst(x) => write!(f, "{}", x),
            ExpandedProgramPoint::Ebb(x) => write!(f, "{}", x),
        }
    }
}

impl fmt::Debug for ProgramPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ProgramPoint({})", self)
    }
}

/// Context for ordering program points.
///
/// `ProgramPoint` objects don't carry enough information to be ordered independently, they need a
/// context providing the program order.
pub trait ProgramOrder {
    /// Compare the program points `a` and `b` relative to this program order.
    ///
    /// Return `Less` if `a` appears in the program before `b`.
    ///
    /// This is declared as a generic such that it can be called with `Inst` and `Ebb` arguments
    /// directly. Depending on the implementation, there is a good chance performance will be
    /// improved for those cases where the type of either argument is known statically.
    fn cmp<A, B>(&self, a: A, b: B) -> cmp::Ordering
        where A: Into<ExpandedProgramPoint>,
              B: Into<ExpandedProgramPoint>;

    /// Is the range from `inst` to `ebb` just the gap between consecutive EBBs?
    ///
    /// This returns true if `inst` is the terminator in the EBB immediately before `ebb`.
    fn is_ebb_gap(&self, inst: Inst, ebb: Ebb) -> bool;
}

#[cfg(test)]
mod tests {
    use super::*;
    use entity_map::EntityRef;
    use ir::{Inst, Ebb};

    #[test]
    fn convert() {
        let i5 = Inst::new(5);
        let b3 = Ebb::new(3);

        let pp1: ProgramPoint = i5.into();
        let pp2: ProgramPoint = b3.into();

        assert_eq!(pp1.to_string(), "inst5");
        assert_eq!(pp2.to_string(), "ebb3");
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeap_(@{
    head: E,
    rest: @List<PairingHeap<E>>
  })
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeap_(@{
    head: initial_value,
    rest: @Nil
  })
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeap_(heapA), PairingHeap_(heapB)) => {
        (heapA.head == heapB.head) && (heapA.rest == heapB.rest)
      }
      //(Empty_, PairingHeap_(_)) => {false} // why are these unreachable?
      //(PairingHeap_(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeap_(heap) => { Some(heap.head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeap_(heap) => {(Some(heap.head), self.merge_pairs(heap.rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeap_(heapA), y@PairingHeap_(heapB)) => {
        if (heapA.head.le(&heapB.head)) {
          PairingHeap_(@{
            head: heapA.head,
            rest: @Cons(y, heapA.rest)
          })
        } else {
          PairingHeap_(@{
            head: heapB.head,
            rest: @Cons(x, heapB.rest)
          })
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<commit_msg>convert @record to more standard enum syntax<commit_after>use core::cmp::{Eq, Ord};
use std::list;
use std::list::{List, Cons, Nil};

/**
 * A purely functional Pairing Heap [FSST86]
 *
 * Our implementation uses Linked List (cons cells) so may not be the
 * fastest way to implement this in Rust.
 *
 * This implementation is a port of the Standard ML found in Okasaki's
 * Purely Functional Data Structures.
 */
pub enum PairingHeap<E: Copy Eq Ord> {
  Empty_,
  PairingHeap_(
    E,
    @List<PairingHeap<E>>
  )
}

pub trait Heap<E: Copy Eq Ord> {
  // returns true if the Heap is empty.
  pure fn is_empty(&self) -> bool;

  // returns a new Heap with the element inserted.
  pure fn insert(elem: E) -> self;

  // returns the minimum element without a modified heap
  pure fn find_min() -> Option<E>;

  // returns the minimum element and a new Heap without that element.
  pure fn delete_min() -> (Option<E>, self);
}

pure fn Empty<E: Copy Eq Ord>() -> PairingHeap<E> {
  Empty_
}

pure fn PairingHeap<E: Copy Eq Ord>(initial_value: E) -> PairingHeap<E> {
  PairingHeap_(
    initial_value,
    @Nil
  )
}

impl<E: Copy Eq Ord> PairingHeap<E> : Eq {
  pure fn eq(other: &PairingHeap<E>) -> bool {
    match (self, *other) {
      (Empty_, Empty_) => {true}
      (PairingHeap_(headA, restA), PairingHeap_(headB, restB)) => {
        (headA == headB) && (restA == restB)
      }
      //(Empty_, PairingHeap_(_)) => {false} // why are these unreachable?
      //(PairingHeap_(_), Empty) => {false}
      (_, _) => {false}
    }
  }

  pure fn ne(other: &PairingHeap<E>) -> bool { !(self).eq(other) }
}

impl<E: Copy Eq Ord> PairingHeap<E> : Heap<E> {
  pure fn is_empty(&self) -> bool {
    *self == Empty_
  }

  pure fn insert(e: E) -> PairingHeap<E> {
    self.merge(PairingHeap(e))
  }

  pure fn find_min() -> Option<E> {
    match self {
      Empty_ => { None }
      PairingHeap_(head, _) => { Some(head) }
    }
  }

  pure fn delete_min() -> (Option<E>, PairingHeap<E>) {
    match self {
      Empty_ => {(None, self)}
      PairingHeap_(head, rest) => {(Some(head), self.merge_pairs(rest))}
    }
  }

  pure fn merge(other: PairingHeap<E>) -> PairingHeap<E> {
    match (self, other) {
      (Empty_, b) => { b }
      (a, Empty_) => { a }
      (x@PairingHeap_(headA, restA), y@PairingHeap_(headB, restB)) => {
        if (headA.le(&headB)) {
          PairingHeap_(
            headA,
            @Cons(y, restA)
          )
        } else {
          PairingHeap_(
            headB,
            @Cons(x, restB)
          )
        }
      }
    }
  }

  pure fn merge_pairs(heaps: @List<PairingHeap<E>>) -> PairingHeap<E> {
    match heaps {
      // Why are @-signs required for pattern matching here?
      @Cons(a, @Cons(b, xs)) => {a.merge(b).merge(self.merge_pairs(xs))}
      @Cons(elem, @Nil) => {elem}
      @Nil => {Empty()}
    }
  }
}

#[test]
fn test_heap_create() {
  let heap = PairingHeap(1);
  assert(!heap.is_empty());

  // inference fails on this without a type declaration.
  let heap : PairingHeap<()> = Empty();
  assert(heap.is_empty());
}

#[test]
fn test_heap_insert() {
  let v1 = PairingHeap(10);
  let v2 = v1.insert(1);
  let (one, v3) = v2.delete_min();
  let (ten, v4) = v3.delete_min();
  let (e, v5) = v4.delete_min();

  assert(one == Some(1));
  assert(ten == Some(10));
  assert(v4 == Empty_);
  assert(e == None);
  assert(v5 == Empty_);
}

#[test]
fn test_heap_insert_delete_interleved() {
  let v1 = PairingHeap(10);
  let (a, v2) = v1.delete_min();
  assert(a == Some(10));
  assert(v2 == Empty_);

  let v3 = v2.insert(9);
  let v4 = v3.insert(8);
  let v5 = v4.insert(11);

  let (b, v6) = v5.delete_min();
  assert(b == Some(8));

  let v7 = v6.insert(7);
  let v8 = v7.insert(12);

  let x = v8.find_min();
  assert(x == Some(7));

  let (c, v9) = v8.delete_min();
  assert(c == Some(7));

  let (d, v10) = v9.delete_min();
  assert(d == Some(9));

  let (e, v11) = v10.delete_min();
  assert(e == Some(11));

  let (f, v12) = v11.delete_min();
  assert(f == Some(12));

  let (g, v13) = v12.delete_min();
  assert(g == None);
  assert(v13 == Empty_);
}

#[test]
fn test_immutable_heap() {
  let heap = PairingHeap(10);
  let x1 = heap.insert(1);

  assert(x1.find_min() == Some(1));
  assert(heap.find_min() == Some(10));

  let (a, v1) = heap.delete_min();
  assert(a == Some(10));
  assert(v1 == Empty_);

  let (b, x2) = x1.delete_min();
  assert(b == Some(1));
  assert(x2 != Empty_);
}

<|endoftext|>


<commit_before>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn eigen_vector_manual() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Upper).unwrap();
    assert_close_l2!(&e, &arr1(&[2.0, 2.0, 5.0]), 1.0e-7);
    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|x| e[i] * x);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn diagonalize() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Upper).unwrap();
    let s = vecs.t().dot(&a).dot(&vecs);
    for i in 0..3 {
        assert_rclose!(e[i], s[(i, i)], 1e-7);
    }
}

#[test]
fn ssqrt() {
    let a: Array2<f64> = random_hpd(3);
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Upper).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}

#[test]
fn ssqrt_t() {
    let a: Array2<f64> = random_hpd(3).reversed_axes();
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Upper).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}
<commit_msg>Add test for eigh<commit_after>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn fixed() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Upper).unwrap();
    assert_close_l2!(&e, &arr1(&[2.0, 2.0, 5.0]), 1.0e-7);

    // Check eigenvectors are orthogonalized
    let s = vecs.t().dot(&vecs);
    assert_close_l2!(&s, &Array::eye(3), 1.0e-7);

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|x| e[i] * x);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn fixed_t() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]).reversed_axes();
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Upper).unwrap();
    assert_close_l2!(&e, &arr1(&[2.0, 2.0, 5.0]), 1.0e-7);

    // Check eigenvectors are orthogonalized
    let s = vecs.t().dot(&vecs);
    assert_close_l2!(&s, &Array::eye(3), 1.0e-7);

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|x| e[i] * x);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn fixed_lower() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Lower).unwrap();
    assert_close_l2!(&e, &arr1(&[2.0, 2.0, 5.0]), 1.0e-7);

    // Check eigenvectors are orthogonalized
    let s = vecs.t().dot(&vecs);
    assert_close_l2!(&s, &Array::eye(3), 1.0e-7);

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|x| e[i] * x);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn fixed_t_lower() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]).reversed_axes();
    let (e, vecs): (Array1<_>, Array2<_>) = (&a).eigh(UPLO::Lower).unwrap();
    assert_close_l2!(&e, &arr1(&[2.0, 2.0, 5.0]), 1.0e-7);

    // Check eigenvectors are orthogonalized
    let s = vecs.t().dot(&vecs);
    assert_close_l2!(&s, &Array::eye(3), 1.0e-7);

    for (i, v) in vecs.axis_iter(Axis(1)).enumerate() {
        let av = a.dot(&v);
        let ev = v.mapv(|x| e[i] * x);
        assert_close_l2!(&av, &ev, 1.0e-7);
    }
}

#[test]
fn ssqrt() {
    let a: Array2<f64> = random_hpd(3);
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Upper).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}

#[test]
fn ssqrt_t() {
    let a: Array2<f64> = random_hpd(3).reversed_axes();
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Upper).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}

#[test]
fn ssqrt_lower() {
    let a: Array2<f64> = random_hpd(3);
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Lower).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}

#[test]
fn ssqrt_t_lower() {
    let a: Array2<f64> = random_hpd(3).reversed_axes();
    let ans = a.clone();
    let s = a.ssqrt(UPLO::Lower).unwrap();
    println!("a = {:?}", &ans);
    println!("s = {:?}", &s);
    assert_close_l2!(&s.t(), &s, 1e-7);
    let ss = s.dot(&s);
    println!("ss = {:?}", &ss);
    assert_close_l2!(&ss, &ans, 1e-7);
}
<|endoftext|>


<commit_before>extern crate mioco;

use mioco::sync::mpsc;
use std::thread;

#[test]
fn tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::channel::<i32>();

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  })
            .join()
            .unwrap();

    for i in 0..10 {
        assert_eq!(i, rx.try_recv().unwrap());
    }
}

#[test]
fn tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<i32>();
    for i in 0..10 {
        let _ = tx.send(i);
    }

    mioco::spawn(move || for i in 0..10 {
                     assert_eq!(i, rx.try_recv().unwrap());
                 })
            .join()
            .unwrap();
}

#[test]
fn tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<i32>();

    mioco::spawn(move || for i in 0..10 {
                     let _ = tx.send(i);
                 })
            .join().unwrap();

    mioco::spawn(move || for i in 0..10 {
                     assert_eq!(i, rx.try_recv().unwrap());
                 })
            .join()
            .unwrap();
}
<commit_msg>1. fix tests to check for counts to make sure rx receives all the messages 2. add tests for syncsender & syncreceiver<commit_after>extern crate mioco;

use mioco::sync::mpsc;
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

// NOTE: All the tests are using single MIOCO instance and
// the number of messages that reciver receives varies
// across machines. so the tests here aren't very scalable.
// on the other hand, the sleep times are generous and
// receiver should ideally receive all the messages. anything
// otherwise might help identify performance issues.

#[test]
fn tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    for i in 0..10 {
        assert_eq!(i, rx.recv().unwrap());
    }
}

#[test]
fn tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    // use count to check if all the messages are
    // received at receiver end
    let count = Arc::new(AtomicUsize::new(0));

    for i in 0..10 {
        let _ = tx.send(i);
    }

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    let count = Arc::new(AtomicUsize::new(0));

    mioco::spawn(move ||{
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    let count_clone = count.clone();
    for i in 0..10 {
        assert_eq!(i, rx.recv().unwrap());
        count_clone.store(i, Ordering::SeqCst);
    }

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    thread::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(1000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    mioco::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    thread::sleep_ms(1000);

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::error::Error;
use std::fmt::Error as FmtError;
use std::fmt::{Display, Formatter};

use gst;

#[macro_export]
macro_rules! panic_to_error(
    ($element:expr, $panicked:expr, $ret:expr, $code:block) => {{
        use std::panic::{self, AssertUnwindSafe};
        use std::sync::atomic::Ordering;

        if $panicked.load(Ordering::Relaxed) {
            $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked"]));
            $ret
        } else {
            let result = panic::catch_unwind(AssertUnwindSafe(|| $code));

            match result {
                Ok(result) => result,
                Err(err) => {
                    $panicked.store(true, Ordering::Relaxed);
                    if let Some(cause) = err.downcast_ref::<&str>() {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
                    } else if let Some(cause) = err.downcast_ref::<String>() {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
                    } else {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked"]));
                    }
                    $ret
                }
            }
        }
    }};
);

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlowError {
    Flushing,
    Eos,
    NotNegotiated(gst::ErrorMessage),
    Error(gst::ErrorMessage),
}

impl Into<gst::FlowReturn> for FlowError {
    fn into(self) -> gst::FlowReturn {
        (&self).into()
    }
}

impl<'a> Into<gst::FlowReturn> for &'a FlowError {
    fn into(self) -> gst::FlowReturn {
        match *self {
            FlowError::Flushing => gst::FlowReturn::Flushing,
            FlowError::Eos => gst::FlowReturn::Eos,
            FlowError::NotNegotiated(..) => gst::FlowReturn::NotNegotiated,
            FlowError::Error(..) => gst::FlowReturn::Error,
        }
    }
}

impl Display for FlowError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        match *self {
            FlowError::Flushing | FlowError::Eos => f.write_str(self.description()),
            FlowError::NotNegotiated(ref m) => {
                f.write_fmt(format_args!("{}: {}", self.description(), m))
            }
            FlowError::Error(ref m) => f.write_fmt(format_args!("{}: {}", self.description(), m)),
        }
    }
}

impl Error for FlowError {
    fn description(&self) -> &str {
        match *self {
            FlowError::Flushing => "Flushing",
            FlowError::Eos => "Eos",
            FlowError::NotNegotiated(..) => "Not Negotiated",
            FlowError::Error(..) => "Error",
        }
    }
}
<commit_msg>Implement From instead of Into for FlowError -> FlowReturn<commit_after>// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::error::Error;
use std::fmt::Error as FmtError;
use std::fmt::{Display, Formatter};

use gst;

#[macro_export]
macro_rules! panic_to_error(
    ($element:expr, $panicked:expr, $ret:expr, $code:block) => {{
        use std::panic::{self, AssertUnwindSafe};
        use std::sync::atomic::Ordering;

        if $panicked.load(Ordering::Relaxed) {
            $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked"]));
            $ret
        } else {
            let result = panic::catch_unwind(AssertUnwindSafe(|| $code));

            match result {
                Ok(result) => result,
                Err(err) => {
                    $panicked.store(true, Ordering::Relaxed);
                    if let Some(cause) = err.downcast_ref::<&str>() {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
                    } else if let Some(cause) = err.downcast_ref::<String>() {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
                    } else {
                        $element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked"]));
                    }
                    $ret
                }
            }
        }
    }};
);

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlowError {
    Flushing,
    Eos,
    NotNegotiated(gst::ErrorMessage),
    Error(gst::ErrorMessage),
}

impl From<FlowError> for gst::FlowReturn {
    fn from(err: FlowError) -> Self {
        gst::FlowReturn::from(&err)
    }
}

impl<'a> From<&'a FlowError> for gst::FlowReturn {
    fn from(err: &FlowError) -> gst::FlowReturn {
        match *err {
            FlowError::Flushing => gst::FlowReturn::Flushing,
            FlowError::Eos => gst::FlowReturn::Eos,
            FlowError::NotNegotiated(..) => gst::FlowReturn::NotNegotiated,
            FlowError::Error(..) => gst::FlowReturn::Error,
        }
    }
}

impl Display for FlowError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        match *self {
            FlowError::Flushing | FlowError::Eos => f.write_str(self.description()),
            FlowError::NotNegotiated(ref m) => {
                f.write_fmt(format_args!("{}: {}", self.description(), m))
            }
            FlowError::Error(ref m) => f.write_fmt(format_args!("{}: {}", self.description(), m)),
        }
    }
}

impl Error for FlowError {
    fn description(&self) -> &str {
        match *self {
            FlowError::Flushing => "Flushing",
            FlowError::Eos => "Eos",
            FlowError::NotNegotiated(..) => "Not Negotiated",
            FlowError::Error(..) => "Error",
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[no_mangle]
pub extern "C" fn acos(n: f64) -> f64 {
	libm::acos(n)
}

#[no_mangle]
pub extern "C" fn acosf(n: f32) -> f32 {
	libm::acosf(n)
}

#[no_mangle]
pub extern "C" fn asin(n: f64) -> f64 {
	libm::asin(n)
}

#[no_mangle]
pub extern "C" fn asinf(n: f32) -> f32 {
	libm::asinf(n)
}

#[no_mangle]
pub extern "C" fn atan(n: f64) -> f64 {
	libm::atan(n)
}

#[no_mangle]
pub extern "C" fn atan2(a: f64, b: f64) -> f64 {
	libm::atan2(a, b)
}

pub extern "C" fn atan2f(a: f32, b: f32) -> f32 {
	libm::atan2f(a, b)
}

#[no_mangle]
pub extern "C" fn atanf(n: f32) -> f32 {
	libm::atanf(n)
}

#[no_mangle]
pub extern "C" fn cbrt(n: f64) -> f64 {
	libm::cbrt(n)
}

#[no_mangle]
pub extern "C" fn cbrtf(n: f32) -> f32 {
	libm::cbrtf(n)
}

#[no_mangle]
pub extern "C" fn cosh(n: f64) -> f64 {
	libm::cosh(n)
}

#[no_mangle]
pub extern "C" fn coshf(n: f32) -> f32 {
	libm::coshf(n)
}

#[no_mangle]
pub extern "C" fn exp(x: f64) -> f64 {
	libm::exp(x)
}

#[no_mangle]
pub extern "C" fn expf(x: f32) -> f32 {
	libm::expf(x)
}

#[no_mangle]
pub extern "C" fn expm1(n: f64) -> f64 {
	libm::expm1(n)
}

#[no_mangle]
pub extern "C" fn expm1f(n: f32) -> f32 {
	libm::expm1f(n)
}

#[no_mangle]
pub extern "C" fn fdim(a: f64, b: f64) -> f64 {
	libm::fdim(a, b)
}

#[no_mangle]
pub extern "C" fn fdimf(a: f32, b: f32) -> f32 {
	libm::fdimf(a, b)
}

#[no_mangle]
pub extern "C" fn hypot(x: f64, y: f64) -> f64 {
	libm::hypot(x, y)
}

#[no_mangle]
pub extern "C" fn hypotf(x: f32, y: f32) -> f32 {
	libm::hypotf(x, y)
}

#[no_mangle]
pub extern "C" fn log(x: f64) -> f64 {
	libm::log(x)
}

pub fn logf(x: f32) -> f32 {
	libm::logf(x)
}

#[no_mangle]
pub extern "C" fn log1p(n: f64) -> f64 {
	libm::log1p(n)
}

#[no_mangle]
pub extern "C" fn log1pf(n: f32) -> f32 {
	libm::log1pf(n)
}

#[no_mangle]
pub extern "C" fn sinh(n: f64) -> f64 {
	libm::sinh(n)
}

#[no_mangle]
pub extern "C" fn sinhf(n: f32) -> f32 {
	libm::sinhf(n)
}

#[no_mangle]
pub extern "C" fn tan(n: f64) -> f64 {
	libm::tan(n)
}

#[no_mangle]
pub extern "C" fn tanf(n: f32) -> f32 {
	libm::tanf(n)
}

#[no_mangle]
pub extern "C" fn tanh(n: f64) -> f64 {
	libm::tanh(n)
}

#[no_mangle]
pub extern "C" fn tanhf(n: f32) -> f32 {
	libm::tanhf(n)
}
<commit_msg>increase the number of arithmetic functions<commit_after>#![allow(dead_code)]

#[no_mangle]
pub extern "C" fn acos(n: f64) -> f64 {
	libm::acos(n)
}

#[no_mangle]
pub extern "C" fn acosf(n: f32) -> f32 {
	libm::acosf(n)
}

#[no_mangle]
pub extern "C" fn acosh(x: f64) -> f64 {
    libm::acosh(x)
}

#[no_mangle]
pub extern "C" fn acoshf(x: f32) -> f32 {
    libm::acoshf(x)
}

#[no_mangle]
pub extern "C" fn asin(n: f64) -> f64 {
	libm::asin(n)
}

#[no_mangle]
pub extern "C" fn asinf(n: f32) -> f32 {
	libm::asinf(n)
}

#[no_mangle]
pub extern "C" fn asinh(x: f64) -> f64 {
    libm::asinh(x)
}

#[no_mangle]
pub extern "C" fn asinhf(x: f32) -> f32 {
    libm::asinhf(x)
}

#[no_mangle]
pub extern "C" fn atan(n: f64) -> f64 {
	libm::atan(n)
}

#[no_mangle]
pub extern "C" fn atan2(a: f64, b: f64) -> f64 {
	libm::atan2(a, b)
}

pub extern "C" fn atan2f(a: f32, b: f32) -> f32 {
	libm::atan2f(a, b)
}

#[no_mangle]
pub extern "C" fn atanf(n: f32) -> f32 {
	libm::atanf(n)
}

#[no_mangle]
pub extern "C" fn cbrt(n: f64) -> f64 {
	libm::cbrt(n)
}

#[no_mangle]
pub extern "C" fn cbrtf(n: f32) -> f32 {
	libm::cbrtf(n)
}

#[no_mangle]
pub extern "C" fn ceil(x: f64) -> f64 {
    libm::ceil(x)
}

#[no_mangle]
pub extern "C" fn ceilf(x: f32) -> f32 {
    libm::ceilf(x)
}

#[no_mangle]
pub extern "C" fn cos(x: f64) -> f64 {
    libm::cos(x)
}

#[no_mangle]
pub extern "C" fn cosf(x: f32) -> f32 {
    libm::cosf(x)
}

#[no_mangle]
pub extern "C" fn cosh(x: f64) -> f64 {
    libm::cosh(x)
}

#[no_mangle]
pub extern "C" fn coshf(x: f32) -> f32 {
    libm::coshf(x)
}

#[no_mangle]
pub extern "C" fn exp(x: f64) -> f64 {
	libm::exp(x)
}

#[no_mangle]
pub extern "C" fn expf(x: f32) -> f32 {
	libm::expf(x)
}

#[no_mangle]
pub extern "C" fn expm1(n: f64) -> f64 {
	libm::expm1(n)
}

#[no_mangle]
pub extern "C" fn expm1f(n: f32) -> f32 {
	libm::expm1f(n)
}

#[no_mangle]
pub extern "C" fn fdim(a: f64, b: f64) -> f64 {
	libm::fdim(a, b)
}

#[no_mangle]
pub extern "C" fn fdimf(a: f32, b: f32) -> f32 {
	libm::fdimf(a, b)
}

#[no_mangle]
pub extern "C" fn hypot(x: f64, y: f64) -> f64 {
	libm::hypot(x, y)
}

#[no_mangle]
pub extern "C" fn hypotf(x: f32, y: f32) -> f32 {
	libm::hypotf(x, y)
}

#[no_mangle]
pub extern "C" fn log(x: f64) -> f64 {
	libm::log(x)
}

pub fn logf(x: f32) -> f32 {
	libm::logf(x)
}

#[no_mangle]
pub extern "C" fn log1p(n: f64) -> f64 {
	libm::log1p(n)
}

#[no_mangle]
pub extern "C" fn log1pf(n: f32) -> f32 {
	libm::log1pf(n)
}

#[no_mangle]
pub extern "C" fn sinh(n: f64) -> f64 {
	libm::sinh(n)
}

#[no_mangle]
pub extern "C" fn sinhf(n: f32) -> f32 {
	libm::sinhf(n)
}

#[no_mangle]
pub extern "C" fn sqrt(x: f64) -> f64 {
    libm::sqrt(x)
}

#[no_mangle]
pub extern "C" fn sqrtf(x: f32) -> f32 {
    libm::sqrtf(x)
}

#[no_mangle]
pub extern "C" fn tan(n: f64) -> f64 {
	libm::tan(n)
}

#[no_mangle]
pub extern "C" fn tanf(n: f32) -> f32 {
	libm::tanf(n)
}

#[no_mangle]
pub extern "C" fn tanh(n: f64) -> f64 {
	libm::tanh(n)
}

#[no_mangle]
pub extern "C" fn tanhf(n: f32) -> f32 {
	libm::tanhf(n)
}
<|endoftext|>


<commit_before>//! A "compatibility layer" for spanning XP and Windows 7
//!
//! The standard library currently binds many functions that are not available
//! on Windows XP, but we would also like to support building executables that
//! run on XP. To do this we specify all non-XP APIs as having a fallback
//! implementation to do something reasonable.
//!
//! This dynamic runtime detection of whether a function is available is
//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a
//! static-per-function which caches the result of the first check. In this
//! manner we pay a semi-large one-time cost up front for detecting whether a
//! function is available but afterwards it's just a load and a jump.

use crate::ffi::CString;
use crate::sys::c;

pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
    let mut module: Vec<u16> = module.encode_utf16().collect();
    module.push(0);
    let symbol = CString::new(symbol).unwrap();
    unsafe {
        let handle = c::GetModuleHandleW(module.as_ptr());
        match c::GetProcAddress(handle, symbol.as_ptr()) as usize {
            0 => None,
            n => Some(n),
        }
    }
}

macro_rules! compat_fn {
    ($module:literal: $(
        $(#[$meta:meta])*
        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block
    )*) => ($(
        $(#[$meta])*
        pub mod $symbol {
            use super::*;
            use crate::sync::atomic::{AtomicUsize, Ordering};
            use crate::mem;

            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;

            static PTR: AtomicUsize = AtomicUsize::new(0);

            #[allow(unused_variables)]
            unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body

            /// This address is stored in `PTR` to incidate an unavailable API.
            ///
            /// This way, call() will end up calling fallback() if it is unavailable.
            ///
            /// This is a `static` to avoid rustc duplicating `fn fallback()`
            /// into both load() and is_available(), which would break
            /// is_available()'s comparison. By using the same static variable
            /// in both places, they'll refer to the same (copy of the)
            /// function.
            ///
            /// LLVM merging the address of fallback with other functions
            /// (because of unnamed_addr) is fine, since it's only compared to
            /// an address from GetProcAddress from an external dll.
            static FALLBACK: F = fallback;

            #[cold]
            fn load() -> usize {
                // There is no locking here. It's okay if this is executed by multiple threads in
                // parallel. `lookup` will result in the same value, and it's okay if they overwrite
                // eachothers result as long as they do so atomically. We don't need any guarantees
                // about memory ordering, as this involves just a single atomic variable which is
                // not used to protect or order anything else.
                let addr = crate::sys::compat::lookup($module, stringify!($symbol))
                    .unwrap_or(FALLBACK as usize);
                PTR.store(addr, Ordering::Relaxed);
                addr
            }

            fn addr() -> usize {
                match PTR.load(Ordering::Relaxed) {
                    0 => load(),
                    addr => addr,
                }
            }

            #[allow(dead_code)]
            pub fn is_available() -> bool {
                addr() != FALLBACK as usize
            }

            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                mem::transmute::<usize, F>(addr())($($argname),*)
            }
        }

        pub use $symbol::call as $symbol;
    )*)
}
<commit_msg>Auto merge of #79205 - rust-lang:jdm-patch-1, r=m-ou-se<commit_after>//! A "compatibility layer" for spanning XP and Windows 7
//!
//! The standard library currently binds many functions that are not available
//! on Windows XP, but we would also like to support building executables that
//! run on XP. To do this we specify all non-XP APIs as having a fallback
//! implementation to do something reasonable.
//!
//! This dynamic runtime detection of whether a function is available is
//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a
//! static-per-function which caches the result of the first check. In this
//! manner we pay a semi-large one-time cost up front for detecting whether a
//! function is available but afterwards it's just a load and a jump.

use crate::ffi::CString;
use crate::sys::c;

pub fn lookup(module: &str, symbol: &str) -> Option<usize> {
    let mut module: Vec<u16> = module.encode_utf16().collect();
    module.push(0);
    let symbol = CString::new(symbol).unwrap();
    unsafe {
        let handle = c::GetModuleHandleW(module.as_ptr());
        match c::GetProcAddress(handle, symbol.as_ptr()) as usize {
            0 => None,
            n => Some(n),
        }
    }
}

macro_rules! compat_fn {
    ($module:literal: $(
        $(#[$meta:meta])*
        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block
    )*) => ($(
        $(#[$meta])*
        pub mod $symbol {
            use super::*;
            use crate::sync::atomic::{AtomicUsize, Ordering};
            use crate::mem;

            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;

            static PTR: AtomicUsize = AtomicUsize::new(0);

            #[allow(unused_variables)]
            unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body

            /// This address is stored in `PTR` to incidate an unavailable API.
            ///
            /// This way, call() will end up calling fallback() if it is unavailable.
            ///
            /// This is a `static` to avoid rustc duplicating `fn fallback()`
            /// into both load() and is_available(), which would break
            /// is_available()'s comparison. By using the same static variable
            /// in both places, they'll refer to the same (copy of the)
            /// function.
            ///
            /// LLVM merging the address of fallback with other functions
            /// (because of unnamed_addr) is fine, since it's only compared to
            /// an address from GetProcAddress from an external dll.
            static FALLBACK: F = fallback;

            #[cold]
            fn load() -> usize {
                // There is no locking here. It's okay if this is executed by multiple threads in
                // parallel. `lookup` will result in the same value, and it's okay if they overwrite
                // eachothers result as long as they do so atomically. We don't need any guarantees
                // about memory ordering, as this involves just a single atomic variable which is
                // not used to protect or order anything else.
                let addr = crate::sys::compat::lookup($module, stringify!($symbol))
                    .unwrap_or(FALLBACK as usize);
                PTR.store(addr, Ordering::Relaxed);
                addr
            }

            fn addr() -> usize {
                match PTR.load(Ordering::Relaxed) {
                    0 => load(),
                    addr => addr,
                }
            }

            #[allow(dead_code)]
            pub fn is_available() -> bool {
                addr() != FALLBACK as usize
            }

            pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                mem::transmute::<usize, F>(addr())($($argname),*)
            }
        }

        $(#[$meta])*
        pub use $symbol::call as $symbol;
    )*)
}
<|endoftext|>


<commit_before>use ndarray::*;
use ndarray_linalg::*;

#[test]
fn solve_random() {
    let a: Array2<f64> = random((3, 3));
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[test]
fn solve_random_t() {
    let a: Array2<f64> = random((3, 3).f());
    let x: Array1<f64> = random(3);
    let b = a.dot(&x);
    let y = a.solve_into(b).unwrap();
    assert_close_l2!(&x, &y, 1e-7);
}

#[test]
fn solve_factorized() {
    let a: Array2<f64> = random((3, 3));
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[test]
fn solve_factorized_t() {
    let a: Array2<f64> = random((3, 3).f());
    let ans: Array1<f64> = random(3);
    let b = a.dot(&ans);
    let f = a.factorize_into().unwrap();
    let x = f.solve_into(b).unwrap();
    assert_close_l2!(&x, &ans, 1e-7);
}

#[test]
fn rcond() {
    macro_rules! rcond {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a: Array2<$elem> = random_hpd($rows);
            let rcond = 1. / (a.opnorm_one().unwrap() * a.inv().unwrap().opnorm_one().unwrap());
            assert_aclose!(a.rcond().unwrap(), rcond, $atol);
            assert_aclose!(a.rcond_into().unwrap(), rcond, $atol);
        };
    }
    for rows in 1..6 {
        rcond!(f64, rows, 0.2);
        rcond!(f32, rows, 0.5);
        rcond!(c64, rows, 0.2);
        rcond!(c32, rows, 0.5);
    }
}

#[test]
fn rcond_hilbert() {
    macro_rules! rcond_hilbert {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::from_shape_fn(($rows, $rows), |(i, j)| {
                1. / (i as $elem + j as $elem - 1.)
            });
            assert_aclose!(a.rcond().unwrap(), 0., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 0., $atol);
        };
    }
    rcond_hilbert!(f64, 10, 1e-9);
    rcond_hilbert!(f32, 10, 1e-3);
}

#[test]
fn rcond_identity() {
    macro_rules! rcond_identity {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::eye($rows);
            assert_aclose!(a.rcond().unwrap(), 1., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 1., $atol);
        };
    }
    for rows in 1..6 {
        rcond_identity!(f64, rows, 1e-9);
        rcond_identity!(f32, rows, 1e-3);
        rcond_identity!(c64, rows, 1e-9);
        rcond_identity!(c32, rows, 1e-3);
    }
}
<commit_msg>Add more tests for Solve<commit_after>use ndarray::prelude::*;
use ndarray_linalg::{
    assert_aclose, assert_close_l2, c32, c64, random, random_hpd, solve::*, OperationNorm, Scalar,
};

macro_rules! test_solve {
    (
        [$($elem_type:ty => $rtol:expr),*],
        $a_ident:ident = $a:expr,
        $x_ident:ident = $x:expr,
        b = $b:expr,
        $solve:ident,
    ) => {
        $({
            let $a_ident: Array2<$elem_type> = $a;
            let $x_ident: Array1<$elem_type> = $x;
            let b: Array1<$elem_type> = $b;
            let a = $a_ident;
            let x = $x_ident;
            let rtol = $rtol;
            assert_close_l2!(&a.$solve(&b).unwrap(), &x, rtol);
            assert_close_l2!(&a.factorize().unwrap().$solve(&b).unwrap(), &x, rtol);
            assert_close_l2!(&a.factorize_into().unwrap().$solve(&b).unwrap(), &x, rtol);
        })*
    };
}

macro_rules! test_solve_into {
    (
        [$($elem_type:ty => $rtol:expr),*],
        $a_ident:ident = $a:expr,
        $x_ident:ident = $x:expr,
        b = $b:expr,
        $solve_into:ident,
    ) => {
        $({
            let $a_ident: Array2<$elem_type> = $a;
            let $x_ident: Array1<$elem_type> = $x;
            let b: Array1<$elem_type> = $b;
            let a = $a_ident;
            let x = $x_ident;
            let rtol = $rtol;
            assert_close_l2!(&a.$solve_into(b.clone()).unwrap(), &x, rtol);
            assert_close_l2!(&a.factorize().unwrap().$solve_into(b.clone()).unwrap(), &x, rtol);
            assert_close_l2!(&a.factorize_into().unwrap().$solve_into(b.clone()).unwrap(), &x, rtol);
        })*
    };
}

macro_rules! test_solve_inplace {
    (
        [$($elem_type:ty => $rtol:expr),*],
        $a_ident:ident = $a:expr,
        $x_ident:ident = $x:expr,
        b = $b:expr,
        $solve_inplace:ident,
    ) => {
        $({
            let $a_ident: Array2<$elem_type> = $a;
            let $x_ident: Array1<$elem_type> = $x;
            let b: Array1<$elem_type> = $b;
            let a = $a_ident;
            let x = $x_ident;
            let rtol = $rtol;
            {
                let mut b = b.clone();
                assert_close_l2!(&a.$solve_inplace(&mut b).unwrap(), &x, rtol);
                assert_close_l2!(&b, &x, rtol);
            }
            {
                let mut b = b.clone();
                assert_close_l2!(&a.factorize().unwrap().$solve_inplace(&mut b).unwrap(), &x, rtol);
                assert_close_l2!(&b, &x, rtol);
            }
            {
                let mut b = b.clone();
                assert_close_l2!(&a.factorize_into().unwrap().$solve_inplace(&mut b).unwrap(), &x, rtol);
                assert_close_l2!(&b, &x, rtol);
            }
        })*
    };
}

macro_rules! test_solve_all {
    (
        [$($elem_type:ty => $rtol:expr),*],
        $a_ident:ident = $a:expr,
        $x_ident:ident = $x:expr,
        b = $b:expr,
        [$solve:ident, $solve_into:ident, $solve_inplace:ident],
    ) => {
        test_solve!([$($elem_type => $rtol),*], $a_ident = $a, $x_ident = $x, b = $b, $solve,);
        test_solve_into!([$($elem_type => $rtol),*], $a_ident = $a, $x_ident = $x, b = $b, $solve_into,);
        test_solve_inplace!([$($elem_type => $rtol),*], $a_ident = $a, $x_ident = $x, b = $b, $solve_inplace,);
    };
}

#[test]
fn solve_random_float() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [f32 => 1e-3, f64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.dot(&x),
                [solve, solve_into, solve_inplace],
            );
        }
    }
}

#[test]
fn solve_random_complex() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [c32 => 1e-3, c64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.dot(&x),
                [solve, solve_into, solve_inplace],
            );
        }
    }
}

#[test]
fn solve_t_random_float() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [f32 => 1e-3, f64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.t().dot(&x),
                [solve_t, solve_t_into, solve_t_inplace],
            );
        }
    }
}

#[test]
fn solve_t_random_complex() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [c32 => 1e-3, c64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.t().dot(&x),
                [solve_t, solve_t_into, solve_t_inplace],
            );
        }
    }
}

#[test]
fn solve_h_random_float() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [f32 => 1e-3, f64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.t().mapv(|x| x.conj()).dot(&x),
                [solve_h, solve_h_into, solve_h_inplace],
            );
        }
    }
}

#[test]
fn solve_h_random_complex() {
    for n in 0..=8 {
        for &set_f in &[false, true] {
            test_solve_all!(
                [c32 => 1e-3, c64 => 1e-9],
                a = random([n; 2].set_f(set_f)),
                x = random(n),
                b = a.t().mapv(|x| x.conj()).dot(&x),
                [solve_h, solve_h_into, solve_h_inplace],
            );
        }
    }
}

#[test]
fn rcond() {
    macro_rules! rcond {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a: Array2<$elem> = random_hpd($rows);
            let rcond = 1. / (a.opnorm_one().unwrap() * a.inv().unwrap().opnorm_one().unwrap());
            assert_aclose!(a.rcond().unwrap(), rcond, $atol);
            assert_aclose!(a.rcond_into().unwrap(), rcond, $atol);
        };
    }
    for rows in 1..6 {
        rcond!(f64, rows, 0.2);
        rcond!(f32, rows, 0.5);
        rcond!(c64, rows, 0.2);
        rcond!(c32, rows, 0.5);
    }
}

#[test]
fn rcond_hilbert() {
    macro_rules! rcond_hilbert {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::from_shape_fn(($rows, $rows), |(i, j)| {
                1. / (i as $elem + j as $elem - 1.)
            });
            assert_aclose!(a.rcond().unwrap(), 0., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 0., $atol);
        };
    }
    rcond_hilbert!(f64, 10, 1e-9);
    rcond_hilbert!(f32, 10, 1e-3);
}

#[test]
fn rcond_identity() {
    macro_rules! rcond_identity {
        ($elem:ty, $rows:expr, $atol:expr) => {
            let a = Array2::<$elem>::eye($rows);
            assert_aclose!(a.rcond().unwrap(), 1., $atol);
            assert_aclose!(a.rcond_into().unwrap(), 1., $atol);
        };
    }
    for rows in 1..6 {
        rcond_identity!(f64, rows, 1e-9);
        rcond_identity!(f32, rows, 1e-3);
        rcond_identity!(c64, rows, 1e-9);
        rcond_identity!(c32, rows, 1e-3);
    }
}
<|endoftext|>


<commit_before>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<commit_msg>Add more comment tests<commit_after>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty_comment() {
    let (f, h) = setup("//");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_with_tail() {
    let (f, h) = setup("// line comment\nnot a comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 14);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<|endoftext|>


<commit_before>use vec::Uniq;

/// Collection of methods for getting or evaluating uniqueness, assuming some
/// kind of sorted-ness
pub trait SortedUniq<T>: Uniq<T> {
    /// `uniq` returns a vector of unique values within itself as compared to the
    /// other vector, which is provided as an input parameter. Both of these must
    /// have non-decreasing values.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,4,5,6].uniq(vec![1,2,5,7,9]);
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![3,4,6]
    /// ```
    fn uniq(&self, other: Self) -> Self;

    /// `unique` returns a vector like Self but with all duplicated elements
    /// removed. Must have non-decreasing values.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,1,1,2,3,3,4,5,6].unique();
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![1,2,3,4,5,6]
    /// ```
    fn unique(&self) -> Self;

    /// `is_unique` returns boolean value on whether all values within Self are
    /// unique. Self must be sorted in some way.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,4,6,6,7,8].is_unique();
    /// ```
    ///
    /// # Output
    /// ```text
    /// false
    /// ```
    fn is_unique(&self) -> bool;

    /// `uniq_via` returns a vector of unique values within itself as compared to
    /// the other vector which is provided as an input parameter, as defined by
    /// the two provided custom comparators. Both vectors must be sorted, and the
    /// sort direction is determined by the second comparator: l < r for increasing.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,4,5,6].uniq_via(
    ///     vec![1,2,5,7,9],
    ///     |l, r| l == r,
    ///     |l, r| l < r
    /// );
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![3, 4, 6]
    /// ```
    fn uniq_via<F: Fn(&T, &T) -> bool, K: Fn(&T, &T) -> bool>(
        &self,
        other: Self,
        eq: F,
        ord: K,
    ) -> Self;

    /// `unique_via` removes duplicates from within the vector and returns Self.
    /// Self must be a vector sorted in some way.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,3,4,5,6].unique_via(|l, r| l == r);
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![1,2,3,4,5,6]
    /// ```
    fn unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> Self;

    /// `is_unique_via` returns boolean value on whether all values within
    /// Self are unique, as defined by a provided custom comparator. Self must
    /// be a vector sorted in some way.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1.0,2.0,2.4,3.3,3.1,3.5,4.6,5.2,6.2].is_unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
    /// ```
    ///
    /// # Output
    /// ```text
    /// false
    /// ```
    fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> bool;
}

impl<T: Copy + PartialEq + PartialOrd> SortedUniq<T> for Vec<T> {
    fn uniq(&self, other: Vec<T>) -> Vec<T> {
        SortedUniq::<T>::uniq_via(self, other, |l, r| l == r, |l, r| l < r)
    }

    fn unique(&self) -> Vec<T> {
        SortedUniq::<T>::unique_via(self, |l, r| l == r)
    }

    fn is_unique(&self) -> bool {
        SortedUniq::<T>::is_unique_via(self, |l, r| l == r)
    }

    fn uniq_via<F: Fn(&T, &T) -> bool, K: Fn(&T, &T) -> bool>(
        &self,
        other: Self,
        eq: F,
        ord: K,
    ) -> Vec<T> {
        let mut out = self.clone();
        let mut cursor: usize = 0;
        let mut i: usize = 0;
        let mut j: usize = 0;
        while i < out.len() && j < other.len() {
            if ord(&other[j], &out[i]) {
                // ^ should other[j] be ordered before out[i]?
                j += 1;
            } else if eq(&other[j], &out[i]) {
                i += 1;
                j += 1;
            } else {
                if i == 0 || !eq(&out[i - 1], &out[i]) {
                    out[cursor] = out[i];
                    cursor += 1;
                }
                i += 1;
            }
        }
        while i < out.len() {
            if i == 0 || !eq(&out[i - 1], &out[i]) {
                out[cursor] = out[i];
                cursor += 1;
            }
            i += 1;
        }
        out.truncate(cursor);
        out
    }
    fn unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> Vec<T> {
        let mut out = self.clone();
        let mut cursor: usize = 1;
        for i in 1..out.len() {
            if !eq(&out[i], &out[i - 1]) {
                if i != cursor {
                    out[cursor] = out[i];
                }
                cursor += 1;
            }
        }
        out.truncate(cursor);
        out
    }

    fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> bool {
        for i in 1..self.len() {
            if eq(&self[i], &self[i - 1]) {
                return false;
            }
        }
        true
    }
}
<commit_msg>Add uniq_decreasing trait for ease of access<commit_after>use vec::Uniq;

/// Collection of methods for getting or evaluating uniqueness, assuming some
/// kind of sorted-ness
pub trait SortedUniq<T>: Uniq<T> {
    /// `uniq` returns a vector of unique values within itself as compared to the
    /// other vector, which is provided as an input parameter. Both of these must
    /// be sorted and have non-decreasing values
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,4,5,6].uniq(vec![1,2,5,7,9]);
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![3,4,6]
    /// ```
    fn uniq(&self, other: Self) -> Self;

    /// `uniq_decreasing` returns a vector of unique values within itself as compared
    /// to the other vector, which is provided as an input parameter. Both of these
    /// must be sorted and have non-increasing values. Inverse of `uniq`.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![6,5,4,3,2,1].uniq_decreasing(vec![9,7,5,3,1]);
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![6,4,2]
    /// ```
    fn uniq_decreasing(&self, other: Self) -> Self;

    /// `unique` returns a vector like Self but with all duplicated elements
    /// removed. Self must be a vector sorted in some way.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,1,1,2,3,3,4,5,6].unique();
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![1,2,3,4,5,6]
    /// ```
    fn unique(&self) -> Self;

    /// `is_unique` returns boolean value on whether all values within Self are
    /// unique. Self must be a vecto sorted in some way.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,4,6,6,7,8].is_unique();
    /// ```
    ///
    /// # Output
    /// ```text
    /// false
    /// ```
    fn is_unique(&self) -> bool;

    /// `uniq_via` returns a vector of unique values within itself as compared to
    /// the other vector which is provided as an input parameter, as defined by
    /// the two provided custom comparators. Both vectors must be sorted in a way
    /// corresponding to the custom comparators, and the sort direction is determined
    /// by the second comparator: l < r for increasing.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,4,5,6].uniq_via(
    ///     vec![1,2,5,7,9],
    ///     |l, r| l == r,
    ///     |l, r| l < r
    /// );
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![3, 4, 6]
    /// ```
    fn uniq_via<F: Fn(&T, &T) -> bool, K: Fn(&T, &T) -> bool>(
        &self,
        other: Self,
        eq: F,
        ord: K,
    ) -> Self;

    /// `unique_via` removes duplicates, as defined by a provided custom comparator,
    /// from within the vector and returns Self. Self must be a vector sorted in a
    /// way corresponding to the custom comparator.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1,2,3,3,4,5,6].unique_via(|l, r| l == r);
    /// ```
    ///
    /// # Output
    /// ```text
    /// vec![1,2,3,4,5,6]
    /// ```
    fn unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> Self;

    /// `is_unique_via` returns boolean value on whether all values within
    /// Self are unique, as defined by a provided custom comparator. Self must
    /// be a vector sorted in some way corresponding to the custom comparator.
    ///
    /// # Example
    /// ```
    /// use array_tool::sorted_vec::SortedUniq;
    ///
    /// vec![1.0,2.0,2.4,3.3,3.1,3.5,4.6,5.2,6.2].is_unique_via( |l: &f64, r: &f64| l.floor() == r.floor() );
    /// ```
    ///
    /// # Output
    /// ```text
    /// false
    /// ```
    fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> bool;
}

impl<T: Copy + PartialEq + PartialOrd> SortedUniq<T> for Vec<T> {
    fn uniq(&self, other: Vec<T>) -> Vec<T> {
        SortedUniq::<T>::uniq_via(self, other, |l, r| l == r, |l, r| l < r)
    }

    fn uniq_decreasing(&self, other: Vec<T>) -> Vec<T> {
        SortedUniq::<T>::uniq_via(self, other, |l, r| l == r, |l, r| l > r)
    }

    fn unique(&self) -> Vec<T> {
        SortedUniq::<T>::unique_via(self, |l, r| l == r)
    }

    fn is_unique(&self) -> bool {
        SortedUniq::<T>::is_unique_via(self, |l, r| l == r)
    }

    fn uniq_via<F: Fn(&T, &T) -> bool, K: Fn(&T, &T) -> bool>(
        &self,
        other: Vec<T>,
        eq: F,
        ord: K,
    ) -> Vec<T> {
        let mut out = self.clone();
        let mut cursor: usize = 0;
        let mut i: usize = 0;
        let mut j: usize = 0;
        while i < out.len() && j < other.len() {
            if ord(&other[j], &out[i]) {
                // ^ should other[j] be ordered before out[i]?
                j += 1;
            } else if eq(&other[j], &out[i]) {
                i += 1;
                j += 1;
            } else {
                if i == 0 || !eq(&out[i - 1], &out[i]) {
                    out[cursor] = out[i];
                    cursor += 1;
                }
                i += 1;
            }
        }
        while i < out.len() {
            if i == 0 || !eq(&out[i - 1], &out[i]) {
                out[cursor] = out[i];
                cursor += 1;
            }
            i += 1;
        }
        out.truncate(cursor);
        out
    }
    fn unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> Vec<T> {
        let mut out = self.clone();
        let mut cursor: usize = 1;
        for i in 1..out.len() {
            if !eq(&out[i], &out[i - 1]) {
                if i != cursor {
                    out[cursor] = out[i];
                }
                cursor += 1;
            }
        }
        out.truncate(cursor);
        out
    }

    fn is_unique_via<F: Fn(&T, &T) -> bool>(&self, eq: F) -> bool {
        for i in 1..self.len() {
            if eq(&self[i], &self[i - 1]) {
                return false;
            }
        }
        true
    }
}
<|endoftext|>