<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::{RgbImage, 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 = RgbImage::new(width, height);
        for x in 0..width {
            for y in 0..height {
                image.put_pixel(x, y, Rgb {data: [(255.0 * x as f32 / width as f32) as u8,
                                                  (255.0 * y as f32 / height as f32) as u8,
                                                  self.t as u8]});
            }
        }
        self.t += 1;
        let raw_image = RawImage2d::from_raw_rgb(image.into_raw(), (width, height));
        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>Change image format to f32<commit_after>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]);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use rustc::ty::layout::{Size, Align};
use rustc_mir::interpret::{Pointer, Memory};
use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in std::env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let bytes = [name, b"=", value].concat();
    let tcx = {memory.tcx.tcx};
    let length = bytes.len() as u64;
    // `+1` for the null terminator.
    let ptr = memory.allocate(
        Size::from_bytes(length + 1),
        Align::from_bytes(1).unwrap(),
        MiriMemoryKind::Env.into(),
    );
    // We just allocated these, so the write cannot fail.
    let alloc = memory.get_mut(ptr.alloc_id).unwrap();
    alloc.write_bytes(&tcx, ptr, &bytes).unwrap();
    let trailing_zero_ptr = ptr.offset(
        Size::from_bytes(length),
        &tcx,
    ).unwrap();
    alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap();
    ptr
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }
}
<commit_msg>Auto merge of #938 - christianpoveda:clean-env-alloc, r=RalfJung<commit_after>use std::collections::HashMap;

use rustc::ty::layout::{Size};
use rustc_mir::interpret::{Pointer, Memory};
use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Default)]
pub struct EnvVars {
    /// Stores pointers to the environment variables. These variables must be stored as
    /// null-terminated C strings with the `"{name}={value}"` format.
    map: HashMap<Vec<u8>, Pointer<Tag>>,
}

impl EnvVars {
    pub(crate) fn init<'mir, 'tcx>(
        ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
        mut excluded_env_vars: Vec<String>,
    ) {
        // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
        excluded_env_vars.push("TERM".to_owned());

        if ecx.machine.communicate {
            for (name, value) in std::env::vars() {
                if !excluded_env_vars.contains(&name) {
                    let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
                }
            }
        }
    }
}

fn alloc_env_var<'mir, 'tcx>(
    name: &[u8],
    value: &[u8],
    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
) -> Pointer<Tag> {
    let mut bytes = name.to_vec();
    bytes.push(b'=');
    bytes.extend_from_slice(value);
    bytes.push(0);
    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn getenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, Scalar<Tag>> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let name = this.memory().read_c_str(name_ptr)?;
        Ok(match this.machine.env_vars.map.get(name) {
            // The offset is used to strip the "{name}=" part of the string.
            Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
            None => Scalar::ptr_null(&*this.tcx),
        })
    }

    fn setenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
        value_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let value_ptr = this.read_scalar(value_op)?.not_undef()?;
        let value = this.memory().read_c_str(value_ptr)?;
        let mut new = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?;
            if !name.is_empty() && !name.contains(&b'=') {
                new = Some((name.to_owned(), value.to_owned()));
            }
        }
        if let Some((name, value)) = new {
            let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
            if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }

    fn unsetenv(
        &mut self,
        name_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        let name_ptr = this.read_scalar(name_op)?.not_undef()?;
        let mut success = None;
        if !this.is_null(name_ptr)? {
            let name = this.memory().read_c_str(name_ptr)?.to_owned();
            if !name.is_empty() && !name.contains(&b'=') {
                success = Some(this.machine.env_vars.map.remove(&name));
            }
        }
        if let Some(old) = success {
            if let Some(var) = old {
                this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
            }
            Ok(0)
        } else {
            Ok(-1)
        }
    }
}
<|endoftext|>


<commit_before>//! Volume (base unit cubic meter, m3).

quantity! {
    /// Volume (base unit cubic meter, m3).
    quantity: Volume; "volume";
    /// Volume dimension, m3.
    dimension: ISQ<
        P3,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @cubic_yottameter: prefix!(yotta) * prefix!(yotta) * prefix!(yotta);
            "Ym³", "cubic yottameter", "cubic yottameters";
        @cubic_zettameter: prefix!(zetta) * prefix!(zetta) * prefix!(zetta);
            "Zm³", "cubic zettameter", "cubic zettameters";
        @cubic_exameter: prefix!(exa) * prefix!(exa) * prefix!(exa);
            "Em³", "cubic exameter", "cubic exameters";
        @cubic_petameter: prefix!(peta) * prefix!(peta) * prefix!(peta);
            "Pm³", "cubic petameter", "cubic petameters";
        @cubic_terameter: prefix!(tera) * prefix!(tera) * prefix!(tera);
            "Tm³", "cubic terameter", "cubic terameters";
        @cubic_gigameter: prefix!(giga) * prefix!(giga) * prefix!(giga);
            "Gm³", "cubic gigameter", "cubic gigameters";
        @cubic_megameter: prefix!(mega) * prefix!(mega) * prefix!(mega);
            "Mm³", "cubic megameter", "cubic megameters";
        @cubic_kilometer: prefix!(kilo) * prefix!(kilo) * prefix!(kilo);
            "km³", "cubic kilometer", "cubic kilometers";
        @cubic_hectometer: prefix!(hecto) * prefix!(hecto) * prefix!(hecto);
            "hm³", "cubic hectometer", "cubic hectometers";
        @cubic_decameter: prefix!(deca) * prefix!(deca) * prefix!(deca);
            "dam³", "cubic decameter", "cubic decameters";
        @cubic_meter: prefix!(none); "m³", "cubic meter", "cubic meters";
        @cubic_decimeter: prefix!(deci) * prefix!(deci) * prefix!(deci);
            "dm³", "cubic decimeter", "cubic decimeters";
        @cubic_centimeter: prefix!(centi) * prefix!(centi) * prefix!(centi);
            "cm³", "cubic centimeter", "cubic centimeters";
        @cubic_millimeter: prefix!(milli) * prefix!(milli) * prefix!(milli);
            "mm³", "cubic millimeter", "cubic millimeters";
        @cubic_micrometer: prefix!(micro) * prefix!(micro) * prefix!(micro);
            "µm³", "cubic micrometer", "cubic micrometers";
        @cubic_nanometer: prefix!(nano) * prefix!(nano) * prefix!(nano);
            "nm³", "cubic nanometer", "cubic nanometers";
        @cubic_picometer: prefix!(pico) * prefix!(pico) * prefix!(pico);
            "pm³", "cubic picometer", "cubic picometers";
        @cubic_femtometer: prefix!(femto) * prefix!(femto) * prefix!(femto);
            "fm³", "cubic femtometer", "cubic femtometers";
        @cubic_attometer: prefix!(atto) * prefix!(atto) * prefix!(atto);
            "am³", "cubic attometer", "cubic attometers";
        @cubic_zeptometer: prefix!(zepto) * prefix!(zepto) * prefix!(zepto);
            "zm³", "cubic zeptometer", "cubic zeptometers";
        @cubic_yoctometer: prefix!(yocto) * prefix!(yocto) * prefix!(yocto);
            "ym³", "cubic yoctometer", "cubic yoctometers";
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use lib::any::TypeId;
        use num::One;
        use si::quantities::*;
        use si::area as a;
        use si::volume as v;
        use si::length as l;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Volume<V> = Length::new::<l::meter>(V::one())
                * Length::new::<l::meter>(V::one())
                * Length::new::<l::meter>(V::one());
            let _: Volume<V> = Length::new::<l::meter>(V::one())
                * Area::new::(V::one());
        }

        #[test]
        fn check_units() {
            // Values too large for f32.
            if TypeId::of::<f64>() == TypeId::of::<V>() {
                test::<l::yottameter, v::cubic_yottameter>();
                test::<l::zettameter, v::cubic_zettameter>();
                test::<l::exameter, v::cubic_exameter>();
                test::<l::petameter, v::cubic_petameter>();
            }

            test::<l::terameter, v::cubic_terameter>();
            test::<l::gigameter, v::cubic_gigameter>();
            test::<l::megameter, v::cubic_megameter>();
            test::<l::kilometer, v::cubic_kilometer>();
            test::<l::hectometer, v::cubic_hectometer>();
            test::<l::decameter, v::cubic_decameter>();
            test::<l::meter, v::cubic_meter>();
            test::<l::decimeter, v::cubic_decimeter>();
            test::<l::centimeter, v::cubic_centimeter>();
            test::<l::millimeter, v::cubic_millimeter>();
            test::<l::micrometer, v::cubic_micrometer>();
            test::<l::nanometer, v::cubic_nanometer>();
            test::<l::picometer, v::cubic_picometer>();
            test::<l::femtometer, v::cubic_femtometer>();

            // Values too small for f32.
            if TypeId::of::<f64>() == TypeId::of::<V>() {
                test::<l::attometer, v::cubic_attometer>();
                test::<l::zeptometer, v::cubic_zeptometer>();
                test::<l::yoctometer, v::cubic_yoctometer>();
            }

            fn test<L: l::Conversion<V>, O: v::Conversion<V>>() {
                Test::assert_eq(&Volume::new::<O>(V::one()),
                    &(Length::new::<L>(V::one())
                        * Length::new::<L>(V::one())
                        * Length::new::<L>(V::one())));
            }
        }
    }
}
<commit_msg>Add additional volume units.<commit_after>//! Volume (base unit cubic meter, m3).

quantity! {
    /// Volume (base unit cubic meter, m3).
    quantity: Volume; "volume";
    /// Volume dimension, m3.
    dimension: ISQ<
        P3,     // length
        Z0,     // mass
        Z0,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @cubic_yottameter: prefix!(yotta) * prefix!(yotta) * prefix!(yotta);
            "Ym³", "cubic yottameter", "cubic yottameters";
        @cubic_zettameter: prefix!(zetta) * prefix!(zetta) * prefix!(zetta);
            "Zm³", "cubic zettameter", "cubic zettameters";
        @cubic_exameter: prefix!(exa) * prefix!(exa) * prefix!(exa);
            "Em³", "cubic exameter", "cubic exameters";
        @cubic_petameter: prefix!(peta) * prefix!(peta) * prefix!(peta);
            "Pm³", "cubic petameter", "cubic petameters";
        @cubic_terameter: prefix!(tera) * prefix!(tera) * prefix!(tera);
            "Tm³", "cubic terameter", "cubic terameters";
        @cubic_gigameter: prefix!(giga) * prefix!(giga) * prefix!(giga);
            "Gm³", "cubic gigameter", "cubic gigameters";
        @cubic_megameter: prefix!(mega) * prefix!(mega) * prefix!(mega);
            "Mm³", "cubic megameter", "cubic megameters";
        @cubic_kilometer: prefix!(kilo) * prefix!(kilo) * prefix!(kilo);
            "km³", "cubic kilometer", "cubic kilometers";
        @cubic_hectometer: prefix!(hecto) * prefix!(hecto) * prefix!(hecto);
            "hm³", "cubic hectometer", "cubic hectometers";
        @cubic_decameter: prefix!(deca) * prefix!(deca) * prefix!(deca);
            "dam³", "cubic decameter", "cubic decameters";
        @cubic_meter: prefix!(none); "m³", "cubic meter", "cubic meters";
        @cubic_decimeter: prefix!(deci) * prefix!(deci) * prefix!(deci);
            "dm³", "cubic decimeter", "cubic decimeters";
        @cubic_centimeter: prefix!(centi) * prefix!(centi) * prefix!(centi);
            "cm³", "cubic centimeter", "cubic centimeters";
        @cubic_millimeter: prefix!(milli) * prefix!(milli) * prefix!(milli);
            "mm³", "cubic millimeter", "cubic millimeters";
        @cubic_micrometer: prefix!(micro) * prefix!(micro) * prefix!(micro);
            "µm³", "cubic micrometer", "cubic micrometers";
        @cubic_nanometer: prefix!(nano) * prefix!(nano) * prefix!(nano);
            "nm³", "cubic nanometer", "cubic nanometers";
        @cubic_picometer: prefix!(pico) * prefix!(pico) * prefix!(pico);
            "pm³", "cubic picometer", "cubic picometers";
        @cubic_femtometer: prefix!(femto) * prefix!(femto) * prefix!(femto);
            "fm³", "cubic femtometer", "cubic femtometers";
        @cubic_attometer: prefix!(atto) * prefix!(atto) * prefix!(atto);
            "am³", "cubic attometer", "cubic attometers";
        @cubic_zeptometer: prefix!(zepto) * prefix!(zepto) * prefix!(zepto);
            "zm³", "cubic zeptometer", "cubic zeptometers";
        @cubic_yoctometer: prefix!(yocto) * prefix!(yocto) * prefix!(yocto);
            "ym³", "cubic yoctometer", "cubic yoctometers";

        @acre_foot: 1.233_489_E3; "ac · ft", "acre-foot", "acre-feet";
        @barrel: 1.589_873_E-1; "bbl", "barrel", "barrels";
        @bushel: 3.523_907_E-2; "bu", "bushel", "bushels";
        @cord: 3.624_556_E0; "cords", "cord", "cords";
        @cubic_foot: 2.831_685_E-2; "ft³", "cubic foot", "cubic feet";
        @cubic_inch: 1.638_706_E-5; "in³", "cubic inch", "cubic inches";
        @cubic_mile: 4.168_182_E9; "mi³", "cubic mile", "cubic miles";
        @cubic_yard: 7.645_549_E-1; "yd³", "cubic yard", "cubic yards";
        @cup: 2.365_882_E-4; "cup", "cup", "cups";
        @fluid_ounce: 2.957_353_E-5; "fl oz", "fluid ounce", "fluid ounces";
        @fluid_ounce_imperial: 2.841_306_E-5; "fl oz (UK)", "Imperial fluid ounce", "Imperial fluid ounces";
        @gallon_imperial: 4.546_09_E-3; "gal (UK)", "Imperial gallon", "Imperial gallons";
        @gallon: 3.785_412_E-3; "gal", "gallon", "gallons";
        @gill_imperial: 1.420_653_E-4; "gi (UK)", "Imperial gill", "Imperial gills";
        @gill: 1.182_941_E-4; "gi", "gill", "gills";
        @liter: 1.0_E-3; "L", "liter", "liters";
        @peck: 8.809_768_E-3; "pk", "peck", "pecks";
        @pint_dry: 5.506_105_E-4; "dry pt", "dry pint", "dry pints";
        @pint_liquid: 4.731_765_E-4; "liq pt", "liquid pint", "liquid pints";
        @quart_dry: 1.101_221_E-3; "dry qt", "dry quart", "dry quarts";
        @quart_liquid: 9.463_529_E-4; "liq qt", "liquid quart", "liquid quarts";
        @stere: 1.0_E0; "st", "stere", "steres";
        @tablespoon: 1.478_676_E-5; "tbsp", "tablespoon", "tablespoons";
        @teaspoon: 4.928_922_E-6; "tsp", "teaspoon", "teaspoons";
        @register_ton: 2.831_685_E0; "RT", "register ton", "register tons";
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use lib::any::TypeId;
        use num::One;
        use si::quantities::*;
        use si::area as a;
        use si::volume as v;
        use si::length as l;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Volume<V> = Length::new::<l::meter>(V::one())
                * Length::new::<l::meter>(V::one())
                * Length::new::<l::meter>(V::one());
            let _: Volume<V> = Length::new::<l::meter>(V::one())
                * Area::new::(V::one());
        }

        #[test]
        fn check_units() {
            // Values too large for f32.
            if TypeId::of::<f64>() == TypeId::of::<V>() {
                test::<l::yottameter, v::cubic_yottameter>();
                test::<l::zettameter, v::cubic_zettameter>();
                test::<l::exameter, v::cubic_exameter>();
                test::<l::petameter, v::cubic_petameter>();
            }

            test::<l::terameter, v::cubic_terameter>();
            test::<l::gigameter, v::cubic_gigameter>();
            test::<l::megameter, v::cubic_megameter>();
            test::<l::kilometer, v::cubic_kilometer>();
            test::<l::hectometer, v::cubic_hectometer>();
            test::<l::decameter, v::cubic_decameter>();
            test::<l::meter, v::cubic_meter>();
            test::<l::decimeter, v::cubic_decimeter>();
            test::<l::centimeter, v::cubic_centimeter>();
            test::<l::millimeter, v::cubic_millimeter>();
            test::<l::micrometer, v::cubic_micrometer>();
            test::<l::nanometer, v::cubic_nanometer>();
            test::<l::picometer, v::cubic_picometer>();
            test::<l::femtometer, v::cubic_femtometer>();

            // Values too small for f32.
            if TypeId::of::<f64>() == TypeId::of::<V>() {
                test::<l::attometer, v::cubic_attometer>();
                test::<l::zeptometer, v::cubic_zeptometer>();
                test::<l::yoctometer, v::cubic_yoctometer>();
            }

            fn test<L: l::Conversion<V>, O: v::Conversion<V>>() {
                Test::assert_eq(&Volume::new::<O>(V::one()),
                    &(Length::new::<L>(V::one())
                        * Length::new::<L>(V::one())
                        * Length::new::<L>(V::one())));
            }
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gaol::platform;
use gaol::profile::{Operation, PathPattern, Profile};
use std::path::PathBuf;
use util::resource_files;

/// Our content process sandbox profile on Mac. As restrictive as possible.
#[cfg(target_os = "macos")]
pub fn content_process_sandbox_profile() -> Profile {
    Profile::new(vec![
        Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
        Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path())),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/Library/Fonts"))),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/System/Library/Fonts"))),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from(
                    "/System/Library/Frameworks/ApplicationServices.framework/"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/Library"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/System"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/etc"))),
        Operation::SystemInfoRead,
        Operation::PlatformSpecific(platform::macos::Operation::MachLookup(
                b"com.apple.FontServer".to_vec())),
    ]).expect("Failed to create sandbox profile!")
}

/// Our content process sandbox profile on Linux. As restrictive as possible.
#[cfg(not(target_os = "macos"))]
pub fn content_process_sandbox_profile() -> Profile {
    Profile::new(vec![
        Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
        Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path())),
    ]).expect("Failed to create sandbox profile!")
}

<commit_msg>Auto merge of #8615 - Ms2ger:unusued-import, r=SimonSapin<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gaol::profile::{Operation, PathPattern, Profile};
use std::path::PathBuf;
use util::resource_files;

/// Our content process sandbox profile on Mac. As restrictive as possible.
#[cfg(target_os = "macos")]
pub fn content_process_sandbox_profile() -> Profile {
    use gaol::platform;
    Profile::new(vec![
        Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
        Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path())),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/Library/Fonts"))),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/System/Library/Fonts"))),
        Operation::FileReadAll(PathPattern::Subpath(PathBuf::from(
                    "/System/Library/Frameworks/ApplicationServices.framework/"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/Library"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/System"))),
        Operation::FileReadMetadata(PathPattern::Literal(PathBuf::from("/etc"))),
        Operation::SystemInfoRead,
        Operation::PlatformSpecific(platform::macos::Operation::MachLookup(
                b"com.apple.FontServer".to_vec())),
    ]).expect("Failed to create sandbox profile!")
}

/// Our content process sandbox profile on Linux. As restrictive as possible.
#[cfg(not(target_os = "macos"))]
pub fn content_process_sandbox_profile() -> Profile {
    Profile::new(vec![
        Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
        Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path())),
    ]).expect("Failed to create sandbox profile!")
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> AudioBuffer {
        let initial_data = match initial_data {
            Some(initial_data) => {
                let mut data = vec![];
                data.extend_from_slice(initial_data);
                data
            },
            None => vec![0.; (length * number_of_channels) as usize],
        };
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            let _ = unsafe {
                Float32Array::create(
                    cx,
                    CreateWith::Slice(&initial_data.as_slice()[offset..offset + (length as usize)]),
                    array.handle_mut(),
                )
            };
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(
            global,
            number_of_channels,
            length,
            sample_rate,
            initial_data,
        );
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    // XXX TypedArrays API does not expose a way to steal the buffer's
                    //     content.
                    let data = array.to_vec();
                    let _ = JS_StealArrayBufferContents(cx, channel.handle());
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());
        // let destination = unsafe { destination.as_mut_slice() };

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe {
                array.update(&source.as_slice()[offset..offset + bytes_to_copy]);
            }
        } else {
            return Err(Error::IndexSize);
        }

        Ok(())
    }
}
<commit_msg>Do not copy initial data during AudioBuffer construction and use JS_DetachArrayBuffer<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions};
use dom::bindings::error::{Error, Fallible};
use dom::bindings::num::Finite;
use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::window::Window;
use dom_struct::dom_struct;
use js::jsapi::{DetachDataDisposition, Heap, JSContext, JSObject, JS_DetachArrayBuffer};
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{CreateWith, Float32Array};
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
use std::cmp::min;
use std::ptr::{self, NonNull};

type JSAudioChannel = Heap<*mut JSObject>;

#[dom_struct]
pub struct AudioBuffer {
    reflector_: Reflector,
    js_channels: DomRefCell<Vec<JSAudioChannel>>,
    #[ignore_malloc_size_of = "servo_media"]
    shared_channels: DomRefCell<ServoMediaAudioBuffer>,
    sample_rate: f32,
    length: u32,
    duration: f64,
    number_of_channels: u32,
}

impl AudioBuffer {
    #[allow(unrooted_must_root)]
    #[allow(unsafe_code)]
    pub fn new_inherited(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> AudioBuffer {
        let cx = global.get_cx();
        let mut js_channels: Vec<JSAudioChannel> = Vec::with_capacity(number_of_channels as usize);
        for channel in 0..number_of_channels {
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let offset = (channel * length) as usize;
            match initial_data {
                Some(data) => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&data[offset..offset + (length as usize) - 1]),
                            array.handle_mut(),
                        )
                    };
                },
                None => {
                    let _ = unsafe {
                        Float32Array::create(
                            cx,
                            CreateWith::Slice(&vec![0.; length as usize]),
                            array.handle_mut(),
                        )
                    };
                }
            }
            let js_channel = Heap::default();
            js_channel.set(array.get());
            js_channels.push(js_channel);
        }
        AudioBuffer {
            reflector_: Reflector::new(),
            js_channels: DomRefCell::new(js_channels),
            shared_channels: DomRefCell::new(ServoMediaAudioBuffer::new(
                number_of_channels as u8,
                length as usize,
            )),
            sample_rate,
            length,
            duration: length as f64 / sample_rate as f64,
            number_of_channels,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &Window,
        number_of_channels: u32,
        length: u32,
        sample_rate: f32,
        initial_data: Option<&[f32]>,
    ) -> DomRoot<AudioBuffer> {
        let buffer = AudioBuffer::new_inherited(
            global,
            number_of_channels,
            length,
            sample_rate,
            initial_data,
        );
        reflect_dom_object(Box::new(buffer), global, AudioBufferBinding::Wrap)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-audiobuffer
    pub fn Constructor(
        window: &Window,
        options: &AudioBufferOptions,
    ) -> Fallible<DomRoot<AudioBuffer>> {
        if options.numberOfChannels > MAX_CHANNEL_COUNT {
            return Err(Error::NotSupported);
        }
        Ok(AudioBuffer::new(
            window,
            options.numberOfChannels,
            options.length,
            *options.sampleRate,
            None,
        ))
    }

    #[allow(unsafe_code)]
    unsafe fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool {
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            if !channel.get().is_null() {
                // Already have data in JS array.
                continue;
            }

            // Move the channel data from shared_channels to js_channels.
            rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
            let shared_channel = (*self.shared_channels.borrow_mut()).buffers.remove(i);
            if Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
                .is_err()
            {
                return false;
            }
            channel.set(array.get());
        }

        true
    }

    // https://webaudio.github.io/web-audio-api/#acquire-the-content
    #[allow(unsafe_code)]
    pub fn acquire_contents(&self) -> Option<ServoMediaAudioBuffer> {
        let cx = self.global().get_cx();
        for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
            // Step 1.
            if channel.get().is_null() {
                return None;
            }

            // Step 2.
            let channel_data = unsafe {
                typedarray!(in(cx) let array: Float32Array = channel.get());
                if let Ok(array) = array {
                    let data = array.to_vec();
                    let _ = JS_DetachArrayBuffer(cx, channel.handle(), DetachDataDisposition::KeepData);
                    data
                } else {
                    return None;
                }
            };

            channel.set(ptr::null_mut());

            // Step 3.
            (*self.shared_channels.borrow_mut()).buffers[i] = channel_data;

            // Step 4 will complete turning shared_channels
            // data into js_channels ArrayBuffers in restore_js_channel_data.
        }

        self.js_channels.borrow_mut().clear();

        Some((*self.shared_channels.borrow()).clone())
    }
}

impl AudioBufferMethods for AudioBuffer {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate
    fn SampleRate(&self) -> Finite<f32> {
        Finite::wrap(self.sample_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length
    fn Length(&self) -> u32 {
        self.length
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration
    fn Duration(&self) -> Finite<f64> {
        Finite::wrap(self.duration)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels
    fn NumberOfChannels(&self) -> u32 {
        self.number_of_channels
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata
    #[allow(unsafe_code)]
    unsafe fn GetChannelData(
        &self,
        cx: *mut JSContext,
        channel: u32,
    ) -> Fallible<NonNull<JSObject>> {
        if channel >= self.number_of_channels {
            return Err(Error::IndexSize);
        }

        if !self.restore_js_channel_data(cx) {
            return Err(Error::JSFailed);
        }

        Ok(NonNull::new_unchecked(
            self.js_channels.borrow()[channel as usize].get(),
        ))
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copyfromchannel
    #[allow(unsafe_code)]
    fn CopyFromChannel(
        &self,
        mut destination: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > self.length {
            return Err(Error::IndexSize);
        }

        let bytes_to_copy = min(self.length - start_in_channel, destination.len() as u32) as usize;
        let cx = self.global().get_cx();
        let channel_number = channel_number as usize;
        let offset = start_in_channel as usize;
        let mut dest = Vec::with_capacity(destination.len());
        // let destination = unsafe { destination.as_mut_slice() };

        // We either copy form js_channels or shared_channels.

        let js_channel = self.js_channels.borrow()[channel_number].get();
        if !js_channel.is_null() {
            typedarray!(in(cx) let array: Float32Array = js_channel);
            if let Ok(array) = array {
                let data = unsafe { array.as_slice() };
                dest.extend_from_slice(&data[offset..offset + bytes_to_copy]);
                return Ok(());
            }
        }

        if let Some(shared_channel) = self.shared_channels.borrow().buffers.get(channel_number) {
            dest.extend_from_slice(&shared_channel.as_slice()[offset..offset + bytes_to_copy]);
        }

        unsafe {
            destination.update(&dest);
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffer-copytochannel
    #[allow(unsafe_code)]
    fn CopyToChannel(
        &self,
        source: CustomAutoRooterGuard<Float32Array>,
        channel_number: u32,
        start_in_channel: u32,
    ) -> Fallible<()> {
        if channel_number >= self.number_of_channels || start_in_channel > (source.len() as u32) {
            return Err(Error::IndexSize);
        }

        let cx = self.global().get_cx();
        if unsafe { !self.restore_js_channel_data(cx) } {
            return Err(Error::JSFailed);
        }

        let js_channel = self.js_channels.borrow()[channel_number as usize].get();
        if js_channel.is_null() {
            // The array buffer was detached.
            return Err(Error::IndexSize);
        }

        typedarray!(in(cx) let array: Float32Array = js_channel);
        if let Ok(mut array) = array {
            let bytes_to_copy = min(self.length - start_in_channel, source.len() as u32) as usize;
            let offset = start_in_channel as usize;
            unsafe {
                array.update(&source.as_slice()[offset..offset + bytes_to_copy]);
            }
        } else {
            return Err(Error::IndexSize);
        }

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


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::RootedReference;
use dom::bindings::str::DOMString;
use dom::htmlheadelement::HTMLHeadElement;
use dom::node::Node;
use servo_config::opts;
use servo_config::resource_files::resources_dir_path;
use std::borrow::ToOwned;
use std::fs::read_dir;
use std::path::PathBuf;

pub fn load_script(head: &HTMLHeadElement) {
    if let Some(ref path_str) = opts::get().userscripts {
        let node = head.upcast::<Node>();
        let first_child = node.GetFirstChild();
        let doc = node.owner_doc();

        let path = if &**path_str == "" {
            if let Ok(mut p) = resources_dir_path() {
                p.push("user-agent-js");
                p
            } else {
                return
            }
        } else {
            PathBuf::from(path_str)
        };

        let mut files = read_dir(&path).expect("Bad path passed to --userscripts")
                                       .filter_map(|e| e.ok())
                                       .map(|e| e.path()).collect::<Vec<_>>();

        files.sort();

        for file in files {
            let name = match file.into_os_string().into_string() {
                Ok(ref s) if s.ends_with(".js") => "file://".to_owned() + &s[..],
                _ => continue
            };
            let new_script = doc.CreateElement(DOMString::from("script")).unwrap();
            new_script.set_string_attribute(&local_name!("src"), DOMString::from(name));
            node.InsertBefore(new_script.upcast(), first_child.r()).unwrap();
        }
    }
}
<commit_msg>apply user scripts correctly<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::inheritance::Castable;
use dom::globalscope::GlobalScope;
use dom::htmlheadelement::HTMLHeadElement;
use dom::node::Node;
use js::jsval::UndefinedValue;
use servo_config::opts;
use servo_config::resource_files::resources_dir_path;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::PathBuf;

pub fn load_script(head: &HTMLHeadElement) {
    if let Some(ref path_str) = opts::get().userscripts {
        let node = head.upcast::<Node>();
        let doc = node.owner_doc();
        let win = doc.window();
        let cx = win.get_cx();
        rooted!(in(cx) let mut rval = UndefinedValue());

        let path = if &**path_str == "" {
            if let Ok(mut p) = resources_dir_path() {
                p.push("user-agent-js");
                p
            } else {
                return
            }
        } else {
            PathBuf::from(path_str)
        };

        let mut files = read_dir(&path).expect("Bad path passed to --userscripts")
                                       .filter_map(|e| e.ok())
                                       .map(|e| e.path()).collect::<Vec<_>>();

        files.sort();

        for file in files {
            let mut f = File::open(&file).unwrap();
            let mut contents = vec![];
            f.read_to_end(&mut contents).unwrap();
            let script_text = String::from_utf8_lossy(&contents);
            win.upcast::<GlobalScope>().evaluate_js_on_global_with_result(&script_text, rval.handle_mut());
        }
    }
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::collections::hash_map::{self, HashMap};
use std::collections::{BTreeSet, HashSet};
use std::hash::Hash;
use super::{Collection};
use super::{BaseMap, Map, MapLookup};
use super::{Entry, EntryMap, OccupiedEntry, VacantEntry};
use super::{BaseSet, Set, SetLookup};

impl<T> Collection for Vec<T> { collection_methods!{} }

impl<K, V> Collection for BTreeMap<K, V> where K: Ord { collection_methods!{} }
impl<K, V> BaseMap for BTreeMap<K, V> where K: Ord { type Key = K; type Value = V; }
impl<K, V> Map for BTreeMap<K, V> where K: Ord { map_methods!{K, V} }
impl<K, V, Q: ?Sized> MapLookup<Q> for BTreeMap<K, V>
    where K: Ord + Borrow<Q>, Q: Ord { map_lookup_methods!{Q, V} }

impl<'a, K, V: 'a> EntryMap<'a> for BTreeMap<K, V> where K: Ord {
    type Occupied = btree_map::OccupiedEntry<'a, K, V>;
    type Vacant = btree_map::VacantEntry<'a, K, V>;

    fn entry(&'a mut self, key: K) ->
        Entry<btree_map::OccupiedEntry<'a, K, V>, btree_map::VacantEntry<'a, K, V>> {

        match self.entry(key) { // FIXME: all `Entry` enums should be changed to this crate's
            btree_map::Entry::Occupied(e) => Entry::Occupied(e),
            btree_map::Entry::Vacant(e) => Entry::Vacant(e),
        }
    }
}

impl<'a, K, V: 'a> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> where K: Ord {
    type Value = V;
    occupied_entry_methods!{V}
    fn into_mut(self) -> &'a mut V { self.into_mut() }
}

impl<'a, K, V: 'a> VacantEntry<'a> for btree_map::VacantEntry<'a, K, V> where K: Ord {
    type Value = V;
    fn insert(self, value: V) -> &'a mut V { self.insert(value) }
}

impl<K, V> Collection for HashMap<K, V> where K: Eq + Hash { collection_methods!{} }
impl<K, V> BaseMap for HashMap<K, V> where K: Eq + Hash { type Key = K; type Value = V; }
impl<K, V> Map for HashMap<K, V> where K: Eq + Hash { map_methods!{K, V} }
impl<K, V, Q: ?Sized> MapLookup<Q> for HashMap<K, V>
    where K: Eq + Hash + Borrow<Q>, Q: Eq + Hash { map_lookup_methods!{Q, V} }

impl<'a, K, V: 'a> EntryMap<'a> for HashMap<K, V> where K: Eq + Hash {
    type Occupied = hash_map::OccupiedEntry<'a, K, V>;
    type Vacant = hash_map::VacantEntry<'a, K, V>;

    fn entry(&'a mut self, key: K) ->
        Entry<hash_map::OccupiedEntry<'a, K, V>, hash_map::VacantEntry<'a, K, V>> {

        match self.entry(key) { // FIXME: all `Entry` enums should be changed to this crate's
            hash_map::Entry::Occupied(e) => Entry::Occupied(e),
            hash_map::Entry::Vacant(e) => Entry::Vacant(e),
        }
    }
}

impl<'a, K, V: 'a> OccupiedEntry<'a> for hash_map::OccupiedEntry<'a, K, V> where K: Eq + Hash {
    type Value = V;
    occupied_entry_methods!{V}
    fn into_mut(self) -> &'a mut V { self.into_mut() }
}

impl<'a, K, V: 'a> VacantEntry<'a> for hash_map::VacantEntry<'a, K, V> where K: Eq + Hash {
    type Value = V;
    fn insert(self, value: V) -> &'a mut V { self.insert(value) }
}

impl<T> Collection for BTreeSet<T> where T: Ord { collection_methods!{} }
impl<T> BaseSet for BTreeSet<T> where T: Ord {type Item = T; }
impl<T> Set for BTreeSet<T> where T: Ord { set_methods!{T} }
impl<T, Q: ?Sized> SetLookup<Q> for BTreeSet<T>
    where T: Ord + Borrow<Q>, Q: Ord { set_lookup_methods!{Q} }

impl<T> Collection for HashSet<T> where T: Eq + Hash { collection_methods!{} }
impl<T> BaseSet for HashSet<T> where T: Eq + Hash { type Item = T; }
impl<T> Set for HashSet<T> where T: Eq + Hash { set_methods!{T} }
impl<T, Q: ?Sized> SetLookup<Q> for HashSet<T>
    where T: Eq + Hash + Borrow<Q>, Q: Eq + Hash { set_lookup_methods!{Q} }
<commit_msg>implement `Collection` for `{BinaryHeap, LinkedList, VecDeque}`<commit_after>use std::borrow::Borrow;
use std::collections::btree_map::{self, BTreeMap};
use std::collections::hash_map::{self, HashMap};
use std::collections::{BTreeSet, BinaryHeap, HashSet, LinkedList, VecDeque};
use std::hash::Hash;
use super::{Collection};
use super::{BaseMap, Map, MapLookup};
use super::{Entry, EntryMap, OccupiedEntry, VacantEntry};
use super::{BaseSet, Set, SetLookup};

impl<T> Collection for BinaryHeap<T> where T: Ord { collection_methods!{} }

impl<T> Collection for LinkedList<T> { collection_methods!{} }

impl<T> Collection for Vec<T> { collection_methods!{} }

impl<T> Collection for VecDeque<T> { collection_methods!{} }

impl<K, V> Collection for BTreeMap<K, V> where K: Ord { collection_methods!{} }
impl<K, V> BaseMap for BTreeMap<K, V> where K: Ord { type Key = K; type Value = V; }
impl<K, V> Map for BTreeMap<K, V> where K: Ord { map_methods!{K, V} }
impl<K, V, Q: ?Sized> MapLookup<Q> for BTreeMap<K, V>
    where K: Ord + Borrow<Q>, Q: Ord { map_lookup_methods!{Q, V} }

impl<'a, K, V: 'a> EntryMap<'a> for BTreeMap<K, V> where K: Ord {
    type Occupied = btree_map::OccupiedEntry<'a, K, V>;
    type Vacant = btree_map::VacantEntry<'a, K, V>;

    fn entry(&'a mut self, key: K) ->
        Entry<btree_map::OccupiedEntry<'a, K, V>, btree_map::VacantEntry<'a, K, V>> {

        match self.entry(key) { // FIXME: all `Entry` enums should be changed to this crate's
            btree_map::Entry::Occupied(e) => Entry::Occupied(e),
            btree_map::Entry::Vacant(e) => Entry::Vacant(e),
        }
    }
}

impl<'a, K, V: 'a> OccupiedEntry<'a> for btree_map::OccupiedEntry<'a, K, V> where K: Ord {
    type Value = V;
    occupied_entry_methods!{V}
    fn into_mut(self) -> &'a mut V { self.into_mut() }
}

impl<'a, K, V: 'a> VacantEntry<'a> for btree_map::VacantEntry<'a, K, V> where K: Ord {
    type Value = V;
    fn insert(self, value: V) -> &'a mut V { self.insert(value) }
}

impl<K, V> Collection for HashMap<K, V> where K: Eq + Hash { collection_methods!{} }
impl<K, V> BaseMap for HashMap<K, V> where K: Eq + Hash { type Key = K; type Value = V; }
impl<K, V> Map for HashMap<K, V> where K: Eq + Hash { map_methods!{K, V} }
impl<K, V, Q: ?Sized> MapLookup<Q> for HashMap<K, V>
    where K: Eq + Hash + Borrow<Q>, Q: Eq + Hash { map_lookup_methods!{Q, V} }

impl<'a, K, V: 'a> EntryMap<'a> for HashMap<K, V> where K: Eq + Hash {
    type Occupied = hash_map::OccupiedEntry<'a, K, V>;
    type Vacant = hash_map::VacantEntry<'a, K, V>;

    fn entry(&'a mut self, key: K) ->
        Entry<hash_map::OccupiedEntry<'a, K, V>, hash_map::VacantEntry<'a, K, V>> {

        match self.entry(key) { // FIXME: all `Entry` enums should be changed to this crate's
            hash_map::Entry::Occupied(e) => Entry::Occupied(e),
            hash_map::Entry::Vacant(e) => Entry::Vacant(e),
        }
    }
}

impl<'a, K, V: 'a> OccupiedEntry<'a> for hash_map::OccupiedEntry<'a, K, V> where K: Eq + Hash {
    type Value = V;
    occupied_entry_methods!{V}
    fn into_mut(self) -> &'a mut V { self.into_mut() }
}

impl<'a, K, V: 'a> VacantEntry<'a> for hash_map::VacantEntry<'a, K, V> where K: Eq + Hash {
    type Value = V;
    fn insert(self, value: V) -> &'a mut V { self.insert(value) }
}

impl<T> Collection for BTreeSet<T> where T: Ord { collection_methods!{} }
impl<T> BaseSet for BTreeSet<T> where T: Ord {type Item = T; }
impl<T> Set for BTreeSet<T> where T: Ord { set_methods!{T} }
impl<T, Q: ?Sized> SetLookup<Q> for BTreeSet<T>
    where T: Ord + Borrow<Q>, Q: Ord { set_lookup_methods!{Q} }

impl<T> Collection for HashSet<T> where T: Eq + Hash { collection_methods!{} }
impl<T> BaseSet for HashSet<T> where T: Eq + Hash { type Item = T; }
impl<T> Set for HashSet<T> where T: Eq + Hash { set_methods!{T} }
impl<T, Q: ?Sized> SetLookup<Q> for HashSet<T>
    where T: Eq + Hash + Borrow<Q>, Q: Eq + Hash { set_lookup_methods!{Q} }
<|endoftext|>


<commit_before>use super::super::{AuditLogEntryId, UserId};
use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
use std::fmt;
use std::collections::HashMap;

trait FromNum {
    fn from_num(num: i32) -> Result<Self, String> where Self: Sized;
}

/// Determines to what entity an action was used on.
#[derive(Debug)]
pub enum Target {
    Guild,
    Channel,
    User,
    Role,
    Invite,
    Webhook,
    Emoji,
}

impl FromNum for Target {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::Target::*;

        Ok(match num {
            10 => Guild,
            20 => Channel,
            30 => User,
            40 => Role,
            50 => Invite,
            60 => Webhook,
            70 => Emoji,
            _ => return Err(format!("Unexpected target number: {}", num)),
        })
    }
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
}

impl FromNum for Action {
    fn from_num(num: i32) -> Result<Self, String> {
        Ok(match num {
            1 => Action::GuildUpdate,
            num if num >= 10 && num <= 13 => Action::Channel(ActionChannel::from_num(num)?),
            num if num >= 13 && num <= 15 => {
                Action::ChannelOverwrite(ActionChannelOverwrite::from_num(num)?)
            },
            num if num >= 20 && num <= 25 => Action::Member(ActionMember::from_num(num)?),
            num if num >= 30 && num <= 32 => Action::Role(ActionRole::from_num(num)?),
            num if num >= 40 && num <= 42 => Action::Invite(ActionInvite::from_num(num)?),
            num if num >= 50 && num <= 52 => Action::Webhook(ActionWebhook::from_num(num)?),
            num if num >= 60 && num <= 62 => Action::Emoji(ActionEmoji::from_num(num)?),
            _ => return Err(format!("Unexpected action number: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionChannel {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionChannel {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionChannel::*;

        Ok(match num {
            10 => Create,
            11 => Update,
            12 => Delete,
            _ => return Err(format!("Unexpected action channel num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionChannelOverwrite {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionChannelOverwrite {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionChannelOverwrite::*;

        Ok(match num {
            13 => Create,
            14 => Update,
            15 => Delete,
            _ => return Err(format!("Unexpected action channel overwrite num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionMember {
    Kick,
    Prune,
    BanAdd,
    BanRemove,
    Update,
    RoleUpdate,
}

impl FromNum for ActionMember {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionMember::*;

        Ok(match num {
            20 => Kick,
            21 => Prune,
            22 => BanAdd,
            23 => BanRemove,
            24 => Update,
            25 => RoleUpdate,
            _ => return Err(format!("Unexpected action member num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionRole {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionRole {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionRole::*;

        Ok(match num {
            30 => Create,
            31 => Update,
            32 => Delete,
            _ => return Err(format!("Unexpected action role num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionInvite {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionInvite {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionInvite::*;

        Ok(match num {
            40 => Create,
            41 => Update,
            42 => Delete,
            _ => return Err(format!("Unexpected action invite num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionWebhook {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionWebhook {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionWebhook::*;

        Ok(match num {
            50 => Create,
            51 => Update,
            52 => Delete,
            _ => return Err(format!("Unexpected action webhook num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionEmoji {
    Create,
    Delete,
    Update,
}

impl FromNum for ActionEmoji {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionEmoji::*;

        Ok(match num {
            60 => Create,
            61 => Update,
            62 => Delete,
            _ => return Err(format!("Unexpected action emoji num: {}", num)),
        })
    }
}

#[derive(Debug, Deserialize)]
pub struct Change {
    #[serde(rename = "key")]
    pub name: String,
    #[serde(rename = "old_value")]
    pub old: String,
    #[serde(rename = "new_value")]
    pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
}

#[derive(Debug, Deserialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(deserialize_with = "deserialize_target", rename = "target_type")]
    pub target: Target,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(deserialize_with = "deserialize_action", rename = "action_type")]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Vec<Change>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
}

fn deserialize_target<'de, D: Deserializer<'de>>(de: D) -> Result<Target, D::Error> {
    struct TargetVisitor;

    impl<'de> Visitor<'de> for TargetVisitor {
        type Value = Target;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 0 to 70")
        }

        fn visit_i32<E: de::Error>(self, value: i32) -> Result<Target, E> {
            Target::from_num(value).map_err(E::custom)
        }
    }

    de.deserialize_i32(TargetVisitor)
}

fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> Result<Action, D::Error> {
    struct ActionVisitor;

    impl<'de> Visitor<'de> for ActionVisitor {
        type Value = Action;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 1 to 62")
        }

        fn visit_i32<E: de::Error>(self, value: i32) -> Result<Action, E> {
            Action::from_num(value).map_err(E::custom)
        }
    }

    de.deserialize_i32(ActionVisitor)
}

impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")]
            Entries,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<AuditLogs, V::Error> {
                let audit_log_entries = loop {
                    if let Some(Field::Entries) = map.next_key()? {
                        break map.next_value::<Vec<AuditLogEntry>>()?;
                    }
                };

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                })
            }
        }

        const FIELD: &'static [&'static str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<commit_msg>Use ranges instead of guards<commit_after>use super::super::{AuditLogEntryId, UserId};
use serde::de::{self, Deserialize, Deserializer, MapAccess, Visitor};
use std::fmt;
use std::collections::HashMap;

trait FromNum {
    fn from_num(num: i32) -> Result<Self, String> where Self: Sized;
}

/// Determines to what entity an action was used on.
#[derive(Debug)]
pub enum Target {
    Guild,
    Channel,
    User,
    Role,
    Invite,
    Webhook,
    Emoji,
}

impl FromNum for Target {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::Target::*;

        Ok(match num {
            10 => Guild,
            20 => Channel,
            30 => User,
            40 => Role,
            50 => Invite,
            60 => Webhook,
            70 => Emoji,
            _ => return Err(format!("Unexpected target number: {}", num)),
        })
    }
}

/// Determines the action that was done on a target.
#[derive(Debug)]
pub enum Action {
    GuildUpdate,
    Channel(ActionChannel),
    ChannelOverwrite(ActionChannelOverwrite),
    Member(ActionMember),
    Role(ActionRole),
    Invite(ActionInvite),
    Webhook(ActionWebhook),
    Emoji(ActionEmoji),
}

impl FromNum for Action {
    fn from_num(num: i32) -> Result<Self, String> {
        Ok(match num {
            1 => Action::GuildUpdate,
            10...13 => Action::Channel(ActionChannel::from_num(num)?),
            13...15 => Action::ChannelOverwrite(ActionChannelOverwrite::from_num(num)?),
            20...25 => Action::Member(ActionMember::from_num(num)?),
            30...32 => Action::Role(ActionRole::from_num(num)?),
            40...42 => Action::Invite(ActionInvite::from_num(num)?),
            50...52 => Action::Webhook(ActionWebhook::from_num(num)?),
            60...62 => Action::Emoji(ActionEmoji::from_num(num)?),
            _ => return Err(format!("Unexpected action number: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionChannel {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionChannel {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionChannel::*;

        Ok(match num {
            10 => Create,
            11 => Update,
            12 => Delete,
            _ => return Err(format!("Unexpected action channel num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionChannelOverwrite {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionChannelOverwrite {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionChannelOverwrite::*;

        Ok(match num {
            13 => Create,
            14 => Update,
            15 => Delete,
            _ => return Err(format!("Unexpected action channel overwrite num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionMember {
    Kick,
    Prune,
    BanAdd,
    BanRemove,
    Update,
    RoleUpdate,
}

impl FromNum for ActionMember {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionMember::*;

        Ok(match num {
            20 => Kick,
            21 => Prune,
            22 => BanAdd,
            23 => BanRemove,
            24 => Update,
            25 => RoleUpdate,
            _ => return Err(format!("Unexpected action member num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionRole {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionRole {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionRole::*;

        Ok(match num {
            30 => Create,
            31 => Update,
            32 => Delete,
            _ => return Err(format!("Unexpected action role num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionInvite {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionInvite {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionInvite::*;

        Ok(match num {
            40 => Create,
            41 => Update,
            42 => Delete,
            _ => return Err(format!("Unexpected action invite num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionWebhook {
    Create,
    Update,
    Delete,
}

impl FromNum for ActionWebhook {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionWebhook::*;

        Ok(match num {
            50 => Create,
            51 => Update,
            52 => Delete,
            _ => return Err(format!("Unexpected action webhook num: {}", num)),
        })
    }
}

#[derive(Debug)]
pub enum ActionEmoji {
    Create,
    Delete,
    Update,
}

impl FromNum for ActionEmoji {
    fn from_num(num: i32) -> Result<Self, String> {
        use self::ActionEmoji::*;

        Ok(match num {
            60 => Create,
            61 => Update,
            62 => Delete,
            _ => return Err(format!("Unexpected action emoji num: {}", num)),
        })
    }
}

#[derive(Debug, Deserialize)]
pub struct Change {
    #[serde(rename = "key")]
    pub name: String,
    #[serde(rename = "old_value")]
    pub old: String,
    #[serde(rename = "new_value")]
    pub new: String,
}

#[derive(Debug)]
pub struct AuditLogs {
    pub entries: HashMap<AuditLogEntryId, AuditLogEntry>,
}

#[derive(Debug, Deserialize)]
pub struct AuditLogEntry {
    /// Determines to what entity an [`action`] was used on.
    ///
    /// [`action`]: #structfield.action
    #[serde(deserialize_with = "deserialize_target", rename = "target_type")]
    pub target: Target,
    /// Determines what action was done on a [`target`]
    ///
    /// [`target`]: #structfield.target
    #[serde(deserialize_with = "deserialize_action", rename = "action_type")]
    pub action: Action,
    /// What was the reasoning by doing an action on a target? If there was one.
    pub reason: Option<String>,
    /// The user that did this action on a target.
    pub user_id: UserId,
    /// What changes were made.
    pub changes: Vec<Change>,
    /// The id of this entry.
    pub id: AuditLogEntryId,
}

fn deserialize_target<'de, D: Deserializer<'de>>(de: D) -> Result<Target, D::Error> {
    struct TargetVisitor;

    impl<'de> Visitor<'de> for TargetVisitor {
        type Value = Target;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 0 to 70")
        }

        fn visit_i32<E: de::Error>(self, value: i32) -> Result<Target, E> {
            Target::from_num(value).map_err(E::custom)
        }
    }

    de.deserialize_i32(TargetVisitor)
}

fn deserialize_action<'de, D: Deserializer<'de>>(de: D) -> Result<Action, D::Error> {
    struct ActionVisitor;

    impl<'de> Visitor<'de> for ActionVisitor {
        type Value = Action;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("an integer between 1 to 62")
        }

        fn visit_i32<E: de::Error>(self, value: i32) -> Result<Action, E> {
            Action::from_num(value).map_err(E::custom)
        }
    }

    de.deserialize_i32(ActionVisitor)
}

impl<'de> Deserialize<'de> for AuditLogs {
    fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier)]
        enum Field {
            #[serde(rename = "audit_log_entries")]
            Entries,
        }

        struct EntriesVisitor;

        impl<'de> Visitor<'de> for EntriesVisitor {
            type Value = AuditLogs;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("audit log entries")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<AuditLogs, V::Error> {
                let audit_log_entries = loop {
                    if let Some(Field::Entries) = map.next_key()? {
                        break map.next_value::<Vec<AuditLogEntry>>()?;
                    }
                };

                Ok(AuditLogs {
                    entries: audit_log_entries
                        .into_iter()
                        .map(|entry| (entry.id, entry))
                        .collect(),
                })
            }
        }

        const FIELD: &'static [&'static str] = &["audit_log_entries"];
        de.deserialize_struct("AuditLogs", FIELD, EntriesVisitor)
    }
}
<|endoftext|>