<commit_before>extern crate image;

mod material;
mod mesh;
mod obj_load;

use std::collections::HashMap;
use std::path::Path;
use std::vec::Vec;

use glium;
use glium::{DrawParameters, VertexBuffer, IndexBuffer, Program, Surface};
use glium::backend::Facade;
use glium::texture::{RawImage2d, Texture2d};

use cgmath::Matrix4;
use cgmath::conv::*;

use self::image::{ImageBuffer, Rgb};

use self::mesh::Mesh;
use self::material::Material;

/// Renderer representation of a vertex
#[derive(Copy, Clone, Debug)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub tex_coords: [f32; 2]
}

implement_vertex!(Vertex, position, normal, tex_coords);

/// Renderer representation of a scene
#[derive(Default)]
pub struct Scene {
    pub vertices: Vec<Vertex>,
    pub meshes: Vec<Mesh>,
    pub materials: Vec<Material>,
    pub vertex_buffer: Option<VertexBuffer<Vertex>>,
    image_vertex_buffer: Option<VertexBuffer<Vertex>>,
    image_index_buffer: Option<IndexBuffer<u32>>,
    preview_shader: Option<Program>,
    image_shader: Option<Program>,
    t: u32,
    /// Bounding box of the scene
    pub min: [f32; 3],
    pub max: [f32; 3],
}

#[cfg_attr(feature="clippy", allow(needless_range_loop))]
impl Scene {
    pub fn init<F: Facade>(scene_path: &Path, facade: &F) -> Scene {
        let mut scene = Scene { .. Default::default() };
        scene.load_scene(scene_path);
        scene.upload_data(facade);
        scene.init_renderers(facade);
        scene
    }

    /// Load a scene from the given path
    fn load_scene(&mut self, scene_path: &Path) {
        let obj = obj_load::load_obj(scene_path).expect("Failed to load.");

        // Closure to calculate planar normal for a triangle
        let calculate_normal = |triangle: &obj_load::Triangle| -> [f32; 3] {
            let pos_i1 = triangle.index_vertices[0].pos_i;
            let pos_i2 = triangle.index_vertices[1].pos_i;
            let pos_i3 = triangle.index_vertices[2].pos_i;
            let pos_1 = obj.positions[pos_i1];
            let pos_2 = obj.positions[pos_i2];
            let pos_3 = obj.positions[pos_i3];
            let u = [pos_2[0] - pos_1[0],
                    pos_2[1] - pos_1[1],
                    pos_2[2] - pos_1[2]];
            let v = [pos_3[0] - pos_1[0],
                    pos_3[1] - pos_1[1],
                    pos_3[2] - pos_1[2]];
            [u[1]*v[2] - u[2]*v[1],
            u[2]*v[0] - u[0]*v[2],
            u[0]*v[1] - u[1]*v[0]]
        };

        // Group the polygons by materials for easy rendering
        let mut vertex_map = HashMap::new();
        for range in &obj.material_ranges {
            let obj_mat = obj.materials.get(&range.name)
                .expect(&::std::fmt::format(format_args!("Couldn't find material {}!", range.name)));
            let mut mesh = Mesh::new(self.materials.len());
            self.materials.push(Material::new(obj_mat));
            for tri in &obj.triangles[range.start_i..range.end_i] {
                let default_tex_coords= [0.0; 2];
                for index_vertex in &tri.index_vertices {
                    match vertex_map.get(index_vertex) {
                        // Vertex has already been added
                        Some(&i) => mesh.indices.push(i),
                        None => {
                            // Add vertex to map
                            vertex_map.insert(index_vertex, self.vertices.len() as u32);
                            let pos = obj.positions[index_vertex.pos_i];
                            self.update_ranges(pos);

                            let tex_coords = match index_vertex.tex_i {
                                Some(tex_i) => obj.tex_coords[tex_i],
                                None => default_tex_coords
                            };
                            let normal = match index_vertex.normal_i {
                                Some(normal_i) => obj.normals[normal_i],
                                None => calculate_normal(tri)
                            };

                            mesh.indices.push(self.vertices.len() as u32);
                            self.vertices.push(Vertex { position: pos, normal: normal, tex_coords: tex_coords });
                        }
                    }
                }
            }
            if !mesh.indices.is_empty() {
                self.meshes.push(mesh);
            }
        }
    }

    /// Load the textures + vertex and index buffers to the GPU
    fn upload_data<F: Facade>(&mut self, facade: &F) {
        self.vertex_buffer = Some(VertexBuffer::new(facade, &self.vertices)
                                  .expect("Failed to create vertex buffer!"));
        for mesh in &mut self.meshes {
            mesh.upload_data(facade);
        }
        for material in &mut self.materials {
            material.upload_textures(facade);
        }
        let vertices = vec!(
            Vertex { position: [-1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 0.0] },
            Vertex { position: [1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 0.0] },
            Vertex { position: [1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 1.0] },
            Vertex { position: [-1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 1.0] },
        );
        self.image_vertex_buffer = Some(VertexBuffer::new(facade, &vertices)
                                  .expect("Failed to create vertex buffer!"));
        let indices = vec!(0, 1, 2, 0, 2, 3);
        self.image_index_buffer = Some(IndexBuffer::new(facade, glium::index::PrimitiveType::TrianglesList,
                                                        &indices) .expect("Failed to create index buffer!"));
    }

    fn init_renderers<F: Facade>(&mut self, facade: &F) {
        // Preview shader
        let vertex_shader_src = include_str!("../preview.vert");
        let fragment_shader_src = include_str!("../preview.frag");
        let program = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        self.preview_shader = Some(program);

        // Image shader
        let vertex_shader_src = include_str!("../image.vert");
        let fragment_shader_src = include_str!("../image.frag");
        let program = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        self.image_shader = Some(program);
    }

    pub fn draw<S: Surface>(&self, target: &mut S, world_to_clip: Matrix4<f32>) {
        let draw_parameters = DrawParameters {
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        for mesh in &self.meshes {
            let material = &self.materials[mesh.material_i];
            let uniforms = uniform! {
                local_to_world: array4x4(mesh.local_to_world),
                world_to_clip: array4x4(world_to_clip),
                u_light: [-1.0, 0.4, 0.9f32],
                u_color: material.diffuse,
                u_has_diffuse: material.diffuse_image.is_some(),
                tex_diffuse: material.diffuse_texture.as_ref().expect("Use of unloaded texture!")
            };
            target.draw(self.vertex_buffer.as_ref().expect("No vertex buffer"),
                        mesh.index_buffer.as_ref().expect("No index buffer!"),
                        self.preview_shader.as_ref().expect("No preview shader!"),
                        &uniforms, &draw_parameters).unwrap();
        }
    }

    pub fn trace<S: Surface, F: Facade>(&mut self, target: &mut S, facade: &F, width: u32, height: u32) {
        let draw_parameters = DrawParameters {
            .. Default::default()
        };
        let mut image = ImageBuffer::<Rgb<f32>, Vec<f32>>::new(width, height);
        for x in 0..width {
            for y in 0..height {
                image.put_pixel(x, y, Rgb {data: [x as f32 / width as f32,
                                                  y as f32 / height as f32,
                                                  (self.t % 255) as f32 / 255.0]});
            }
        }
        self.t += 1;
        let mut raw_image = RawImage2d::from_raw_rgb(image.into_raw(), (width, height));
        raw_image.format = glium::texture::ClientFormat::F32F32F32;
        let texture = Texture2d::new(facade, raw_image).expect("Failed to upload traced image!");
        let uniforms = uniform! {
            image: &texture,
        };
        target.draw(self.image_vertex_buffer.as_ref().expect("No vertex buffer"),
                    self.image_index_buffer.as_ref().expect("No index buffer!"),
                    self.image_shader.as_ref().expect("No image shader!"),
                    &uniforms, &draw_parameters).unwrap();
    }

    /// Get the center of the scene as defined by the bounding box
    pub fn get_center(&self) -> [f32; 3] {
        let mut res = [0.0f32; 3];
        for i in 0..2 {
            res[i] = (self.min[i] + self.max[i]) / 2.0;
        }
        res
    }

    /// Get the longest edge of the bounding box
    pub fn get_size(&self) -> f32 {
        let mut max = 0.0f32;
        for i in 0..2 {
            max = max.max(self.max[i] - self.min[i]);
        }
        max
    }

    /// Update the bounding box with new position
    fn update_ranges(&mut self, new_pos: [f32; 3]) {
        for i in 0..2 {
            self.min[i] = self.min[i].min(new_pos[i]);
        }
        for i in 0..2 {
            self.max[i] = self.max[i].max(new_pos[i]);
        }
    }
}
<commit_msg>Initial work for tracable triangles<commit_after>#![cfg_attr(feature="clippy", allow(forget_copy))]
extern crate image;

mod material;
mod mesh;
mod obj_load;

use std::collections::HashMap;
use std::path::Path;
use std::vec::Vec;

use glium;
use glium::{DrawParameters, VertexBuffer, IndexBuffer, Program, Surface};
use glium::backend::Facade;
use glium::texture::{RawImage2d, Texture2d};

use cgmath::Matrix4;
use cgmath::conv::*;

use self::image::{ImageBuffer, Rgb};

use self::mesh::Mesh;
use self::material::Material;

/// Renderer representation of a vertex
#[derive(Copy, Clone, Debug)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub tex_coords: [f32; 2]
}

implement_vertex!(Vertex, position, normal, tex_coords);

/// Tracable triangle
struct RTTriangle {
    vert_is: [usize; 3],
}

/// Renderer representation of a scene
#[derive(Default)]
pub struct Scene {
    pub vertices: Vec<Vertex>,
    pub meshes: Vec<Mesh>,
    pub materials: Vec<Material>,
    pub vertex_buffer: Option<VertexBuffer<Vertex>>,
    triangles: Vec<RTTriangle>,
    image_vertex_buffer: Option<VertexBuffer<Vertex>>,
    image_index_buffer: Option<IndexBuffer<u32>>,
    preview_shader: Option<Program>,
    image_shader: Option<Program>,
    t: u32,
    /// Bounding box of the scene
    pub min: [f32; 3],
    pub max: [f32; 3],
}

#[cfg_attr(feature="clippy", allow(needless_range_loop))]
impl Scene {
    pub fn init<F: Facade>(scene_path: &Path, facade: &F) -> Scene {
        let mut scene = Scene { .. Default::default() };
        scene.load_scene(scene_path);
        scene.upload_data(facade);
        scene.init_renderers(facade);
        scene
    }

    /// Load a scene from the given path
    fn load_scene(&mut self, scene_path: &Path) {
        let obj = obj_load::load_obj(scene_path).expect("Failed to load.");

        // Closure to calculate planar normal for a triangle
        let calculate_normal = |triangle: &obj_load::Triangle| -> [f32; 3] {
            let pos_i1 = triangle.index_vertices[0].pos_i;
            let pos_i2 = triangle.index_vertices[1].pos_i;
            let pos_i3 = triangle.index_vertices[2].pos_i;
            let pos_1 = obj.positions[pos_i1];
            let pos_2 = obj.positions[pos_i2];
            let pos_3 = obj.positions[pos_i3];
            let u = [pos_2[0] - pos_1[0],
                    pos_2[1] - pos_1[1],
                    pos_2[2] - pos_1[2]];
            let v = [pos_3[0] - pos_1[0],
                    pos_3[1] - pos_1[1],
                    pos_3[2] - pos_1[2]];
            [u[1]*v[2] - u[2]*v[1],
            u[2]*v[0] - u[0]*v[2],
            u[0]*v[1] - u[1]*v[0]]
        };

        // Group the polygons by materials for easy rendering
        let mut vertex_map = HashMap::new();
        for range in &obj.material_ranges {
            let obj_mat = obj.materials.get(&range.name)
                .expect(&::std::fmt::format(format_args!("Couldn't find material {}!", range.name)));
            let mut mesh = Mesh::new(self.materials.len());
            self.materials.push(Material::new(obj_mat));
            for tri in &obj.triangles[range.start_i..range.end_i] {
                let mut rt_tri = RTTriangle { vert_is: [0, 0, 0] };
                let default_tex_coords = [0.0; 2];
                for (i, index_vertex) in tri.index_vertices.iter().enumerate() {
                    match vertex_map.get(index_vertex) {
                        // Vertex has already been added
                        Some(&i) => mesh.indices.push(i),
                        None => {
                            // Add vertex to map
                            vertex_map.insert(index_vertex, self.vertices.len() as u32);
                            let pos = obj.positions[index_vertex.pos_i];
                            self.update_ranges(pos);

                            let tex_coords = match index_vertex.tex_i {
                                Some(tex_i) => obj.tex_coords[tex_i],
                                None => default_tex_coords
                            };
                            let normal = match index_vertex.normal_i {
                                Some(normal_i) => obj.normals[normal_i],
                                None => calculate_normal(tri)
                            };

                            mesh.indices.push(self.vertices.len() as u32);
                            rt_tri.vert_is[i] = self.vertices.len();
                            self.vertices.push(Vertex { position: pos, normal: normal,
                                                        tex_coords: tex_coords });
                        }
                    }
                }
                self.triangles.push(rt_tri);
            }
            if !mesh.indices.is_empty() {
                self.meshes.push(mesh);
            }
        }
    }

    /// Load the textures + vertex and index buffers to the GPU
    fn upload_data<F: Facade>(&mut self, facade: &F) {
        self.vertex_buffer = Some(VertexBuffer::new(facade, &self.vertices)
                                  .expect("Failed to create vertex buffer!"));
        for mesh in &mut self.meshes {
            mesh.upload_data(facade);
        }
        for material in &mut self.materials {
            material.upload_textures(facade);
        }
        let vertices = vec!(
            Vertex { position: [-1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 0.0] },
            Vertex { position: [1.0, -1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 0.0] },
            Vertex { position: [1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [1.0, 1.0] },
            Vertex { position: [-1.0, 1.0, 0.0],
                     normal: [0.0, 0.0, 0.0],
                     tex_coords: [0.0, 1.0] },
        );
        self.image_vertex_buffer = Some(VertexBuffer::new(facade, &vertices)
                                  .expect("Failed to create vertex buffer!"));
        let indices = vec!(0, 1, 2, 0, 2, 3);
        self.image_index_buffer = Some(IndexBuffer::new(facade, glium::index::PrimitiveType::TrianglesList,
                                                        &indices) .expect("Failed to create index buffer!"));
    }

    fn init_renderers<F: Facade>(&mut self, facade: &F) {
        // Preview shader
        let vertex_shader_src = include_str!("../preview.vert");
        let fragment_shader_src = include_str!("../preview.frag");
        let program = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        self.preview_shader = Some(program);

        // Image shader
        let vertex_shader_src = include_str!("../image.vert");
        let fragment_shader_src = include_str!("../image.frag");
        let program = glium::Program::from_source(facade, vertex_shader_src, fragment_shader_src, None)
            .expect("Failed to create program!");
        self.image_shader = Some(program);
    }

    pub fn draw<S: Surface>(&self, target: &mut S, world_to_clip: Matrix4<f32>) {
        let draw_parameters = DrawParameters {
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        };

        for mesh in &self.meshes {
            let material = &self.materials[mesh.material_i];
            let uniforms = uniform! {
                local_to_world: array4x4(mesh.local_to_world),
                world_to_clip: array4x4(world_to_clip),
                u_light: [-1.0, 0.4, 0.9f32],
                u_color: material.diffuse,
                u_has_diffuse: material.diffuse_image.is_some(),
                tex_diffuse: material.diffuse_texture.as_ref().expect("Use of unloaded texture!")
            };
            target.draw(self.vertex_buffer.as_ref().expect("No vertex buffer"),
                        mesh.index_buffer.as_ref().expect("No index buffer!"),
                        self.preview_shader.as_ref().expect("No preview shader!"),
                        &uniforms, &draw_parameters).unwrap();
        }
    }

    pub fn trace<S: Surface, F: Facade>(&mut self, target: &mut S, facade: &F, width: u32, height: u32) {
        let draw_parameters = DrawParameters {
            .. Default::default()
        };
        let mut image = ImageBuffer::<Rgb<f32>, Vec<f32>>::new(width, height);
        for x in 0..width {
            for y in 0..height {
                image.put_pixel(x, y, Rgb {data: [x as f32 / width as f32,
                                                  y as f32 / height as f32,
                                                  (self.t % 255) as f32 / 255.0]});
            }
        }
        self.t += 1;
        let mut raw_image = RawImage2d::from_raw_rgb(image.into_raw(), (width, height));
        raw_image.format = glium::texture::ClientFormat::F32F32F32;
        let texture = Texture2d::new(facade, raw_image).expect("Failed to upload traced image!");
        let uniforms = uniform! {
            image: &texture,
        };
        target.draw(self.image_vertex_buffer.as_ref().expect("No vertex buffer"),
                    self.image_index_buffer.as_ref().expect("No index buffer!"),
                    self.image_shader.as_ref().expect("No image shader!"),
                    &uniforms, &draw_parameters).unwrap();
    }

    /// Get the center of the scene as defined by the bounding box
    pub fn get_center(&self) -> [f32; 3] {
        let mut res = [0.0f32; 3];
        for i in 0..2 {
            res[i] = (self.min[i] + self.max[i]) / 2.0;
        }
        res
    }

    /// Get the longest edge of the bounding box
    pub fn get_size(&self) -> f32 {
        let mut max = 0.0f32;
        for i in 0..2 {
            max = max.max(self.max[i] - self.min[i]);
        }
        max
    }

    /// Update the bounding box with new position
    fn update_ranges(&mut self, new_pos: [f32; 3]) {
        for i in 0..2 {
            self.min[i] = self.min[i].min(new_pos[i]);
        }
        for i in 0..2 {
            self.max[i] = self.max[i].max(new_pos[i]);
        }
    }
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;
use spinlock::{Spinlock, SpinlockGuard};

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {
    // switch stack so we can park current thread

    call_on_stack(inner, current_rsp, scheduler_stack_top());

    fn inner(current_rsp: uint) -> ! {
        // park current thread
        let current = Thread::from_rsp(current_rsp);
        global().scheduler.park(current);

        schedule_inner();
    }
}

pub unsafe fn schedule() -> ! {
    call_on_stack(inner, scheduler_stack_top());

    unsafe fn call_on_stack(function: fn() -> !, stack_top: uint) -> ! {
        asm!("call $0;" :: "r"(function), "{rsp}"(stack_top) :: "intel", "volatile");
        panic!("diverging fn returned");
    }

    fn inner() -> ! {
        // TODO FIXME kill current thread and deallocate stack
        schedule_inner()
    }
}

fn schedule_inner() -> ! {
    #[allow(improper_ctypes)]
    extern {
        fn pop_registers_and_iret(rsp: uint) -> !;
    }

    fn new_stack() -> uint {
        const NEW_STACK_SIZE: uint = 4096*2;
        let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
        let stack_top = stack_bottom as uint + NEW_STACK_SIZE;
        stack_top
    }

    fn invoke(function: Box<FnBox() + Send>) -> ! {
        unsafe{::enable_interrupts()};
        function.call_once(());
        unsafe{asm!("int $$66" :::: "volatile")};
        unreachable!();
    }

    // schedule new thread
    let new_thread = unsafe{global().scheduler.schedule().unwrap_or_default()};

    match new_thread {
        Thread{state: ThreadState::Active{rsp}} => {
            unsafe{pop_registers_and_iret(rsp)}
        },
        Thread{state: ThreadState::New{function}} => {
            println!("new");
            let new_stack_top = new_stack();
            unsafe{call_on_stack(invoke, function, new_stack_top)}
        },
    }
}

fn scheduler_stack_top() -> uint {
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    &SCHEDULER_STACK as *const [u8; 4096] as uint + SCHEDULER_STACK_SIZE
}

unsafe fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
    asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :
        : "intel", "volatile");
    panic!("diverging fn returned");
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

struct NonInterruptableSpinlock<T>(Spinlock<T>);

impl<T> NonInterruptableSpinlock<T> {
    pub fn lock(&self) -> SpinlockGuard<T> {
        unsafe{::disable_interrupts()};
        self.0.lock()
    }
}

pub struct GlobalScheduler {
    threads: NonInterruptableSpinlock<RingBuf<Thread>>,
}

impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        GlobalScheduler{
            threads: NonInterruptableSpinlock(Spinlock::new(RingBuf::new())),
        }
    }

    fn spawn<F, R>(&self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.lock().push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        unsafe{::enable_interrupts()};

        Future/*::from_receiver(rx)*/
    }

    fn park(&self, thread: Thread) {
        self.threads.lock().push_back(thread)
    }

    unsafe fn schedule(&self) -> Option<Thread> {
        self.threads.lock().pop_front()
    }
}<commit_msg>resume current thread if try_park doesn't get the spinlock<commit_after>use core::prelude::*;
use core::default::Default;
use boxed::Box;
use fn_box::FnBox;
use collections::RingBuf;
use global::global;
use alloc::heap::allocate;
use spinlock::{Spinlock, SpinlockGuard};

pub fn spawn<F, R>(f:F) -> Future<R> where F: FnOnce()->R, F:Send {
    global().scheduler.spawn(f)
}

pub unsafe fn reschedule(current_rsp: uint) -> ! {
    // switch stack so we can park current thread

    call_on_stack(inner, current_rsp, scheduler_stack_top());

    fn inner(current_rsp: uint) -> ! {
        // try to park current thread
        let current = Thread::from_rsp(current_rsp);
        let scheduler = &global().scheduler;

        let thread = match scheduler.try_park(current) {
            Ok(()) => scheduler.schedule(),
            Err(thread) => thread,
        };
        start_thread(thread)
    }
}

pub unsafe fn schedule() -> ! {
    call_on_stack(inner, scheduler_stack_top());

    unsafe fn call_on_stack(function: fn() -> !, stack_top: uint) -> ! {
        asm!("call $0;" :: "r"(function), "{rsp}"(stack_top) :: "intel", "volatile");
        panic!("diverging fn returned");
    }

    fn inner() -> ! {
        // TODO FIXME kill current thread and deallocate stack
        start_thread(global().scheduler.schedule())
    }
}

fn start_thread(thread: Thread) -> ! {
    #[allow(improper_ctypes)]
    extern {
        fn pop_registers_and_iret(rsp: uint) -> !;
    }

    fn new_stack() -> uint {
        const NEW_STACK_SIZE: uint = 4096*2;
        let stack_bottom = unsafe{allocate(NEW_STACK_SIZE, 4096)};
        let stack_top = stack_bottom as uint + NEW_STACK_SIZE;
        stack_top
    }

    fn invoke(function: Box<FnBox() + Send>) -> ! {
        unsafe{::enable_interrupts()};
        function.call_once(());
        unsafe{asm!("int $$66" :::: "volatile")};
        unreachable!();
    }

    match thread {
        Thread{state: ThreadState::Active{rsp}} => {
            unsafe{pop_registers_and_iret(rsp)}
        },
        Thread{state: ThreadState::New{function}} => {
            println!("new");
            let new_stack_top = new_stack();
            unsafe{call_on_stack(invoke, function, new_stack_top)}
        },
    }
}

fn scheduler_stack_top() -> uint {
    const SCHEDULER_STACK_SIZE: uint = 4096;
    static SCHEDULER_STACK: [u8; SCHEDULER_STACK_SIZE] = [0; SCHEDULER_STACK_SIZE];

    &SCHEDULER_STACK as *const [u8; 4096] as uint + SCHEDULER_STACK_SIZE
}

unsafe fn call_on_stack<Arg>(function: fn(Arg) -> !, arg: Arg, stack_top: uint) -> ! {
    asm!("call $0;" :: "r"(function), "{rdi}"(arg), "{rsp}"(stack_top) :
        : "intel", "volatile");
    panic!("diverging fn returned");
}

pub struct Future<T>;

pub struct Thread {
    state: ThreadState,
}

impl Thread {
    fn new<F>(f: F) -> Thread where F : FnOnce(), F: Send {
        Thread {
            state: ThreadState::New {
                function: box f,
            }
        }
    }

    pub fn from_rsp(rsp: uint) -> Thread {
        Thread {
            state: ThreadState::Active {
                rsp: rsp,
            }
        }
    }
}

impl Default for Thread {
    fn default() -> Thread {
        Thread::new(|| print!("."))
    }
}

enum ThreadState {
    New {
        function: Box<FnBox() + Send>,
    },
    Active {
        rsp: uint,
    }
}

pub struct GlobalScheduler {
    threads: Spinlock<RingBuf<Thread>>,
}

impl GlobalScheduler {
    pub fn new() -> GlobalScheduler {
        GlobalScheduler{
            threads: Spinlock::new(RingBuf::new()),
        }
    }

    fn spawn<F, R>(&self, f:F) -> Future<R> where F: FnOnce()->R, F: Send {

        //let (tx, rx) = channel();

        self.threads.lock().push_back(Thread::new(move |:| {
            /*tx.send_opt(*/ f();
        }));

        unsafe{::enable_interrupts()};

        Future/*::from_receiver(rx)*/
    }

    fn try_park(&self, thread: Thread) -> Result<(), Thread> {
        match self.threads.try_lock() {
            Some(mut threads) => Ok(threads.push_back(thread)),
            None => Err(thread),
        }
    }

    fn schedule(&self) -> Thread {
        self.threads.lock().pop_front().unwrap_or_default()
    }
}<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Generating numbers between two others.

// this is surprisingly complicated to be both generic & correct

use std::num::Wrapping as w;

use Rng;
use distributions::{Sample, IndependentSample};

/// Sample values uniformly between two bounds.
///
/// This gives a uniform distribution (assuming the RNG used to sample
/// it is itself uniform & the `SampleRange` implementation for the
/// given type is correct), even for edge cases like `low = 0u8`,
/// `high = 170u8`, for which a naive modulo operation would return
/// numbers less than 85 with double the probability to those greater
/// than 85.
///
/// Types should attempt to sample in `[low, high)`, i.e., not
/// including `high`, but this may be very difficult. All the
/// primitive integer types satisfy this property, and the float types
/// normally satisfy it, but rounding may mean `high` can occur.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Range};
///
/// fn main() {
///     let between = Range::new(10, 10000);
///     let mut rng = rand::thread_rng();
///     let mut sum = 0;
///     for _ in 0..1000 {
///         sum += between.ind_sample(&mut rng);
///     }
///     println!("{}", sum);
/// }
/// ```
#[derive(Clone, Copy)]
pub struct Range<X> {
    low: X,
    range: X,
    accept_zone: X
}

impl<X: SampleRange + PartialOrd> Range<X> {
    /// Create a new `Range` instance that samples uniformly from
    /// `[low, high)`. Panics if `low >= high`.
    pub fn new(low: X, high: X) -> Range<X> {
        assert!(low < high, "Range::new called with `low >= high`");
        SampleRange::construct_range(low, high)
    }
}

impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
    #[inline]
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        SampleRange::sample_range(self, rng)
    }
}

/// The helper trait for types that have a sensible way to sample
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
pub trait SampleRange {
    /// Construct the `Range` object that `sample_range`
    /// requires. This should not ever be called directly, only via
    /// `Range::new`, which will check that `low < high`, so this
    /// function doesn't have to repeat the check.
    fn construct_range(low: Self, high: Self) -> Range<Self>;

    /// Sample a value from the given `Range` with the given `Rng` as
    /// a source of randomness.
    fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}

macro_rules! integer_impl {
    ($ty:ty, $unsigned:ident) => {
        impl SampleRange for $ty {
            // we play free and fast with unsigned vs signed here
            // (when $ty is signed), but that's fine, since the
            // contract of this macro is for $ty and $unsigned to be
            // "bit-equal", so casting between them is a no-op & a
            // bijection.

            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                let range = (w(high as $unsigned) - w(low as $unsigned)).0;
                let unsigned_max: $unsigned = ::std::$unsigned::MAX;

                // this is the largest number that fits into $unsigned
                // that `range` divides evenly, so, if we've sampled
                // `n` uniformly from this region, then `n % range` is
                // uniform in [0, range)
                let zone = unsigned_max - unsigned_max % range;

                Range {
                    low: low,
                    range: range as $ty,
                    accept_zone: zone as $ty
                }
            }
            #[inline]
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                loop {
                    // rejection sample
                    let v = rng.gen::<$unsigned>();
                    // until we find something that fits into the
                    // region which r.range evenly divides (this will
                    // be uniformly distributed)
                    if v < r.accept_zone as $unsigned {
                        // and return it, with some adjustments
                        return (w(r.low) + w((v % r.range as $unsigned) as $ty)).0;
                    }
                }
            }
        }
    }
}

integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { isize, usize }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { usize, usize }

macro_rules! float_impl {
    ($ty:ty) => {
        impl SampleRange for $ty {
            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                Range {
                    low: low,
                    range: high - low,
                    accept_zone: 0.0 // unused
                }
            }
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                r.low + r.range * rng.gen::<$ty>()
            }
        }
    }
}

float_impl! { f32 }
float_impl! { f64 }

#[cfg(test)]
mod tests {
    use distributions::{Sample, IndependentSample};
    use super::Range as Range;

    #[should_panic]
    #[cfg_attr(target_env = "msvc", ignore)]
    #[test]
    fn test_range_bad_limits_equal() {
        Range::new(10, 10);
    }
    #[should_panic]
    #[cfg_attr(target_env = "msvc", ignore)]
    #[test]
    fn test_range_bad_limits_flipped() {
        Range::new(10, 5);
    }

    #[test]
    fn test_integers() {
        let mut rng = ::test::rng();
        macro_rules! t {
            ($($ty:ident),*) => {{
                $(
                   let v: &[($ty, $ty)] = &[(0, 10),
                                            (10, 127),
                                            (::std::$ty::MIN, ::std::$ty::MAX)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in 0..1000 {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        }
        t!(i8, i16, i32, i64, isize,
           u8, u16, u32, u64, usize)
    }

    #[test]
    fn test_floats() {
        let mut rng = ::test::rng();
        macro_rules! t {
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = &[(0.0, 100.0),
                                            (-1e35, -1e25),
                                            (1e-35, 1e-25),
                                            (-1e35, 1e35)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in 0..1000 {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        }

        t!(f32, f64)
    }

}
<commit_msg>Add Sized to SampleRange<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Generating numbers between two others.

// this is surprisingly complicated to be both generic & correct

use std::num::Wrapping as w;

use Rng;
use distributions::{Sample, IndependentSample};

/// Sample values uniformly between two bounds.
///
/// This gives a uniform distribution (assuming the RNG used to sample
/// it is itself uniform & the `SampleRange` implementation for the
/// given type is correct), even for edge cases like `low = 0u8`,
/// `high = 170u8`, for which a naive modulo operation would return
/// numbers less than 85 with double the probability to those greater
/// than 85.
///
/// Types should attempt to sample in `[low, high)`, i.e., not
/// including `high`, but this may be very difficult. All the
/// primitive integer types satisfy this property, and the float types
/// normally satisfy it, but rounding may mean `high` can occur.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{IndependentSample, Range};
///
/// fn main() {
///     let between = Range::new(10, 10000);
///     let mut rng = rand::thread_rng();
///     let mut sum = 0;
///     for _ in 0..1000 {
///         sum += between.ind_sample(&mut rng);
///     }
///     println!("{}", sum);
/// }
/// ```
#[derive(Clone, Copy)]
pub struct Range<X> {
    low: X,
    range: X,
    accept_zone: X
}

impl<X: SampleRange + PartialOrd> Range<X> {
    /// Create a new `Range` instance that samples uniformly from
    /// `[low, high)`. Panics if `low >= high`.
    pub fn new(low: X, high: X) -> Range<X> {
        assert!(low < high, "Range::new called with `low >= high`");
        SampleRange::construct_range(low, high)
    }
}

impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
    #[inline]
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        SampleRange::sample_range(self, rng)
    }
}

/// The helper trait for types that have a sensible way to sample
/// uniformly between two values. This should not be used directly,
/// and is only to facilitate `Range`.
pub trait SampleRange : Sized {
    /// Construct the `Range` object that `sample_range`
    /// requires. This should not ever be called directly, only via
    /// `Range::new`, which will check that `low < high`, so this
    /// function doesn't have to repeat the check.
    fn construct_range(low: Self, high: Self) -> Range<Self>;

    /// Sample a value from the given `Range` with the given `Rng` as
    /// a source of randomness.
    fn sample_range<R: Rng>(r: &Range<Self>, rng: &mut R) -> Self;
}

macro_rules! integer_impl {
    ($ty:ty, $unsigned:ident) => {
        impl SampleRange for $ty {
            // we play free and fast with unsigned vs signed here
            // (when $ty is signed), but that's fine, since the
            // contract of this macro is for $ty and $unsigned to be
            // "bit-equal", so casting between them is a no-op & a
            // bijection.

            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                let range = (w(high as $unsigned) - w(low as $unsigned)).0;
                let unsigned_max: $unsigned = ::std::$unsigned::MAX;

                // this is the largest number that fits into $unsigned
                // that `range` divides evenly, so, if we've sampled
                // `n` uniformly from this region, then `n % range` is
                // uniform in [0, range)
                let zone = unsigned_max - unsigned_max % range;

                Range {
                    low: low,
                    range: range as $ty,
                    accept_zone: zone as $ty
                }
            }
            #[inline]
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                loop {
                    // rejection sample
                    let v = rng.gen::<$unsigned>();
                    // until we find something that fits into the
                    // region which r.range evenly divides (this will
                    // be uniformly distributed)
                    if v < r.accept_zone as $unsigned {
                        // and return it, with some adjustments
                        return (w(r.low) + w((v % r.range as $unsigned) as $ty)).0;
                    }
                }
            }
        }
    }
}

integer_impl! { i8, u8 }
integer_impl! { i16, u16 }
integer_impl! { i32, u32 }
integer_impl! { i64, u64 }
integer_impl! { isize, usize }
integer_impl! { u8, u8 }
integer_impl! { u16, u16 }
integer_impl! { u32, u32 }
integer_impl! { u64, u64 }
integer_impl! { usize, usize }

macro_rules! float_impl {
    ($ty:ty) => {
        impl SampleRange for $ty {
            fn construct_range(low: $ty, high: $ty) -> Range<$ty> {
                Range {
                    low: low,
                    range: high - low,
                    accept_zone: 0.0 // unused
                }
            }
            fn sample_range<R: Rng>(r: &Range<$ty>, rng: &mut R) -> $ty {
                r.low + r.range * rng.gen::<$ty>()
            }
        }
    }
}

float_impl! { f32 }
float_impl! { f64 }

#[cfg(test)]
mod tests {
    use distributions::{Sample, IndependentSample};
    use super::Range as Range;

    #[should_panic]
    #[cfg_attr(target_env = "msvc", ignore)]
    #[test]
    fn test_range_bad_limits_equal() {
        Range::new(10, 10);
    }
    #[should_panic]
    #[cfg_attr(target_env = "msvc", ignore)]
    #[test]
    fn test_range_bad_limits_flipped() {
        Range::new(10, 5);
    }

    #[test]
    fn test_integers() {
        let mut rng = ::test::rng();
        macro_rules! t {
            ($($ty:ident),*) => {{
                $(
                   let v: &[($ty, $ty)] = &[(0, 10),
                                            (10, 127),
                                            (::std::$ty::MIN, ::std::$ty::MAX)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in 0..1000 {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        }
        t!(i8, i16, i32, i64, isize,
           u8, u16, u32, u64, usize)
    }

    #[test]
    fn test_floats() {
        let mut rng = ::test::rng();
        macro_rules! t {
            ($($ty:ty),*) => {{
                $(
                   let v: &[($ty, $ty)] = &[(0.0, 100.0),
                                            (-1e35, -1e25),
                                            (1e-35, 1e-25),
                                            (-1e35, 1e35)];
                   for &(low, high) in v.iter() {
                        let mut sampler: Range<$ty> = Range::new(low, high);
                        for _ in 0..1000 {
                            let v = sampler.sample(&mut rng);
                            assert!(low <= v && v < high);
                            let v = sampler.ind_sample(&mut rng);
                            assert!(low <= v && v < high);
                        }
                    }
                 )*
            }}
        }

        t!(f32, f64)
    }

}
<|endoftext|>


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

//! Implementation of the ElasticSearch Query DSL.
//!
//! ElasticSearch offers a
//! [rich DSL for searches](https://www.elastic.co/guide/en/elasticsearch/reference/1.x/query-dsl.html).
//! It is JSON based, and therefore very easy to use and composable if using from a
//! dynamic language (e.g.
//! [Ruby](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl#features-overview));
//! but Rust, being a staticly-typed language, things are different.  The `rs_es::query`
//! module defines a set of builder objects which can be similarly composed to the same
//! ends.
//!
//! For example:
//!
//! ```rust
//! use rs_es::query::Query;
//!
//! let query = Query::build_bool()
//!     .with_must(vec![Query::build_term("field_a",
//!                                       "value").build(),
//!                     Query::build_range("field_b")
//!                           .with_gte(5)
//!                           .with_lt(10)
//!                           .build()])
//!     .build();
//! ```

use std::collections::BTreeMap;

use serde::{Serialize, Serializer};

use ::json::ShouldSkip;
use ::util::StrJoin;

#[macro_use]
mod common;

pub mod compound;
pub mod full_text;
pub mod functions;
pub mod geo;
pub mod joining;
pub mod specialized;
pub mod term;

// Miscellaneous types required by queries go here

// Enums

/// Minimum should match - used in numerous queries
/// TODO: should go somewhere specific
#[derive(Debug)]
pub struct CombinationMinimumShouldMatch {
    first: MinimumShouldMatch,
    second: MinimumShouldMatch
}

impl CombinationMinimumShouldMatch {
    pub fn new(first: A, second: B) -> CombinationMinimumShouldMatch
        where A: Into<MinimumShouldMatch>,
              B: Into<MinimumShouldMatch>
    {
        CombinationMinimumShouldMatch {
            first:  first.into(),
            second: second.into()
        }
    }
}

impl ToString for CombinationMinimumShouldMatch {
    fn to_string(&self) -> String {
        format!("{}<{}", self.first.to_string(), self.second.to_string())
    }
}

impl Serialize for CombinationMinimumShouldMatch {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        self.to_string().serialize(serializer)
    }
}

#[derive(Debug)]
pub enum MinimumShouldMatch {
    Integer(i64),
    Percentage(f64),
    Combination(Box<CombinationMinimumShouldMatch>),
    MultipleCombination(Vec<CombinationMinimumShouldMatch>),
    LowHigh(i64, i64)
}

from!(i64, MinimumShouldMatch, Integer);
from!(f64, MinimumShouldMatch, Percentage);
from_exp!(CombinationMinimumShouldMatch,
          MinimumShouldMatch,
          from,
          MinimumShouldMatch::Combination(Box::new(from)));
from!(Vec<CombinationMinimumShouldMatch>, MinimumShouldMatch, MultipleCombination);
from_exp!((i64, i64),
          MinimumShouldMatch,
          from,
          MinimumShouldMatch::LowHigh(from.0, from.1));

impl ToString for MinimumShouldMatch {
    fn to_string(&self) -> String {
        match self {
            &MinimumShouldMatch::Integer(val) => val.to_string(),
            &MinimumShouldMatch::Percentage(val) => {
                format!("{}%", val)
            },
            _ => panic!("Can't convert {:?} to String", self)
        }
    }
}

impl Serialize for MinimumShouldMatch {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        match self {
            &MinimumShouldMatch::Integer(val) => val.serialize(serializer),
            &MinimumShouldMatch::Percentage(_) => self.to_string().serialize(serializer),
            &MinimumShouldMatch::Combination(ref comb) => comb.serialize(serializer),
            &MinimumShouldMatch::MultipleCombination(ref combs) => {
                combs.iter().map(|c| c.to_string()).join(" ").serialize(serializer)
            },
            &MinimumShouldMatch::LowHigh(low, high) => {
                let mut d = BTreeMap::new();
                d.insert("low_freq", low);
                d.insert("high_freq", high);
                d.serialize(serializer)
            }
        }
    }
}

/// Fuzziness
#[derive(Debug)]
pub enum Fuzziness {
    Auto,
    LevenshteinDistance(i64),
    Proportionate(f64)
}

from!(i64, Fuzziness, LevenshteinDistance);
from!(f64, Fuzziness, Proportionate);

impl Serialize for Fuzziness {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {

        use self::Fuzziness::*;
        match self {
            &Auto => "auto".serialize(serializer),
            &LevenshteinDistance(dist) => dist.serialize(serializer),
            &Proportionate(p) => p.serialize(serializer)
        }
    }
}

// Flags

/// Flags - multiple operations can take a set of flags, each set is dependent
/// on the operation in question, but they're all formatted to a similar looking
/// String
#[derive(Debug)]
pub struct Flags(Vec)
    where A: AsRef<str>;

impl Serialize for Flags
    where A: AsRef<str> {

    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {

        self.0.iter().join("|").serialize(serializer)
    }
}

impl From<Vec> for Flags
    where A: AsRef<str> {

    fn from(from: Vec) -> Self {
        Flags(from)
    }
}

/// ScoreMode
#[derive(Debug)]
pub enum ScoreMode {
    Multiply,
    Sum,
    Avg,
    First,
    Max,
    Min
}

impl Serialize for ScoreMode {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        match self {
            &ScoreMode::Multiply => "multiply".serialize(serializer),
            &ScoreMode::Sum => "sum".serialize(serializer),
            &ScoreMode::Avg => "avg".serialize(serializer),
            &ScoreMode::First => "first".serialize(serializer),
            &ScoreMode::Max => "max".serialize(serializer),
            &ScoreMode::Min => "min".serialize(serializer)
        }
    }
}

/// Query represents all available queries
///
/// Each value is boxed as Queries can be recursive, they also vary
/// significantly in size

// TODO: Filters and Queries are merged, ensure all filters are included in this enum
#[derive(Debug, Serialize)]
pub enum Query {
    // TODO - uncomment one-level to re-enable after Serdeification
    #[serde(rename="match_all")]
    MatchAll(Box<MatchAllQuery>),

    // Full-text queries
    #[serde(rename="match")]
    Match(Box<full_text::MatchQuery>),
    #[serde(rename="multi_match")]
    MultiMatch(Box<full_text::MultiMatchQuery>),
    #[serde(rename="common")]
    Common(Box<full_text::CommonQuery>),
    #[serde(rename="query_string")]
    QueryString(Box<full_text::QueryStringQuery>),
    #[serde(rename="simple_query_string")]
    SimpleQueryString(Box<full_text::SimpleQueryStringQuery>),

    // // Term level queries
    #[serde(rename="term")]
    Term(Box<term::TermQuery>),
    #[serde(rename="terms")]
    Terms(Box<term::TermsQuery>),
    #[serde(rename="range")]
    Range(Box<term::RangeQuery>),
    #[serde(rename="exists")]
    Exists(Box<term::ExistsQuery>),
    // // Not implementing the Missing query, as it's deprecated, use `must_not` and `Exists`
    // // instead
    #[serde(rename="prefix")]
    Prefix(Box<term::PrefixQuery>),
    #[serde(rename="wildcard")]
    Wildcard(Box<term::WildcardQuery>),
    #[serde(rename="regexp")]
    Regexp(Box<term::RegexpQuery>),
    #[serde(rename="fuzzy")]
    Fuzzy(Box<term::FuzzyQuery>),
    #[serde(rename="type")]
    Type(Box<term::TypeQuery>),
    #[serde(rename="ids")]
    Ids(Box<term::IdsQuery>),

    // Compound queries
    #[serde(rename="constant_score")]
    ConstantScore(Box<compound::ConstantScoreQuery>),
    #[serde(rename="bool")]
    Bool(Box<compound::BoolQuery>),
    #[serde(rename="dis_max")]
    DisMax(Box<compound::DisMaxQuery>),
    #[serde(rename="function_score")]
    FunctionScore(Box<compound::FunctionScoreQuery>),
    #[serde(rename="boosting")]
    Boosting(Box<compound::BoostingQuery>),
    #[serde(rename="indices")]
    Indices(Box<compound::IndicesQuery>),
    // // Not implementing the And query, as it's deprecated, use `bool` instead.
    // // Not implementing the Not query, as it's deprecated
    // // Not implementing the Or query, as it's deprecated, use `bool` instead.
    // // Not implementing the Filtered query, as it's deprecated.
    // // Not implementing the Limit query, as it's deprecated.

    // Joining queries
    #[serde(rename="nested")]
    Nested(Box<joining::NestedQuery>),
    #[serde(rename="has_child")]
    HasChild(Box<joining::HasChildQuery>),
    #[serde(rename="has_parent")]
    HasParent(Box<joining::HasParentQuery>),

    // Geo queries
    #[serde(rename="geo_shape")]
    GeoShape(Box<geo::GeoShapeQuery>),
    #[serde(rename="geo_bounding_box")]
    GeoBoundingBox(Box<geo::GeoBoundingBoxQuery>),
    #[serde(rename="geo_distance")]
    GeoDistance(Box<geo::GeoDistanceQuery>),
    // TODO: implement me - pending changes to range query
    //GeoDistanceRange(Box<geo::GeoDistanceRangeQuery>)
    #[serde(rename="geo_polygon")]
    GeoPolygon(Box<geo::GeoPolygonQuery>),
    #[serde(rename="geohash_cell")]
    GeohashCell(Box<geo::GeohashCellQuery>),

    // Specialized queries
    #[serde(rename="more_like_this")]
    MoreLikeThis(Box<specialized::MoreLikeThisQuery>),
    // TODO: template queries
    // TODO: Search by script

    // Span queries
    // TODO: SpanTerm(Box<term::TermQuery>),
    // TODO: Span multi term query
    // TODO: Span first query
    // TODO: Span near query
    // TODO: Span or query
    // TODO: Span not query
    // TODO: Span containing query
    // TODO: Span within query
}

impl Default for Query {
    fn default() -> Query {
        Query::MatchAll(Default::default())
    }
}

// Specific query types go here

/// Match all query

#[derive(Debug, Default, Serialize)]
pub struct MatchAllQuery {
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    boost: Option<f64>,
}

impl Query {
    pub fn build_match_all() -> MatchAllQuery {
        MatchAllQuery::default()
    }
}

impl MatchAllQuery {
    add_option!(with_boost, boost, f64);

    build!(MatchAll);
}

#[cfg(test)]
mod tests {
    extern crate serde_json;

    use super::{Flags, Query};
    use super::full_text::SimpleQueryStringFlags;
    use super::functions::Function;
    use super::term::TermsQueryLookup;

    #[test]
    fn test_simple_query_string_flags() {
        let opts = vec![SimpleQueryStringFlags::And, SimpleQueryStringFlags::Not];
        let flags:Flags<SimpleQueryStringFlags> = opts.into();
        let json = serde_json::to_string(&flags);
        assert_eq!("\"AND|NOT\"", json.unwrap());
    }

    #[test]
    fn test_terms_query() {
        let terms_query = Query::build_terms("field_name")
            .with_values(vec!["a", "b", "c"])
            .build();
        assert_eq!("{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
                   serde_json::to_string(&terms_query).unwrap());

        let terms_query_2 = Query::build_terms("field_name")
            .with_values(["a", "b", "c"].as_ref())
            .build();
        assert_eq!("{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
                   serde_json::to_string(&terms_query_2).unwrap());

        let terms_query_3 = Query::build_terms("field_name")
            .with_values(TermsQueryLookup::new(123, "blah.de.blah").with_index("other"))
            .build();
        assert_eq!("{\"terms\":{\"field_name\":{\"id\":123,\"index\":\"other\",\"path\":\"blah.de.blah\"}}}",
                   serde_json::to_string(&terms_query_3).unwrap());
    }

    // TODO - re-enable
    // #[test]
    // fn test_function_score_query() {
    //     let function_score_query = Query::build_function_score()
    //         .with_function(Function::build_script_score("this_is_a_script")
    //                        .with_lang("made_up")
    //                        .add_param("A", 12)
    //                        .build())
    //         .build();
    //     assert_eq!("{\"function_score\":{\"functions\":[{\"script_score\":{\"inline\":\"this_is_a_script\",\"lang\":\"made_up\",\"params\":{\"A\":12}}}]}}",
    //                function_score_query.to_json().to_string());
    // }
}
<commit_msg>Re-enabled Function Score Query test<commit_after>/*
 * Copyright 2015-2016 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Implementation of the ElasticSearch Query DSL.
//!
//! ElasticSearch offers a
//! [rich DSL for searches](https://www.elastic.co/guide/en/elasticsearch/reference/1.x/query-dsl.html).
//! It is JSON based, and therefore very easy to use and composable if using from a
//! dynamic language (e.g.
//! [Ruby](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl#features-overview));
//! but Rust, being a staticly-typed language, things are different.  The `rs_es::query`
//! module defines a set of builder objects which can be similarly composed to the same
//! ends.
//!
//! For example:
//!
//! ```rust
//! use rs_es::query::Query;
//!
//! let query = Query::build_bool()
//!     .with_must(vec![Query::build_term("field_a",
//!                                       "value").build(),
//!                     Query::build_range("field_b")
//!                           .with_gte(5)
//!                           .with_lt(10)
//!                           .build()])
//!     .build();
//! ```

use std::collections::BTreeMap;

use serde::{Serialize, Serializer};

use ::json::ShouldSkip;
use ::util::StrJoin;

#[macro_use]
mod common;

pub mod compound;
pub mod full_text;
pub mod functions;
pub mod geo;
pub mod joining;
pub mod specialized;
pub mod term;

// Miscellaneous types required by queries go here

// Enums

/// Minimum should match - used in numerous queries
/// TODO: should go somewhere specific
#[derive(Debug)]
pub struct CombinationMinimumShouldMatch {
    first: MinimumShouldMatch,
    second: MinimumShouldMatch
}

impl CombinationMinimumShouldMatch {
    pub fn new(first: A, second: B) -> CombinationMinimumShouldMatch
        where A: Into<MinimumShouldMatch>,
              B: Into<MinimumShouldMatch>
    {
        CombinationMinimumShouldMatch {
            first:  first.into(),
            second: second.into()
        }
    }
}

impl ToString for CombinationMinimumShouldMatch {
    fn to_string(&self) -> String {
        format!("{}<{}", self.first.to_string(), self.second.to_string())
    }
}

impl Serialize for CombinationMinimumShouldMatch {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        self.to_string().serialize(serializer)
    }
}

#[derive(Debug)]
pub enum MinimumShouldMatch {
    Integer(i64),
    Percentage(f64),
    Combination(Box<CombinationMinimumShouldMatch>),
    MultipleCombination(Vec<CombinationMinimumShouldMatch>),
    LowHigh(i64, i64)
}

from!(i64, MinimumShouldMatch, Integer);
from!(f64, MinimumShouldMatch, Percentage);
from_exp!(CombinationMinimumShouldMatch,
          MinimumShouldMatch,
          from,
          MinimumShouldMatch::Combination(Box::new(from)));
from!(Vec<CombinationMinimumShouldMatch>, MinimumShouldMatch, MultipleCombination);
from_exp!((i64, i64),
          MinimumShouldMatch,
          from,
          MinimumShouldMatch::LowHigh(from.0, from.1));

impl ToString for MinimumShouldMatch {
    fn to_string(&self) -> String {
        match self {
            &MinimumShouldMatch::Integer(val) => val.to_string(),
            &MinimumShouldMatch::Percentage(val) => {
                format!("{}%", val)
            },
            _ => panic!("Can't convert {:?} to String", self)
        }
    }
}

impl Serialize for MinimumShouldMatch {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        match self {
            &MinimumShouldMatch::Integer(val) => val.serialize(serializer),
            &MinimumShouldMatch::Percentage(_) => self.to_string().serialize(serializer),
            &MinimumShouldMatch::Combination(ref comb) => comb.serialize(serializer),
            &MinimumShouldMatch::MultipleCombination(ref combs) => {
                combs.iter().map(|c| c.to_string()).join(" ").serialize(serializer)
            },
            &MinimumShouldMatch::LowHigh(low, high) => {
                let mut d = BTreeMap::new();
                d.insert("low_freq", low);
                d.insert("high_freq", high);
                d.serialize(serializer)
            }
        }
    }
}

/// Fuzziness
#[derive(Debug)]
pub enum Fuzziness {
    Auto,
    LevenshteinDistance(i64),
    Proportionate(f64)
}

from!(i64, Fuzziness, LevenshteinDistance);
from!(f64, Fuzziness, Proportionate);

impl Serialize for Fuzziness {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {

        use self::Fuzziness::*;
        match self {
            &Auto => "auto".serialize(serializer),
            &LevenshteinDistance(dist) => dist.serialize(serializer),
            &Proportionate(p) => p.serialize(serializer)
        }
    }
}

// Flags

/// Flags - multiple operations can take a set of flags, each set is dependent
/// on the operation in question, but they're all formatted to a similar looking
/// String
#[derive(Debug)]
pub struct Flags(Vec)
    where A: AsRef<str>;

impl Serialize for Flags
    where A: AsRef<str> {

    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {

        self.0.iter().join("|").serialize(serializer)
    }
}

impl From<Vec> for Flags
    where A: AsRef<str> {

    fn from(from: Vec) -> Self {
        Flags(from)
    }
}

/// ScoreMode
#[derive(Debug)]
pub enum ScoreMode {
    Multiply,
    Sum,
    Avg,
    First,
    Max,
    Min
}

impl Serialize for ScoreMode {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer {
        match self {
            &ScoreMode::Multiply => "multiply".serialize(serializer),
            &ScoreMode::Sum => "sum".serialize(serializer),
            &ScoreMode::Avg => "avg".serialize(serializer),
            &ScoreMode::First => "first".serialize(serializer),
            &ScoreMode::Max => "max".serialize(serializer),
            &ScoreMode::Min => "min".serialize(serializer)
        }
    }
}

/// Query represents all available queries
///
/// Each value is boxed as Queries can be recursive, they also vary
/// significantly in size

// TODO: Filters and Queries are merged, ensure all filters are included in this enum
#[derive(Debug, Serialize)]
pub enum Query {
    // TODO - uncomment one-level to re-enable after Serdeification
    #[serde(rename="match_all")]
    MatchAll(Box<MatchAllQuery>),

    // Full-text queries
    #[serde(rename="match")]
    Match(Box<full_text::MatchQuery>),
    #[serde(rename="multi_match")]
    MultiMatch(Box<full_text::MultiMatchQuery>),
    #[serde(rename="common")]
    Common(Box<full_text::CommonQuery>),
    #[serde(rename="query_string")]
    QueryString(Box<full_text::QueryStringQuery>),
    #[serde(rename="simple_query_string")]
    SimpleQueryString(Box<full_text::SimpleQueryStringQuery>),

    // // Term level queries
    #[serde(rename="term")]
    Term(Box<term::TermQuery>),
    #[serde(rename="terms")]
    Terms(Box<term::TermsQuery>),
    #[serde(rename="range")]
    Range(Box<term::RangeQuery>),
    #[serde(rename="exists")]
    Exists(Box<term::ExistsQuery>),
    // // Not implementing the Missing query, as it's deprecated, use `must_not` and `Exists`
    // // instead
    #[serde(rename="prefix")]
    Prefix(Box<term::PrefixQuery>),
    #[serde(rename="wildcard")]
    Wildcard(Box<term::WildcardQuery>),
    #[serde(rename="regexp")]
    Regexp(Box<term::RegexpQuery>),
    #[serde(rename="fuzzy")]
    Fuzzy(Box<term::FuzzyQuery>),
    #[serde(rename="type")]
    Type(Box<term::TypeQuery>),
    #[serde(rename="ids")]
    Ids(Box<term::IdsQuery>),

    // Compound queries
    #[serde(rename="constant_score")]
    ConstantScore(Box<compound::ConstantScoreQuery>),
    #[serde(rename="bool")]
    Bool(Box<compound::BoolQuery>),
    #[serde(rename="dis_max")]
    DisMax(Box<compound::DisMaxQuery>),
    #[serde(rename="function_score")]
    FunctionScore(Box<compound::FunctionScoreQuery>),
    #[serde(rename="boosting")]
    Boosting(Box<compound::BoostingQuery>),
    #[serde(rename="indices")]
    Indices(Box<compound::IndicesQuery>),
    // // Not implementing the And query, as it's deprecated, use `bool` instead.
    // // Not implementing the Not query, as it's deprecated
    // // Not implementing the Or query, as it's deprecated, use `bool` instead.
    // // Not implementing the Filtered query, as it's deprecated.
    // // Not implementing the Limit query, as it's deprecated.

    // Joining queries
    #[serde(rename="nested")]
    Nested(Box<joining::NestedQuery>),
    #[serde(rename="has_child")]
    HasChild(Box<joining::HasChildQuery>),
    #[serde(rename="has_parent")]
    HasParent(Box<joining::HasParentQuery>),

    // Geo queries
    #[serde(rename="geo_shape")]
    GeoShape(Box<geo::GeoShapeQuery>),
    #[serde(rename="geo_bounding_box")]
    GeoBoundingBox(Box<geo::GeoBoundingBoxQuery>),
    #[serde(rename="geo_distance")]
    GeoDistance(Box<geo::GeoDistanceQuery>),
    // TODO: implement me - pending changes to range query
    //GeoDistanceRange(Box<geo::GeoDistanceRangeQuery>)
    #[serde(rename="geo_polygon")]
    GeoPolygon(Box<geo::GeoPolygonQuery>),
    #[serde(rename="geohash_cell")]
    GeohashCell(Box<geo::GeohashCellQuery>),

    // Specialized queries
    #[serde(rename="more_like_this")]
    MoreLikeThis(Box<specialized::MoreLikeThisQuery>),
    // TODO: template queries
    // TODO: Search by script

    // Span queries
    // TODO: SpanTerm(Box<term::TermQuery>),
    // TODO: Span multi term query
    // TODO: Span first query
    // TODO: Span near query
    // TODO: Span or query
    // TODO: Span not query
    // TODO: Span containing query
    // TODO: Span within query
}

impl Default for Query {
    fn default() -> Query {
        Query::MatchAll(Default::default())
    }
}

// Specific query types go here

/// Match all query

#[derive(Debug, Default, Serialize)]
pub struct MatchAllQuery {
    #[serde(skip_serializing_if="ShouldSkip::should_skip")]
    boost: Option<f64>,
}

impl Query {
    pub fn build_match_all() -> MatchAllQuery {
        MatchAllQuery::default()
    }
}

impl MatchAllQuery {
    add_option!(with_boost, boost, f64);

    build!(MatchAll);
}

#[cfg(test)]
mod tests {
    extern crate serde_json;

    use super::{Flags, Query};
    use super::full_text::SimpleQueryStringFlags;
    use super::functions::Function;
    use super::term::TermsQueryLookup;

    #[test]
    fn test_simple_query_string_flags() {
        let opts = vec![SimpleQueryStringFlags::And, SimpleQueryStringFlags::Not];
        let flags:Flags<SimpleQueryStringFlags> = opts.into();
        let json = serde_json::to_string(&flags);
        assert_eq!("\"AND|NOT\"", json.unwrap());
    }

    #[test]
    fn test_terms_query() {
        let terms_query = Query::build_terms("field_name")
            .with_values(vec!["a", "b", "c"])
            .build();
        assert_eq!("{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
                   serde_json::to_string(&terms_query).unwrap());

        let terms_query_2 = Query::build_terms("field_name")
            .with_values(["a", "b", "c"].as_ref())
            .build();
        assert_eq!("{\"terms\":{\"field_name\":[\"a\",\"b\",\"c\"]}}",
                   serde_json::to_string(&terms_query_2).unwrap());

        let terms_query_3 = Query::build_terms("field_name")
            .with_values(TermsQueryLookup::new(123, "blah.de.blah").with_index("other"))
            .build();
        assert_eq!("{\"terms\":{\"field_name\":{\"id\":123,\"index\":\"other\",\"path\":\"blah.de.blah\"}}}",
                   serde_json::to_string(&terms_query_3).unwrap());
    }

    #[test]
    fn test_function_score_query() {
        let function_score_query = Query::build_function_score()
            .with_function(Function::build_script_score("this_is_a_script")
                           .with_lang("made_up")
                           .add_param("A", 12)
                           .build())
            .build();
        assert_eq!("{\"function_score\":{\"functions\":[{\"script_score\":{\"lang\":\"made_up\",\"params\":{\"A\":12},\"inline\":\"this_is_a_script\"}}]}}",
                   serde_json::to_string(&function_score_query).unwrap());
    }
}
<|endoftext|>


<commit_before>//! This module contains shareable mutable containers designed for enabling
//! and detecting race conditions in thread synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is typically done by showing that a given non-atomic
//! operation is properly encapsulated by the transactional semantics of the
//! synchronization protocol, and will never appear as half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to increase in future
//! hardware), and highly dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! Which is why I think we need some types whose operations are guaranteed to
//! be non-atomic under a set of reasonable assumptions, and which can easily be
//! observed to be in an inconsistent state.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type U like a `Cell<U>` would, but is guaranteed **not** to be read
//! or written to in a single atomic operation, even if the corresponding type U
//! can be atomically read or written to in hardware.
//!
//! In addition, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared states
//! being exposed to the outside world.
//!
//! # Requirements on U
//!
//! In principle, any Clone + Eq type U whose equality operator and clone()
//! implementation behave well even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could be used. This is true of all primitive
//! integral types and aggregates thereof, for example.
//!
//! However, in practice, unsynchronized concurrent read/write access to
//! arbitrary data from multiple threads constitutes a data race, which is
//! undefined behaviour in Rust even when it occurs inside an UnsafeCell. This
//! is problematic because rustc's optimizer allows itself to transform code
//! which relies on undefined behaviour however it likes, leading to breakages
//! in release builds such as infinite loops appearing out of nowhere.
//!
//! For this reason, we currently only support some specific types U which have
//! atomic load and store operations, implemented as part of an atomic wrapper
//! T. Note that although individual loads and stores to U are atomic, loads and
//! stores to RaceCell<T> are still guaranteed not to be atomic.

#![deny(missing_docs)]

use std::boxed::Box;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize};
use std::sync::atomic::Ordering;

/// Shareable mutable container for triggering and detecting write-after-read
/// data races in a well-controlled fashion. Operates on a type U through an
/// atomic wrapper type T.
pub struct RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Two copies of a value of type U are made. One is stored on the stack...
    local_contents: T,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it will rather have
    /// an averse effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T>,

    /// Rust really dislikes unused generic struct parameters, even if they are
    /// used in the implementation, so a PhantomData marker must be added for U
    unused: PhantomData<U>,
}
//
impl<T, U> RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: U) -> Self {
        RaceCell {
            local_contents: T::new(value.clone()),
            remote_version: Box::new(T::new(value)),
            unused: PhantomData,
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: U) {
        self.local_contents.relaxed_store(value.clone());
        self.remote_version.relaxed_store(value);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<U> {
        let local_data = self.local_contents.relaxed_load();
        let remote_data = self.remote_version.relaxed_load();
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: Debug + Eq> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent: a data race has occurred
    Inconsistent,
}

/// Atomic wrapper type for a value of type U
///
/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type U must be loaded and stored atomically. This requires synchronizing
/// accesses to it using things like the std::sync::atomic::AtomicXyz wrappers.
///
/// The only guarantee that we need is that loads and stores are atomic. We do
/// not need any other memory ordering guarantee. This is why we allow for
/// more wrapper type implementation freedom by not specifying memory orderings,
/// and internally relying only on relaxed ordering.
///
pub trait AtomicLoadStore<U> {
    /// Create an atomic wrapper for a value of type U
    fn new(v: U) -> Self;

    /// Atomically load a value from the wrapper
    fn relaxed_load(&self) -> U;

    /// Atomically store a new value into the wrapper
    fn relaxed_store(&self, val: U);
}
///
/// This macro implements support for non-generic standard atomic types
///
macro_rules! impl_load_store {
    ($($U:ty, $T:ty);*) => ($(
        impl AtomicLoadStore<$U> for $T {
            fn new(v: $U) -> $T {
                <$T>::new(v)
            }

            fn relaxed_load(&self) -> $U {
                <$T>::load(self, Ordering::Relaxed)
            }

            fn relaxed_store(&self, val: $U) {
                <$T>::store(self, val, Ordering::Relaxed)
            }
        }
    )*)
}
///
impl_load_store!{ bool,  AtomicBool;
                  isize, AtomicIsize;
                  usize, AtomicUsize }
///
/// Atomic pointers are a bit special as they are generic, for now we will just
/// treat them as a special case.
///
impl<V> AtomicLoadStore<*mut V> for AtomicPtr<V> {
    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn relaxed_load(&self) -> *mut V {
        <AtomicPtr<V>>::load(self, Ordering::Relaxed)
    }

    fn relaxed_store(&self, val: *mut V) {
        <AtomicPtr<V>>::store(self, val, Ordering::Relaxed)
    }
}

// Here are implementations of RaceCell for all stable hardware atomic types

/// Implementation of RaceCell for bool
pub type BoolRaceCell = RaceCell<AtomicBool, bool>;
/// Implementation of RaceCell for isize
pub type IsizeRaceCell = RaceCell<AtomicIsize, isize>;
/// Implementation of RaceCell for pointers
pub type PtrRaceCell<V> = RaceCell<AtomicPtr<V>, *mut V>;
/// Implementation of RaceCell for usize
pub type UsizeRaceCell = RaceCell<AtomicUsize, usize>;

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use std::sync::{Arc, Mutex};
    use super::{AtomicLoadStore, Racey};
    use super::{BoolRaceCell, IsizeRaceCell, UsizeRaceCell};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = BoolRaceCell::new(true);
        assert_eq!(cell.local_contents.relaxed_load(), true);
        assert_eq!(cell.remote_version.relaxed_load(), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = IsizeRaceCell::new(-42);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = UsizeRaceCell::new(0xbad);
        cell.local_contents.relaxed_store(0xdead);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(UsizeRaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races, with a
        // detection probability better than 1% for very obvious ones :)
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected: ", data_race_count);
                assert!(data_race_count > WRITES_COUNT/100);
            }
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(Mutex::new(UsizeRaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            }
        );
    }
}
<commit_msg>Implemented Debug and Clone on RaceCell<commit_after>//! This module contains shareable mutable containers designed for enabling
//! and detecting race conditions in thread synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is typically done by showing that a given non-atomic
//! operation is properly encapsulated by the transactional semantics of the
//! synchronization protocol, and will never appear as half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to increase in future
//! hardware), and highly dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! Which is why I think we need some types whose operations are guaranteed to
//! be non-atomic under a set of reasonable assumptions, and which can easily be
//! observed to be in an inconsistent state.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type U like a `Cell<U>` would, but is guaranteed **not** to be read
//! or written to in a single atomic operation, even if the corresponding type U
//! can be atomically read or written to in hardware.
//!
//! In addition, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared states
//! being exposed to the outside world.
//!
//! # Requirements on U
//!
//! In principle, any Clone + Eq type U whose equality operator and clone()
//! implementation behave well even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could be used. This is true of all primitive
//! integral types and aggregates thereof, for example.
//!
//! However, in practice, unsynchronized concurrent read/write access to
//! arbitrary data from multiple threads constitutes a data race, which is
//! undefined behaviour in Rust even when it occurs inside an UnsafeCell. This
//! is problematic because rustc's optimizer allows itself to transform code
//! which relies on undefined behaviour however it likes, leading to breakages
//! in release builds such as infinite loops appearing out of nowhere.
//!
//! For this reason, we currently only support some specific types U which have
//! atomic load and store operations, implemented as part of an atomic wrapper
//! T. Note that although individual loads and stores to U are atomic, loads and
//! stores to RaceCell<T> are still guaranteed not to be atomic.

#![deny(missing_docs)]

use std::boxed::Box;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize};
use std::sync::atomic::Ordering;

/// Shareable mutable container for triggering and detecting write-after-read
/// data races in a well-controlled fashion. Operates on a type U through an
/// atomic wrapper type T.
#[derive(Debug)]
pub struct RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Two copies of a value of type U are made. One is stored on the stack...
    local_contents: T,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it will rather have
    /// an averse effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T>,

    /// Rust really dislikes unused generic struct parameters, even if they are
    /// used in the implementation, so a PhantomData marker must be added for U
    unused: PhantomData<U>,
}
//
impl<T, U> RaceCell<T, U> where T: AtomicLoadStore<U>,
                                U: Clone + Debug + Eq {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: U) -> Self {
        RaceCell {
            local_contents: T::new(value.clone()),
            remote_version: Box::new(T::new(value)),
            unused: PhantomData,
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: U) {
        self.local_contents.relaxed_store(value.clone());
        self.remote_version.relaxed_store(value);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<U> {
        let local_data = self.local_contents.relaxed_load();
        let remote_data = self.remote_version.relaxed_load();
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}
//
impl<T, U> Clone for RaceCell<T, U> where T: AtomicLoadStore<U>,
                                          U: Clone + Debug + Eq {
    /// Making RaceCells cloneable allows putting them in concurrent containers
    fn clone(&self) -> Self {
        let local_copy = self.local_contents.relaxed_load();
        let remote_copy = self.remote_version.relaxed_load();
        RaceCell {
            local_contents: T::new(local_copy),
            remote_version: Box::new(T::new(remote_copy)),
            unused: PhantomData,
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: Debug + Eq> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent: a data race has occurred
    Inconsistent,
}

/// Atomic wrapper type for a value of type U
///
/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type U must be loaded and stored atomically. This requires synchronizing
/// accesses to it using things like the std::sync::atomic::AtomicXyz wrappers.
///
/// The only guarantee that we need is that loads and stores are atomic. We do
/// not need any other memory ordering guarantee. This is why we allow for
/// more wrapper type implementation freedom by not specifying memory orderings,
/// and internally relying only on relaxed ordering.
///
pub trait AtomicLoadStore<U> {
    /// Create an atomic wrapper for a value of type U
    fn new(v: U) -> Self;

    /// Atomically load a value from the wrapper
    fn relaxed_load(&self) -> U;

    /// Atomically store a new value into the wrapper
    fn relaxed_store(&self, val: U);
}
///
/// This macro implements support for non-generic standard atomic types
///
macro_rules! impl_load_store {
    ($($U:ty, $T:ty);*) => ($(
        impl AtomicLoadStore<$U> for $T {
            fn new(v: $U) -> $T {
                <$T>::new(v)
            }

            fn relaxed_load(&self) -> $U {
                <$T>::load(self, Ordering::Relaxed)
            }

            fn relaxed_store(&self, val: $U) {
                <$T>::store(self, val, Ordering::Relaxed)
            }
        }
    )*)
}
///
impl_load_store!{ bool,  AtomicBool;
                  isize, AtomicIsize;
                  usize, AtomicUsize }
///
/// Atomic pointers are a bit special as they are generic, for now we will just
/// treat them as a special case.
///
impl<V> AtomicLoadStore<*mut V> for AtomicPtr<V> {
    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn relaxed_load(&self) -> *mut V {
        <AtomicPtr<V>>::load(self, Ordering::Relaxed)
    }

    fn relaxed_store(&self, val: *mut V) {
        <AtomicPtr<V>>::store(self, val, Ordering::Relaxed)
    }
}

// Here are implementations of RaceCell for all stable hardware atomic types

/// Implementation of RaceCell for bool
pub type BoolRaceCell = RaceCell<AtomicBool, bool>;
/// Implementation of RaceCell for isize
pub type IsizeRaceCell = RaceCell<AtomicIsize, isize>;
/// Implementation of RaceCell for pointers
pub type PtrRaceCell<V> = RaceCell<AtomicPtr<V>, *mut V>;
/// Implementation of RaceCell for usize
pub type UsizeRaceCell = RaceCell<AtomicUsize, usize>;

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use std::sync::{Arc, Mutex};
    use super::{AtomicLoadStore, Racey};
    use super::{BoolRaceCell, IsizeRaceCell, UsizeRaceCell};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = BoolRaceCell::new(true);
        assert_eq!(cell.local_contents.relaxed_load(), true);
        assert_eq!(cell.remote_version.relaxed_load(), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = IsizeRaceCell::new(-42);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = UsizeRaceCell::new(0xbad);
        cell.local_contents.relaxed_store(0xdead);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// RaceCells should be cloned as-is, even if in an inconsistent state
    #[test]
    fn clone() {
        let cell = UsizeRaceCell::new(0xbeef);
        cell.local_contents.relaxed_store(0xdeaf);
        let clone = cell.clone();
        assert_eq!(clone.local_contents.relaxed_load(), 0xdeaf);
        assert_eq!(clone.remote_version.relaxed_load(), 0xbeef);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(UsizeRaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races, with a
        // detection probability better than 1% for very obvious ones :)
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected: ", data_race_count);
                assert!(data_race_count > WRITES_COUNT/100);
            }
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0;
        let cell1 = Arc::new(Mutex::new(UsizeRaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        ::concurrent_test_2(
            move || {
                for i in 1..(WRITES_COUNT+1) {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            }
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use walkdir::DirEntry;

use super::{Matcher, MatcherIO};

/// This matcher checks the type of the file.
pub struct PruneMatcher;

impl PruneMatcher {
    pub fn new() -> PruneMatcher {
        PruneMatcher {}
    }

    pub fn new_box() -> Box<dyn Matcher> {
        Box::new(PruneMatcher::new())
    }
}

impl Matcher for PruneMatcher {
    fn matches(&self, _: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
        matcher_io.mark_current_dir_to_be_skipped();
        true
    }
}
#[cfg(test)]

mod tests {
    use super::*;
    use crate::find::matchers::tests::get_dir_entry_for;
    use crate::find::matchers::Matcher;
    use crate::find::tests::FakeDependencies;

    #[test]
    fn file_type_matcher() {
        let dir = get_dir_entry_for("test_data", "simple");
        let deps = FakeDependencies::new();

        let mut matcher_io = deps.new_matcher_io();
        assert!(!matcher_io.should_skip_current_dir());
        let matcher = PruneMatcher::new();
        assert!(matcher.matches(&dir, &mut matcher_io));
        assert!(matcher_io.should_skip_current_dir());
    }
}
<commit_msg>Avoid skipping the entire directory if a file hits -prune<commit_after>// Copyright 2017 Google Inc.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

use walkdir::DirEntry;

use super::{Matcher, MatcherIO};

/// This matcher checks the type of the file.
pub struct PruneMatcher;

impl PruneMatcher {
    pub fn new() -> PruneMatcher {
        PruneMatcher {}
    }

    pub fn new_box() -> Box<dyn Matcher> {
        Box::new(PruneMatcher::new())
    }
}

impl Matcher for PruneMatcher {
    fn matches(&self, file_info: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
        if file_info.file_type().is_dir() {
            matcher_io.mark_current_dir_to_be_skipped();
        }

        true
    }
}
#[cfg(test)]

mod tests {
    use super::*;
    use crate::find::matchers::tests::get_dir_entry_for;
    use crate::find::matchers::Matcher;
    use crate::find::tests::FakeDependencies;

    #[test]
    fn file_type_matcher() {
        let dir = get_dir_entry_for("test_data", "simple");
        let deps = FakeDependencies::new();

        let mut matcher_io = deps.new_matcher_io();
        assert!(!matcher_io.should_skip_current_dir());
        let matcher = PruneMatcher::new();
        assert!(matcher.matches(&dir, &mut matcher_io));
        assert!(matcher_io.should_skip_current_dir());
    }

    #[test]
    fn only_skips_directories() {
        let abbbc = get_dir_entry_for("test_data/simple", "abbbc");
        let deps = FakeDependencies::new();

        let mut matcher_io = deps.new_matcher_io();
        assert!(!matcher_io.should_skip_current_dir());
        let matcher = PruneMatcher::new();
        assert!(matcher.matches(&abbbc, &mut matcher_io));
        assert!(!matcher_io.should_skip_current_dir());
    }
}
<|endoftext|>