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

#![deny(missing_docs, missing_copy_implementations)]

//! Graphics device. Not meant for direct use.

use std::{fmt, mem, raw};
use std::hash::Hash;
use std::marker::PhantomFn;

pub use draw_state::target;
pub use draw_state::state;

pub mod attrib;
pub mod draw;
pub mod handle;
pub mod mapping;
pub mod shade;
pub mod tex;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw number of instances
pub type InstanceCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// Treat a given slice as `&[u8]` for the given function call
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
    let len = mem::size_of::<T>() * slice.len();
    let slice = raw::Slice { data: slice.as_ptr(), len: len };
    unsafe { mem::transmute(slice) }
}

/// Features that the device supports.
#[derive(Clone, Copy, Debug)]
#[allow(missing_docs)] // pretty self-explanatory fields!
pub struct Capabilities {
    pub shader_model: shade::ShaderModel,

    pub max_draw_buffers: usize,
    pub max_texture_size: usize,
    pub max_vertex_attributes: usize,

    pub array_buffer_supported: bool,
    pub fragment_output_supported: bool,
    pub immutable_storage_supported: bool,
    pub instance_base_supported: bool,
    pub instance_call_supported: bool,
    pub instance_rate_supported: bool,
    pub render_targets_supported: bool,
    pub sampler_objects_supported: bool,
    pub uniform_block_supported: bool,
    pub vertex_base_supported: bool,
}

/// Specifies the access allowed to a buffer mapping.
#[derive(Clone, Copy)]
pub enum MapAccess {
    /// Only allow reads.
    Readable,
    /// Only allow writes.
    Writable,
    /// Allow full access.
    RW
}

/// Describes what geometric primitives are created from vertex data.
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// Role of the memory buffer. GLES doesn't chaning bind points for buffers.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferRole {
    /// Generic vertex buffer
    Vertex,
    /// Index buffer
    Index,
}

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    Static,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    Dynamic,
    /// This buffer always or almost always be updated after each read.
    Stream,
}

/// An information block that is immutable and associated with each buffer
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BufferInfo {
    /// Role
    pub role: BufferRole,
    /// Usage hint
    pub usage: BufferUsage,
    /// Size in bytes
    pub size: usize,
}

/// Resources pertaining to a specific API.
#[allow(missing_docs)]
pub trait Resources: PhantomFn<Self> + Hash + fmt::Debug + Eq + PartialEq + Clone {
    type Buffer:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type ArrayBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Shader:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Program:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type FrameBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Surface:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Texture:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Sampler:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
}

#[allow(missing_docs)]
pub trait Factory<R: Resources> {
    /// Associated mapper type
    type Mapper: Clone + mapping::Raw;
    // resource creation
    fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> handle::RawBuffer<R>;
    fn create_buffer<T>(&mut self, num: usize, usage: BufferUsage) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_raw(num * mem::size_of::<T>(), usage))
    }
    fn create_buffer_static_raw(&mut self, data: &[u8], role: BufferRole) -> handle::RawBuffer<R>;
    fn create_buffer_static<T: Copy>(&mut self, data: &[T]) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), BufferRole::Vertex))
    }
    fn create_buffer_index<T: Copy>(&mut self, data: &[T]) -> handle::IndexBuffer<R, T> {
        handle::IndexBuffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), BufferRole::Index))
    }
    fn create_array_buffer(&mut self) -> Result<handle::ArrayBuffer<R>, ()>;
    fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
                     Result<handle::Shader<R>, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[handle::Shader<R>], targets: Option<&[&str]>)
                      -> Result<handle::Program<R>, ()>;
    fn create_frame_buffer(&mut self) -> handle::FrameBuffer<R>;
    fn create_surface(&mut self, tex::SurfaceInfo) -> Result<handle::Surface<R>, tex::SurfaceError>;
    fn create_texture(&mut self, tex::TextureInfo) -> Result<handle::Texture<R>, tex::TextureError>;
    fn create_sampler(&mut self, tex::SamplerInfo) -> handle::Sampler<R>;

    /// Return the framebuffer handle for the screen.
    fn get_main_frame_buffer(&self) -> handle::FrameBuffer<R>;

    /// Update the information stored in a specific buffer
    fn update_buffer_raw(&mut self, buf: &handle::RawBuffer<R>, data: &[u8], offset_bytes: usize);
    fn update_buffer<T: Copy>(&mut self, buf: &handle::Buffer<R, T>, data: &[T], offset_elements: usize) {
        self.update_buffer_raw(buf.raw(), as_byte_slice(data), mem::size_of::<T>() * offset_elements)
    }
    fn map_buffer_raw(&mut self, &handle::RawBuffer<R>, MapAccess) -> Self::Mapper;
    fn unmap_buffer_raw(&mut self, Self::Mapper);
    fn map_buffer_readable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Readable<T, R, Self>;
    fn map_buffer_writable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Writable<T, R, Self>;
    fn map_buffer_rw<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::RW<T, R, Self>;

    /// Update the information stored in a texture
    fn update_texture_raw(&mut self, tex: &handle::Texture<R>, img: &tex::ImageInfo, data: &[u8])
                          -> Result<(), tex::TextureError>;
    fn update_texture<T: Copy>(&mut self, tex: &handle::Texture<R>, img: &tex::ImageInfo, data: &[T])
                      -> Result<(), tex::TextureError> {
        self.update_texture_raw(tex, img, as_byte_slice(data))
    }
    fn generate_mipmap(&mut self, &handle::Texture<R>);

    /// Clean up all unreferenced resources
    fn cleanup(&mut self);
}

/// All the data needed simultaneously for submitting a command buffer for
/// execution on a device.
pub type SubmitInfo<'a, D: Device> = (
    &'a D::CommandBuffer,
    &'a draw::DataBuffer,
    &'a handle::Manager<D::Resources>
);

/// An interface for performing draw calls using a specific graphics API
pub trait Device {
    /// Associated resources type
    type Resources: Resources;
    /// Associated command buffer type
    type CommandBuffer: draw::CommandBuffer<Self::Resources>;

    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    /// Reset all the states to disabled/default
    fn reset_state(&mut self);

    /// Submit a command buffer for execution
    fn submit(&mut self, SubmitInfo<Self>);

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

#![deny(missing_docs, missing_copy_implementations)]

//! Graphics device. Not meant for direct use.

use std::{fmt, mem, raw};
use std::hash::Hash;
use std::marker::PhantomFn;

pub use draw_state::target;
pub use draw_state::state;

pub mod attrib;
pub mod draw;
pub mod handle;
pub mod mapping;
pub mod shade;
pub mod tex;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw number of instances
pub type InstanceCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// Treat a given slice as `&[u8]` for the given function call
pub fn as_byte_slice<T>(slice: &[T]) -> &[u8] {
    let len = mem::size_of::<T>() * slice.len();
    let slice = raw::Slice { data: slice.as_ptr(), len: len };
    unsafe { mem::transmute(slice) }
}

/// Features that the device supports.
#[derive(Copy, Clone, Debug)]
#[allow(missing_docs)] // pretty self-explanatory fields!
pub struct Capabilities {
    pub shader_model: shade::ShaderModel,

    pub max_draw_buffers: usize,
    pub max_texture_size: usize,
    pub max_vertex_attributes: usize,

    pub array_buffer_supported: bool,
    pub fragment_output_supported: bool,
    pub immutable_storage_supported: bool,
    pub instance_base_supported: bool,
    pub instance_call_supported: bool,
    pub instance_rate_supported: bool,
    pub render_targets_supported: bool,
    pub sampler_objects_supported: bool,
    pub uniform_block_supported: bool,
    pub vertex_base_supported: bool,
}

/// Specifies the access allowed to a buffer mapping.
#[derive(Copy, Clone)]
pub enum MapAccess {
    /// Only allow reads.
    Readable,
    /// Only allow writes.
    Writable,
    /// Allow full access.
    RW
}

/// Describes what geometric primitives are created from vertex data.
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// Role of the memory buffer. GLES doesn't chaning bind points for buffers.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferRole {
    /// Generic vertex buffer
    Vertex,
    /// Index buffer
    Index,
}

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    Static,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    Dynamic,
    /// This buffer always or almost always be updated after each read.
    Stream,
}

/// An information block that is immutable and associated with each buffer
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BufferInfo {
    /// Role
    pub role: BufferRole,
    /// Usage hint
    pub usage: BufferUsage,
    /// Size in bytes
    pub size: usize,
}

/// Resources pertaining to a specific API.
#[allow(missing_docs)]
pub trait Resources: PhantomFn<Self> + Hash + fmt::Debug + Eq + PartialEq + Clone {
    type Buffer:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type ArrayBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Shader:        Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Program:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type FrameBuffer:   Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Surface:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Texture:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
    type Sampler:       Copy + Clone + Hash + fmt::Debug + Eq + PartialEq + Send + Sync;
}

#[allow(missing_docs)]
pub trait Factory<R: Resources> {
    /// Associated mapper type
    type Mapper: Clone + mapping::Raw;
    // resource creation
    fn create_buffer_raw(&mut self, size: usize, usage: BufferUsage) -> handle::RawBuffer<R>;
    fn create_buffer<T>(&mut self, num: usize, usage: BufferUsage) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_raw(num * mem::size_of::<T>(), usage))
    }
    fn create_buffer_static_raw(&mut self, data: &[u8], role: BufferRole) -> handle::RawBuffer<R>;
    fn create_buffer_static<T: Copy>(&mut self, data: &[T]) -> handle::Buffer<R, T> {
        handle::Buffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), BufferRole::Vertex))
    }
    fn create_buffer_index<T: Copy>(&mut self, data: &[T]) -> handle::IndexBuffer<R, T> {
        handle::IndexBuffer::from_raw(
            self.create_buffer_static_raw(as_byte_slice(data), BufferRole::Index))
    }
    fn create_array_buffer(&mut self) -> Result<handle::ArrayBuffer<R>, ()>;
    fn create_shader(&mut self, stage: shade::Stage, code: &[u8]) ->
                     Result<handle::Shader<R>, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[handle::Shader<R>], targets: Option<&[&str]>)
                      -> Result<handle::Program<R>, ()>;
    fn create_frame_buffer(&mut self) -> handle::FrameBuffer<R>;
    fn create_surface(&mut self, tex::SurfaceInfo) -> Result<handle::Surface<R>, tex::SurfaceError>;
    fn create_texture(&mut self, tex::TextureInfo) -> Result<handle::Texture<R>, tex::TextureError>;
    fn create_sampler(&mut self, tex::SamplerInfo) -> handle::Sampler<R>;

    /// Return the framebuffer handle for the screen.
    fn get_main_frame_buffer(&self) -> handle::FrameBuffer<R>;

    /// Update the information stored in a specific buffer
    fn update_buffer_raw(&mut self, buf: &handle::RawBuffer<R>, data: &[u8], offset_bytes: usize);
    fn update_buffer<T: Copy>(&mut self, buf: &handle::Buffer<R, T>, data: &[T], offset_elements: usize) {
        self.update_buffer_raw(buf.raw(), as_byte_slice(data), mem::size_of::<T>() * offset_elements)
    }
    fn map_buffer_raw(&mut self, &handle::RawBuffer<R>, MapAccess) -> Self::Mapper;
    fn unmap_buffer_raw(&mut self, Self::Mapper);
    fn map_buffer_readable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Readable<T, R, Self>;
    fn map_buffer_writable<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::Writable<T, R, Self>;
    fn map_buffer_rw<T: Copy>(&mut self, &handle::Buffer<R, T>) -> mapping::RW<T, R, Self>;

    /// Update the information stored in a texture
    fn update_texture_raw(&mut self, tex: &handle::Texture<R>,
                          img: &tex::ImageInfo, data: &[u8],
                          kind: Option<tex::TextureKind>) -> Result<(), tex::TextureError>;

    fn update_texture<T: Copy>(&mut self, tex: &handle::Texture<R>,
                          img: &tex::ImageInfo, data: &[T],
                          kind: Option<tex::TextureKind>) -> Result<(), tex::TextureError> {
        self.update_texture_raw(tex, img, as_byte_slice(data), kind)
    }
    fn generate_mipmap(&mut self, &handle::Texture<R>);

    /// Clean up all unreferenced resources
    fn cleanup(&mut self);
}

/// All the data needed simultaneously for submitting a command buffer for
/// execution on a device.
pub type SubmitInfo<'a, D: Device> = (
    &'a D::CommandBuffer,
    &'a draw::DataBuffer,
    &'a handle::Manager<D::Resources>
);

/// An interface for performing draw calls using a specific graphics API
pub trait Device {
    /// Associated resources type
    type Resources: Resources;
    /// Associated command buffer type
    type CommandBuffer: draw::CommandBuffer<Self::Resources>;

    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;

    /// Reset all the states to disabled/default
    fn reset_state(&mut self);

    /// Submit a command buffer for execution
    fn submit(&mut self, SubmitInfo<Self>);

    /// Notify the finished frame
    fn after_frame(&mut self);
}
<|endoftext|>


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

#[macro_escape];

macro_rules! impl_dimensional(
    ($Self:ident, $T:ty, $n:expr) => (
        impl<T> Dimensional<$T,[$T,..$n]> for $Self<T> {
            #[inline]
            pub fn index<'a>(&'a self, i: uint) -> &'a $T {
                &'a self.as_slice()[i]
            }

            #[inline]
            pub fn index_mut<'a>(&'a mut self, i: uint) -> &'a mut $T {
                &'a mut self.as_mut_slice()[i]
            }

            #[inline]
            pub fn as_slice<'a>(&'a self) -> &'a [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }

            #[inline]
            pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }
        }
    )
)

macro_rules! impl_dimensional_fns(
    ($Self:ident, $T:ty, 2) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..2]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..2] {
                [f(self.index(0)),
                 f(self.index(1))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..2]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..2] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..2]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), init))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(1), &f(self.index(0), init))
            }
        }
    );
    ($Self:ident, $T:ty, 3) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..3]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..3] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..3]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..3] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..3]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), init)))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(2), &f(self.index(1), &f(self.index(0), init)))
            }
        }
    );
    ($Self:ident, $T:ty, 4) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..4]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..4] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2)),
                 f(self.index(3))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
                f(self.index_mut(3));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..4]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..4] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2)),
                 f(self.index(3), other.index(3))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..4]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
                f(self.index_mut(3), other.index(3));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), &f(self.index(3), init))))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(3), &f(self.index(2), &f(self.index(1), &f(self.index(0), init))))
            }
        }
    )
)

macro_rules! impl_swap(
    ($Self:ident) => (
        impl<T:Copy> $Self<T> {
            #[inline]
            pub fn swap(&mut self, a: uint, b: uint) {
                let tmp = copy *self.index(a);
                *self.index_mut(a) = copy *self.index(b);
                *self.index_mut(b) = tmp;
            }
        }
    )
)

macro_rules! impl_approx(
    ($Self:ident) => (
        impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for $Self<T> {
            #[inline]
            pub fn approx_epsilon() -> T {
                ApproxEq::approx_epsilon::<T,T>()
            }

            #[inline]
            pub fn approx_eq(&self, other: &$Self<T>) -> bool {
                self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
            }

            #[inline]
            pub fn approx_eq_eps(&self, other: &$Self<T>, epsilon: &T) -> bool {
                true
                //self.zip(other, |a, b| a.approx_eq_eps(b, epsilon)).all(|&x| x)
            }
        }
    )
)
<commit_msg>explicit copy<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_escape];

macro_rules! impl_dimensional(
    ($Self:ident, $T:ty, $n:expr) => (
        impl<T> Dimensional<$T,[$T,..$n]> for $Self<T> {
            #[inline]
            pub fn index<'a>(&'a self, i: uint) -> &'a $T {
                &'a self.as_slice()[i]
            }

            #[inline]
            pub fn index_mut<'a>(&'a mut self, i: uint) -> &'a mut $T {
                &'a mut self.as_mut_slice()[i]
            }

            #[inline]
            pub fn as_slice<'a>(&'a self) -> &'a [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }

            #[inline]
            pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }
        }
    )
)

macro_rules! impl_dimensional_fns(
    ($Self:ident, $T:ty, 2) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..2]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..2] {
                [f(self.index(0)),
                 f(self.index(1))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..2]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..2] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..2]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), init))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(1), &f(self.index(0), init))
            }
        }
    );
    ($Self:ident, $T:ty, 3) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..3]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..3] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..3]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..3] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..3]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), init)))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(2), &f(self.index(1), &f(self.index(0), init)))
            }
        }
    );
    ($Self:ident, $T:ty, 4) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..4]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..4] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2)),
                 f(self.index(3))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
                f(self.index_mut(3));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..4]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..4] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2)),
                 f(self.index(3), other.index(3))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..4]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
                f(self.index_mut(3), other.index(3));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), &f(self.index(3), init))))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(3), &f(self.index(2), &f(self.index(1), &f(self.index(0), init))))
            }
        }
    )
)

macro_rules! impl_swap(
    ($Self:ident) => (
        impl<T:Copy> $Self<T> {
            #[inline]
            pub fn swap(&mut self, a: uint, b: uint) {
                let tmp = copy *self.index(a);
                *self.index_mut(a) = copy *self.index(b);
                *self.index_mut(b) = tmp;
            }
        }
    )
)

macro_rules! impl_approx(
    ($Self:ident) => (
        impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for $Self<T> {
            #[inline]
            pub fn approx_epsilon() -> T {
                ApproxEq::approx_epsilon::<T,T>()
            }

            #[inline]
            pub fn approx_eq(&self, other: &$Self<T>) -> bool {
                self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
            }

            #[inline]
            pub fn approx_eq_eps(&self, other: &$Self<T>, epsilon: &T) -> bool {

                self.zip(other, |a, b| a.approx_eq_eps(b, epsilon)).all(|&x| x)
            }
        }
    )
)
<|endoftext|>


<commit_before>use std::{fs, io, mem, path};
use std::ffi::OsString;

use std::os::unix::fs::MetadataExt;

#[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
use std::io::{Read, Seek, SeekFrom, Write};

#[cfg(all(feature = "mmap", target_pointer_width = "64"))]
use memmap::MmapMut;

use CONFIG;
use util::{io_err, native, MHashMap};

const PB_LEN: usize = 256;

pub struct BufCache {
    path_a: OsString,
    path_b: OsString,
    buf: Vec<u8>,
}

/// Holds a file and mmap cache. Because 32 bit systems
/// can't mmap large files, we load them as needed.
pub struct FileCache {
    files: MHashMap<path::PathBuf, Entry>,
}

#[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
pub struct Entry {
    used: bool,
    alloc_failed: bool,
    sparse: bool,
    file: fs::File,
}

#[cfg(all(feature = "mmap", target_pointer_width = "64"))]
pub struct Entry {
    mmap: MmapMut,
    used: bool,
    alloc_failed: bool,
    sparse: bool,
}

pub struct TempPB<'a> {
    path: path::PathBuf,
    buf: &'a mut OsString,
}

pub struct TempBuf<'a> {
    buf: &'a mut Vec<u8>,
}

impl<'a> TempBuf<'a> {
    pub fn get(&mut self, len: usize) -> &mut [u8] {
        unsafe {
            self.buf.reserve(len);
            self.buf.set_len(len);
        }
        &mut self.buf[..]
    }
}

fn get_pb(buf: &mut OsString) -> TempPB {
    debug_assert!(buf.capacity() >= PB_LEN);
    let path = mem::replace(buf, OsString::with_capacity(0)).into();
    TempPB { buf, path }
}

impl<'a> TempPB<'a> {
    pub fn get<P: AsRef<path::Path>>(&mut self, base: P) -> &mut path::PathBuf {
        self.clear();
        self.path.push(base.as_ref());
        &mut self.path
    }

    fn clear(&mut self) {
        let mut s =
            mem::replace(&mut self.path, OsString::with_capacity(0).into()).into_os_string();
        s.clear();
        self.path = s.into();
    }
}

impl<'a> Drop for TempPB<'a> {
    fn drop(&mut self) {
        let mut path =
            mem::replace(&mut self.path, OsString::with_capacity(0).into()).into_os_string();
        mem::swap(self.buf, &mut path);
        self.buf.clear();
    }
}

impl BufCache {
    pub fn new() -> BufCache {
        BufCache {
            path_a: OsString::with_capacity(PB_LEN),
            path_b: OsString::with_capacity(PB_LEN),
            buf: Vec::with_capacity(1048576),
        }
    }

    pub fn data(&mut self) -> (TempBuf, TempPB, TempPB) {
        (
            TempBuf { buf: &mut self.buf },
            get_pb(&mut self.path_a),
            get_pb(&mut self.path_b),
        )
    }
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache {
            files: MHashMap::default(),
        }
    }

    pub fn read_file_range(
        &mut self,
        path: &path::Path,
        offset: u64,
        buf: &mut [u8],
    ) -> io::Result<()> {
        self.ensure_exists(path, Err(0))?;

        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            let entry = self.files.get_mut(path).unwrap();
            entry.file.seek(SeekFrom::Start(offset))?;
            entry.file.read_exact(buf)?;
            Ok(())
        }

        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            let len = buf.len();
            let entry = self.files.get_mut(path).unwrap();
            entry.used = true;
            if entry.sparse {
                let res = native::mmap_read(
                    &entry.mmap[offset as usize..offset as usize + len],
                    buf,
                    len,
                );
                if res.is_err() {
                    return io_err("Disk full!");
                }
            } else {
                buf.copy_from_slice(&entry.mmap[offset as usize..offset as usize + len]);
            };
            Ok(())
        }
    }

    pub fn write_file_range(
        &mut self,
        path: &path::Path,
        size: Result<u64, u64>,
        offset: u64,
        buf: &[u8],
    ) -> io::Result<()> {
        self.ensure_exists(path, size)?;

        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            let entry = self.files.get_mut(path).unwrap();
            entry.file.seek(SeekFrom::Start(offset))?;
            entry.file.write_all(&buf)?;
            Ok(())
        }

        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            let len = buf.len();
            let entry = self.files.get_mut(path).unwrap();
            entry.used = true;
            if entry.sparse {
                let res = native::mmap_write(
                    &mut entry.mmap[offset as usize..offset as usize + len],
                    &buf,
                    len,
                );
                if res.is_err() {
                    return io_err("Disk full!");
                }
            } else {
                (&mut entry.mmap[offset as usize..offset as usize + len]).copy_from_slice(&buf);
            };
            Ok(())
        }
    }

    pub fn remove_file(&mut self, path: &path::Path) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        self.files.remove(path);
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        self.files.remove(path).map(|f| f.mmap.flush_async().ok());
    }

    pub fn flush_file(&mut self, path: &path::Path) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            self.files.get_mut(path).map(|e| e.file.sync_all().ok());
        }
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            self.files.get_mut(path).map(|f| f.mmap.flush_async().ok());
        }
    }

    fn ensure_exists(&mut self, path: &path::Path, len: Result<u64, u64>) -> io::Result<()> {
        let len_val = if let Ok(v) = len { v } else { len.err().unwrap() };
        if !self.files.contains_key(path) {
            if self.files.len() >= CONFIG.net.max_open_files {
                let mut removal = None;
                // We rely on random iteration order to prove us something close to a "clock hand"
                // like algorithm
                for (id, entry) in &mut self.files {
                    if entry.used {
                        entry.used = false;
                    } else {
                        removal = Some(id.clone());
                    }
                }
                removal.map(|f| self.remove_file(&f));
            }

            fs::create_dir_all(path.parent().unwrap())?;
            let file = fs::OpenOptions::new()
                .write(true)
                .create(true)
                .read(true)
                .open(path)?;

            let alloc_failed = if len.is_ok() && file.metadata()?.len() != len.ok().unwrap() {
                let res = !native::fallocate(&file, len.unwrap())?;
                debug!("Attempted to fallocate {:?}: success {}!", path, !res);
                res
            } else {
                file.set_len(len_val)?;
                false
            };

            let stat = file.metadata()?;
            // Check if the file was never allocated
            if stat.size() == 0 {
                return io_err("mmap attempted on 0 sized file");
            }
            let sparse = stat.blocks() * stat.blksize() < stat.size();

            #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
            self.files.insert(
                path.to_path_buf(),
                Entry {
                    file,
                    used: true,
                    sparse,
                    alloc_failed,
                },
            );

            #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
            {
                let mmap = unsafe { MmapMut::map_mut(&file)? };
                self.files.insert(
                    path.to_path_buf(),
                    Entry {
                        mmap,
                        sparse,
                        used: true,
                        alloc_failed,
                    },
                );
            }
        } else if len.is_ok() {
            let entry = self.files.get_mut(path).unwrap();
            if entry.sparse && !entry.alloc_failed {
                debug!("Attempting delayed falloc!");
                let file = fs::OpenOptions::new().write(true).read(true).open(path)?;
                entry.alloc_failed = !native::fallocate(&file, len_val)?;
                if !entry.alloc_failed {
                    entry.sparse = false;
                }
            }
        }
        Ok(())
    }
}

impl Drop for FileCache {
    fn drop(&mut self) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            for (_, entry) in self.files.drain() {
                entry.file.sync_all().ok();
            }
        }
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            for (_, entry) in self.files.drain() {
                entry.mmap.flush().ok();
            }
        }
    }
}
<commit_msg>Make sure disk read doesnt truncate file<commit_after>use std::{fs, io, mem, path};
use std::ffi::OsString;

use std::os::unix::fs::MetadataExt;

#[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
use std::io::{Read, Seek, SeekFrom, Write};

#[cfg(all(feature = "mmap", target_pointer_width = "64"))]
use memmap::MmapMut;

use CONFIG;
use util::{io_err, native, MHashMap};

const PB_LEN: usize = 256;

pub struct BufCache {
    path_a: OsString,
    path_b: OsString,
    buf: Vec<u8>,
}

/// Holds a file and mmap cache. Because 32 bit systems
/// can't mmap large files, we load them as needed.
pub struct FileCache {
    files: MHashMap<path::PathBuf, Entry>,
}

#[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
pub struct Entry {
    used: bool,
    alloc_failed: bool,
    sparse: bool,
    file: fs::File,
}

#[cfg(all(feature = "mmap", target_pointer_width = "64"))]
pub struct Entry {
    mmap: MmapMut,
    used: bool,
    alloc_failed: bool,
    sparse: bool,
}

pub struct TempPB<'a> {
    path: path::PathBuf,
    buf: &'a mut OsString,
}

pub struct TempBuf<'a> {
    buf: &'a mut Vec<u8>,
}

impl<'a> TempBuf<'a> {
    pub fn get(&mut self, len: usize) -> &mut [u8] {
        unsafe {
            self.buf.reserve(len);
            self.buf.set_len(len);
        }
        &mut self.buf[..]
    }
}

fn get_pb(buf: &mut OsString) -> TempPB {
    debug_assert!(buf.capacity() >= PB_LEN);
    let path = mem::replace(buf, OsString::with_capacity(0)).into();
    TempPB { buf, path }
}

impl<'a> TempPB<'a> {
    pub fn get<P: AsRef<path::Path>>(&mut self, base: P) -> &mut path::PathBuf {
        self.clear();
        self.path.push(base.as_ref());
        &mut self.path
    }

    fn clear(&mut self) {
        let mut s =
            mem::replace(&mut self.path, OsString::with_capacity(0).into()).into_os_string();
        s.clear();
        self.path = s.into();
    }
}

impl<'a> Drop for TempPB<'a> {
    fn drop(&mut self) {
        let mut path =
            mem::replace(&mut self.path, OsString::with_capacity(0).into()).into_os_string();
        mem::swap(self.buf, &mut path);
        self.buf.clear();
    }
}

impl BufCache {
    pub fn new() -> BufCache {
        BufCache {
            path_a: OsString::with_capacity(PB_LEN),
            path_b: OsString::with_capacity(PB_LEN),
            buf: Vec::with_capacity(1048576),
        }
    }

    pub fn data(&mut self) -> (TempBuf, TempPB, TempPB) {
        (
            TempBuf { buf: &mut self.buf },
            get_pb(&mut self.path_a),
            get_pb(&mut self.path_b),
        )
    }
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache {
            files: MHashMap::default(),
        }
    }

    pub fn read_file_range(
        &mut self,
        path: &path::Path,
        offset: u64,
        buf: &mut [u8],
    ) -> io::Result<()> {
        self.ensure_exists(path, Err(0))?;

        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            let entry = self.files.get_mut(path).unwrap();
            entry.file.seek(SeekFrom::Start(offset))?;
            entry.file.read_exact(buf)?;
            Ok(())
        }

        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            let len = buf.len();
            let entry = self.files.get_mut(path).unwrap();
            entry.used = true;
            if entry.sparse {
                let res = native::mmap_read(
                    &entry.mmap[offset as usize..offset as usize + len],
                    buf,
                    len,
                );
                if res.is_err() {
                    return io_err("Disk full!");
                }
            } else {
                buf.copy_from_slice(&entry.mmap[offset as usize..offset as usize + len]);
            };
            Ok(())
        }
    }

    pub fn write_file_range(
        &mut self,
        path: &path::Path,
        size: Result<u64, u64>,
        offset: u64,
        buf: &[u8],
    ) -> io::Result<()> {
        self.ensure_exists(path, size)?;

        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            let entry = self.files.get_mut(path).unwrap();
            entry.file.seek(SeekFrom::Start(offset))?;
            entry.file.write_all(&buf)?;
            Ok(())
        }

        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            let len = buf.len();
            let entry = self.files.get_mut(path).unwrap();
            entry.used = true;
            if entry.sparse {
                let res = native::mmap_write(
                    &mut entry.mmap[offset as usize..offset as usize + len],
                    &buf,
                    len,
                );
                if res.is_err() {
                    return io_err("Disk full!");
                }
            } else {
                (&mut entry.mmap[offset as usize..offset as usize + len]).copy_from_slice(&buf);
            };
            Ok(())
        }
    }

    pub fn remove_file(&mut self, path: &path::Path) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        self.files.remove(path);
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        self.files.remove(path).map(|f| f.mmap.flush_async().ok());
    }

    pub fn flush_file(&mut self, path: &path::Path) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            self.files.get_mut(path).map(|e| e.file.sync_all().ok());
        }
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            self.files.get_mut(path).map(|f| f.mmap.flush_async().ok());
        }
    }

    fn ensure_exists(&mut self, path: &path::Path, len: Result<u64, u64>) -> io::Result<()> {
        let len_val = if let Ok(v) = len { v } else { len.err().unwrap() };
        if !self.files.contains_key(path) {
            if self.files.len() >= CONFIG.net.max_open_files {
                let mut removal = None;
                // We rely on random iteration order to prove us something close to a "clock hand"
                // like algorithm
                for (id, entry) in &mut self.files {
                    if entry.used {
                        entry.used = false;
                    } else {
                        removal = Some(id.clone());
                    }
                }
                removal.map(|f| self.remove_file(&f));
            }

            fs::create_dir_all(path.parent().unwrap())?;
            let file = fs::OpenOptions::new()
                .write(true)
                .create(true)
                .read(true)
                .open(path)?;

            let alloc_failed = if len.is_ok() && file.metadata()?.len() != len.ok().unwrap() {
                let res = !native::fallocate(&file, len.unwrap())?;
                debug!("Attempted to fallocate {:?}: success {}!", path, !res);
                res
            } else if len_val != 0 {
                file.set_len(len_val)?;
                false
            };

            let stat = file.metadata()?;
            let sparse = stat.blocks() * stat.blksize() < stat.size();

            #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
            self.files.insert(
                path.to_path_buf(),
                Entry {
                    file,
                    used: true,
                    sparse,
                    alloc_failed,
                },
            );

            #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
            {
                // Check if the file was never allocated
                if stat.size() == 0 {
                    return io_err("mmap attempted on 0 sized file");
                }
                let mmap = unsafe { MmapMut::map_mut(&file)? };
                self.files.insert(
                    path.to_path_buf(),
                    Entry {
                        mmap,
                        sparse,
                        used: true,
                        alloc_failed,
                    },
                );
            }
        } else if len.is_ok() {
            let entry = self.files.get_mut(path).unwrap();
            if entry.sparse && !entry.alloc_failed {
                debug!("Attempting delayed falloc!");
                let file = fs::OpenOptions::new().write(true).read(true).open(path)?;
                entry.alloc_failed = !native::fallocate(&file, len_val)?;
                if !entry.alloc_failed {
                    entry.sparse = false;
                }
            }
        }
        Ok(())
    }
}

impl Drop for FileCache {
    fn drop(&mut self) {
        #[cfg(any(target_pointer_width = "32", not(feature = "mmap")))]
        {
            for (_, entry) in self.files.drain() {
                entry.file.sync_all().ok();
            }
        }
        #[cfg(all(feature = "mmap", target_pointer_width = "64"))]
        {
            for (_, entry) in self.files.drain() {
                entry.mmap.flush().ok();
            }
        }
    }
}
<|endoftext|>


<commit_before>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file};
use std::io::{Read, Write};

fn main() {
    let path = "./tests/hello.txt";
    let bytes = b"Hello, World!\n";
    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();

    file.write(bytes).unwrap();
    // Test opening, reading and closing a file.
    let mut file = File::open(path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Removing file should succeed
    remove_file(path).unwrap();
}
<commit_msg>Add tests for non-existing files<commit_after>// ignore-windows: File handling is not implemented yet
// compile-flags: -Zmiri-disable-isolation

use std::fs::{File, remove_file};
use std::io::{Read, Write};

fn main() {
    let path = "./tests/hello.txt";
    let bytes = b"Hello, World!\n";
    // Test creating, writing and closing a file (closing is tested when `file` is dropped).
    let mut file = File::create(path).unwrap();
    // Writing 0 bytes should not change the file contents.
    file.write(&mut []).unwrap();

    file.write(bytes).unwrap();
    // Test opening, reading and closing a file.
    let mut file = File::open(path).unwrap();
    let mut contents = Vec::new();
    // Reading 0 bytes should not move the file pointer.
    file.read(&mut []).unwrap();
    // Reading until EOF should get the whole text.
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(bytes, contents.as_slice());
    // Removing file should succeed
    remove_file(path).unwrap();
    // Opening non-existing file should fail
    assert!(File::open(path).is_err());
    // Removing non-existing file should fail
    assert!(remove_file(path).is_err());
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Graph visualization traits and functions to emit dot code.

use std::collections::HashMap;
use std::hash::Hash;
use std::cmp::Eq;
use std::fmt::Debug;

use petgraph::graph::NodeIndex;

#[allow(unused_macros)]
macro_rules! add_strings {
    ( $( $x: expr ),* ) => {
        {
            let mut s = String::new();
            $(
                s.push_str(&format!("{}", $x));
             )*
                s
        }
    };
}

/// Represents the contents of a `GraphViz` attribute block
pub enum DotAttrBlock {
    /// The attribute block as string including the surrounding square brackets.
    /// Values have to be escaped manually.
    Raw(String),
    /// List of key-value pairs.
    /// Values will be escaped for you.
    Attributes(Vec<(String, String)>),
    /// Represents one line in a dot file
    Hybrid(String, Vec<(String, String)>),
}

impl DotAttrBlock {
    fn bake(&mut self) -> &String {
        let mut r = String::new();
        let attr = if let DotAttrBlock::Hybrid(ref s, ref attr) = *self {
            r.push_str(s);
            attr.clone()
        } else {
            Vec::new()
        };

        if !attr.is_empty() {
            *self = DotAttrBlock::Attributes(attr);
        }

        let s: String = match *self {
            DotAttrBlock::Raw(ref l) => return l,
            DotAttrBlock::Attributes(ref attrs) => {
                if attrs.is_empty() {
                    "".to_owned()
                } else {
                    let mut t = " [".to_string();
                    for &(ref k, ref v) in attrs {
                        t.push_str(&*format!(" {}={}", k, v));
                    }
                    t.push_str(" ]");
                    t
                }
            }
            _ => unreachable!(),
        };

        r.push_str(&s);
        r.push_str(";\n");
        *self = DotAttrBlock::Raw(r);
        if let DotAttrBlock::Raw(ref r) = *self {
            return r;
        }
        unreachable!();
    }
}

pub trait Index {
    fn to_index(&self) -> usize;
}

impl Index for NodeIndex {
    fn to_index(&self) -> usize {
        self.index()
    }
}

/// This trait enables graphs to be generated from implementors.
pub trait GraphDot {
    type NodeIndex: Hash + Clone + Eq + Index + Debug;
    type EdgeIndex: Hash + Clone + Eq;

    fn node_index_new(usize) -> Self::NodeIndex;
    fn edge_index_new(usize) -> Self::EdgeIndex;

    fn configure(&self) -> String;
    fn node_count(&self) -> usize;
    fn edge_count(&self) -> usize;
    fn nodes(&self) -> Vec<Self::NodeIndex>;
    fn edges(&self) -> Vec<Self::EdgeIndex>;
    // fn get_node(&self, n: usize) -> Option<&Self::NodeType>;

    /// Nodes with the same node_cluster return value will be put in the same
    /// graphviz-cluster.
    fn node_cluster(&self, _: &Self::NodeIndex) -> Option<usize> {
        Some(0)
    }

    fn node_skip(&self, &Self::NodeIndex) -> bool {
        false
    }
    fn node_attrs(&self, &Self::NodeIndex) -> DotAttrBlock;

    fn edge_skip(&self, &Self::EdgeIndex) -> bool {
        false
    }
    fn edge_attrs(&self, &Self::EdgeIndex) -> DotAttrBlock;

    fn edge_source(&self, &Self::EdgeIndex) -> Self::NodeIndex;
    fn edge_target(&self, &Self::EdgeIndex) -> Self::NodeIndex;
}

pub fn emit_dot<T: GraphDot>(g: &T) -> String {
    let mut result = String::new();
    result.push_str(&*g.configure());

    // Node configurations
    {
        let nodes = g.nodes();
        let mut clustermap = HashMap::<T::NodeIndex, Vec<T::NodeIndex>>::new();

        for i in &nodes {
            let block = g.node_cluster(i);
            clustermap.entry(T::node_index_new(block.unwrap()))
                      .or_insert_with(Vec::new)
                      .push(i.clone());
        }

        for (k, v) in &clustermap {
            result.push_str(&*format!("subgraph cluster_{} {{\n", k.to_index()));
            result.push_str("style=filled;\n");
            result.push_str("fillcolor=gray;\n");
            result.push_str("rankdir=TB;\n");
            for node in v.iter() {
                result.push_str(&*g.node_attrs(node).bake());
            }
            result.push_str("}\n");
        }
    }

    // Connect nodes by edges.
    for edge_i in g.edges() {
        if g.edge_skip(&edge_i) {
            continue;
        }
        result.push_str(g.edge_attrs(&edge_i).bake());
    }

    result.push_str("\n}\n");
    result
}
<commit_msg>never panic middle/dot.rs<commit_after>// Copyright (c) 2015, The Radare Project. All rights reserved.
// See the COPYING file at the top-level directory of this distribution.
// Licensed under the BSD 3-Clause License:
// <http://opensource.org/licenses/BSD-3-Clause>
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Graph visualization traits and functions to emit dot code.

use std::collections::HashMap;
use std::hash::Hash;
use std::cmp::Eq;
use std::fmt::Debug;

use petgraph::graph::NodeIndex;

#[allow(unused_macros)]
macro_rules! add_strings {
    ( $( $x: expr ),* ) => {
        {
            let mut s = String::new();
            $(
                s.push_str(&format!("{}", $x));
             )*
                s
        }
    };
}

/// Represents the contents of a `GraphViz` attribute block
pub enum DotAttrBlock {
    /// The attribute block as string including the surrounding square brackets.
    /// Values have to be escaped manually.
    Raw(String),
    /// List of key-value pairs.
    /// Values will be escaped for you.
    Attributes(Vec<(String, String)>),
    /// Represents one line in a dot file
    Hybrid(String, Vec<(String, String)>),
}

impl DotAttrBlock {
    fn bake(&mut self) -> &String {
        let mut r = String::new();
        let attr = if let DotAttrBlock::Hybrid(ref s, ref attr) = *self {
            r.push_str(s);
            attr.clone()
        } else {
            Vec::new()
        };

        if !attr.is_empty() {
            *self = DotAttrBlock::Attributes(attr);
        }

        let s: String = match *self {
            DotAttrBlock::Raw(ref l) => return l,
            DotAttrBlock::Attributes(ref attrs) => {
                if attrs.is_empty() {
                    "".to_owned()
                } else {
                    let mut t = " [".to_string();
                    for &(ref k, ref v) in attrs {
                        t.push_str(&*format!(" {}={}", k, v));
                    }
                    t.push_str(" ]");
                    t
                }
            }
            _ => unreachable!(),
        };

        r.push_str(&s);
        r.push_str(";\n");
        *self = DotAttrBlock::Raw(r);
        if let DotAttrBlock::Raw(ref r) = *self {
            return r;
        }
        unreachable!();
    }
}

pub trait Index {
    fn to_index(&self) -> usize;
}

impl Index for NodeIndex {
    fn to_index(&self) -> usize {
        self.index()
    }
}

/// This trait enables graphs to be generated from implementors.
pub trait GraphDot {
    type NodeIndex: Hash + Clone + Eq + Index + Debug;
    type EdgeIndex: Hash + Clone + Eq;

    fn node_index_new(usize) -> Self::NodeIndex;
    fn edge_index_new(usize) -> Self::EdgeIndex;

    fn configure(&self) -> String;
    fn node_count(&self) -> usize;
    fn edge_count(&self) -> usize;
    fn nodes(&self) -> Vec<Self::NodeIndex>;
    fn edges(&self) -> Vec<Self::EdgeIndex>;
    // fn get_node(&self, n: usize) -> Option<&Self::NodeType>;

    /// Nodes with the same node_cluster return value will be put in the same
    /// graphviz-cluster.
    fn node_cluster(&self, _: &Self::NodeIndex) -> Option<usize> {
        Some(0)
    }

    fn node_skip(&self, &Self::NodeIndex) -> bool {
        false
    }
    fn node_attrs(&self, &Self::NodeIndex) -> DotAttrBlock;

    fn edge_skip(&self, &Self::EdgeIndex) -> bool {
        false
    }
    fn edge_attrs(&self, &Self::EdgeIndex) -> DotAttrBlock;

    fn edge_source(&self, &Self::EdgeIndex) -> Self::NodeIndex;
    fn edge_target(&self, &Self::EdgeIndex) -> Self::NodeIndex;
}

pub fn emit_dot<T: GraphDot>(g: &T) -> String {
    let mut result = String::new();
    result.push_str(&*g.configure());

    // Node configurations
    {
        let nodes = g.nodes();
        let mut clustermap = HashMap::<T::NodeIndex, Vec<T::NodeIndex>>::new();

        for i in &nodes {
            let block = g.node_cluster(i).unwrap_or_else(|| {
                radeco_err!("Block not found");
                0
            });
            clustermap.entry(T::node_index_new(block))
                      .or_insert_with(Vec::new)
                      .push(i.clone());
        }

        for (k, v) in &clustermap {
            result.push_str(&*format!("subgraph cluster_{} {{\n", k.to_index()));
            result.push_str("style=filled;\n");
            result.push_str("fillcolor=gray;\n");
            result.push_str("rankdir=TB;\n");
            for node in v.iter() {
                result.push_str(&*g.node_attrs(node).bake());
            }
            result.push_str("}\n");
        }
    }

    // Connect nodes by edges.
    for edge_i in g.edges() {
        if g.edge_skip(&edge_i) {
            continue;
        }
        result.push_str(g.edge_attrs(&edge_i).bake());
    }

    result.push_str("\n}\n");
    result
}
<|endoftext|>


<commit_before>use std::fs;
use std::env;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::assert_that;

fn setup() {
}

test!(plugin_to_the_max {
    if !::is_nightly() { return }

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#)
        .file("src/foo_lib.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#);
    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc_plugin;
            extern crate baz;

            use rustc_plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#);
    let baz = project("baz")
        .file("Cargo.toml", r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#)
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }");
    bar.build();
    baz.build();

    assert_that(foo.cargo_process("build"),
                execs().with_status(0));
    assert_that(foo.cargo("doc"),
                execs().with_status(0));
});

test!(plugin_with_dynamic_native_dependency {
    if !::is_nightly() { return }

    let build = project("builder")
        .file("Cargo.toml", r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#)
        .file("src/lib.rs", r#"
            #[no_mangle]
            pub extern fn foo() {}
        "#);
    assert_that(build.cargo_process("build"),
                execs().with_status(0));
    let src = build.root().join("target/debug");
    let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
        let lib = lib.file_name().unwrap().to_str().unwrap();
        lib.starts_with(env::consts::DLL_PREFIX) &&
            lib.ends_with(env::consts::DLL_SUFFIX)
    }).unwrap();
    let libname = lib.file_name().unwrap().to_str().unwrap();
    let libname = &libname[env::consts::DLL_PREFIX.len()..
                           libname.len() - env::consts::DLL_SUFFIX.len()];

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/build.rs", r#"
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let src = PathBuf::from(env::var("SRC").unwrap());
                println!("cargo:rustc-flags=-L {}", src.parent().unwrap()
                                                       .display());
            }
        "#)
        .file("bar/src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]
            extern crate rustc_plugin;

            use rustc_plugin::Registry;

            #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
            #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
            extern { fn foo(); }

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {
                unsafe { foo() }
            }
        "#);

    assert_that(foo.cargo_process("build").env("SRC", &lib).arg("-v"),
                execs().with_status(0));
});

test!(plugin_integration {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#)
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "");

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

test!(doctest_a_plugin {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#)
        .file("src/lib.rs", r#"
            #[macro_use]
            extern crate bar;
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/src/lib.rs", r#"
            pub fn bar() {}
        "#);

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

// See #1515
test!(native_plugin_dependency_with_custom_ar_linker {
    let target = ::rustc_host();

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo"
            plugin = true
        "#)
        .file("src/lib.rs", "");

    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"

            [dependencies.foo]
            path = "../foo"
        "#)
        .file("src/lib", "")
        .file(".cargo/config", &format!(r#"
            [target.{}]
            ar = "nonexistent-ar"
            linker = "nonexistent-linker"
        "#, target));

    foo.build();
    assert_that(bar.cargo_process("build").arg("--verbose"),
                execs().with_stdout(&format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
", compiling = COMPILING, running = RUNNING, url = bar.url())))
});
<commit_msg>Auto merge of #2333 - matklad:remove-unused-var, r=alexcrichton<commit_after>use std::fs;
use std::env;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::assert_that;

fn setup() {
}

test!(plugin_to_the_max {
    if !::is_nightly() { return }

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#)
        .file("src/foo_lib.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#);
    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#)
        .file("src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc_plugin;
            extern crate baz;

            use rustc_plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#);
    let baz = project("baz")
        .file("Cargo.toml", r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#)
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }");
    bar.build();
    baz.build();

    assert_that(foo.cargo_process("build"),
                execs().with_status(0));
    assert_that(foo.cargo("doc"),
                execs().with_status(0));
});

test!(plugin_with_dynamic_native_dependency {
    if !::is_nightly() { return }

    let build = project("builder")
        .file("Cargo.toml", r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#)
        .file("src/lib.rs", r#"
            #[no_mangle]
            pub extern fn foo() {}
        "#);
    assert_that(build.cargo_process("build"),
                execs().with_status(0));
    let src = build.root().join("target/debug");
    let lib = fs::read_dir(&src).unwrap().map(|s| s.unwrap().path()).find(|lib| {
        let lib = lib.file_name().unwrap().to_str().unwrap();
        lib.starts_with(env::consts::DLL_PREFIX) &&
            lib.ends_with(env::consts::DLL_SUFFIX)
    }).unwrap();

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/build.rs", r#"
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let src = PathBuf::from(env::var("SRC").unwrap());
                println!("cargo:rustc-flags=-L {}", src.parent().unwrap()
                                                       .display());
            }
        "#)
        .file("bar/src/lib.rs", r#"
            #![feature(plugin_registrar, rustc_private)]
            extern crate rustc_plugin;

            use rustc_plugin::Registry;

            #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
            #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
            extern { fn foo(); }

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {
                unsafe { foo() }
            }
        "#);

    assert_that(foo.cargo_process("build").env("SRC", &lib).arg("-v"),
                execs().with_status(0));
});

test!(plugin_integration {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#)
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "");

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

test!(doctest_a_plugin {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#)
        .file("src/lib.rs", r#"
            #[macro_use]
            extern crate bar;
        "#)
        .file("bar/Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#)
        .file("bar/src/lib.rs", r#"
            pub fn bar() {}
        "#);

    assert_that(p.cargo_process("test").arg("-v"),
                execs().with_status(0));
});

// See #1515
test!(native_plugin_dependency_with_custom_ar_linker {
    let target = ::rustc_host();

    let foo = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo"
            plugin = true
        "#)
        .file("src/lib.rs", "");

    let bar = project("bar")
        .file("Cargo.toml", r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"

            [dependencies.foo]
            path = "../foo"
        "#)
        .file("src/lib", "")
        .file(".cargo/config", &format!(r#"
            [target.{}]
            ar = "nonexistent-ar"
            linker = "nonexistent-linker"
        "#, target));

    foo.build();
    assert_that(bar.cargo_process("build").arg("--verbose"),
                execs().with_stdout(&format!("\
{compiling} foo v0.0.1 ({url})
{running} `rustc [..] -C ar=nonexistent-ar -C linker=nonexistent-linker [..]`
", compiling = COMPILING, running = RUNNING, url = bar.url())))
});
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::io::{File};
use std::os;

use iron::prelude::*;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Phantom;
use plugin::Plugin as PluginFor;
use iron::status;
use iron::headers;

use glob::glob;

use handlebars::Handlebars;
use serialize::json::{ToJson, Json};

pub struct HandlebarsEngine {
    registry: Handlebars
}

#[derive(Clone)]
pub struct Template {
    name: String,
    value: Json
}

impl Template {
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: name.to_string(),
            value: value.to_json()
        }
    }
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    fn eval(resp: &mut Response, _: Phantom<HandlebarsEngine>) -> Option<Template> {
        resp.extensions.get::<HandlebarsEngine>().cloned()
    }
}

impl HandlebarsEngine {
    pub fn new(prefix: &str, suffix: &str) -> HandlebarsEngine {
        let mut r = Handlebars::new();

        let prefix_path = Path::new(prefix);
        let abs_prefix_path = os::make_absolute(&prefix_path).unwrap();
        let prefix_path_str = abs_prefix_path.as_str().unwrap();

        let mut pattern = String::new();
        pattern.push_str(prefix_path_str);
        pattern.push_str("/**/*");
        pattern.push_str(suffix);

        for path in glob(pattern.as_slice()) {
            let disp = path.as_str().unwrap();
            let t = r.register_template_string(
                disp.slice(prefix_path_str.len()+1, disp.len()-suffix.len()),
                File::open(&path).ok()
                    .expect(format!("Failed to open file {}", disp).as_slice())
                    .read_to_string().unwrap());

            if t.is_err() {
                panic!("Failed to create template.");
            }
        }

        HandlebarsEngine {
            registry: r
        }
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, resp: &mut Response) -> IronResult<()> {
        // internally we still extensions.get to avoid clone
        let page = match resp.extensions.get::<HandlebarsEngine>() {
            Some(h) => {
                let name = &h.name;
                let value = &h.value;
                let page = self.registry.render(name.as_slice(), value).unwrap();
                Some(page)
            },
            None => {
                None
            }
        };

        if page.is_some() {
            resp.headers.set(headers::ContentType(FromStr::from_str("text/html;charset=utf-8").unwrap()));
            resp.set_mut(page.unwrap());
        }

        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serialize::json::ToJson;
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_string(), "Handlebars on Iron".to_json());

        Ok(resp.set(Template::new("index", data)))
    }

    #[test]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Some(h) => {
                assert_eq!(h.name, "index".to_string());
                assert_eq!(h.value.as_object().unwrap()
                           .get(&"title".to_string()).unwrap()
                           .as_string().unwrap(),
                           "Handlebars on Iron");
            },
            None => panic!("template expected")
        }
    }
}
<commit_msg>(fix) fixed unused warning<commit_after>use std::str::FromStr;
use std::io::{File};
use std::os;

use iron::prelude::*;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Phantom;
use plugin::Plugin as PluginFor;
use iron::headers;

use glob::glob;

use handlebars::Handlebars;
use serialize::json::{ToJson, Json};

pub struct HandlebarsEngine {
    registry: Handlebars
}

#[derive(Clone)]
pub struct Template {
    name: String,
    value: Json
}

impl Template {
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: name.to_string(),
            value: value.to_json()
        }
    }
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    fn eval(resp: &mut Response, _: Phantom<HandlebarsEngine>) -> Option<Template> {
        resp.extensions.get::<HandlebarsEngine>().cloned()
    }
}

impl HandlebarsEngine {
    pub fn new(prefix: &str, suffix: &str) -> HandlebarsEngine {
        let mut r = Handlebars::new();

        let prefix_path = Path::new(prefix);
        let abs_prefix_path = os::make_absolute(&prefix_path).unwrap();
        let prefix_path_str = abs_prefix_path.as_str().unwrap();

        let mut pattern = String::new();
        pattern.push_str(prefix_path_str);
        pattern.push_str("/**/*");
        pattern.push_str(suffix);

        for path in glob(pattern.as_slice()) {
            let disp = path.as_str().unwrap();
            let t = r.register_template_string(
                disp.slice(prefix_path_str.len()+1, disp.len()-suffix.len()),
                File::open(&path).ok()
                    .expect(format!("Failed to open file {}", disp).as_slice())
                    .read_to_string().unwrap());

            if t.is_err() {
                panic!("Failed to create template.");
            }
        }

        HandlebarsEngine {
            registry: r
        }
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, resp: &mut Response) -> IronResult<()> {
        // internally we still extensions.get to avoid clone
        let page = match resp.extensions.get::<HandlebarsEngine>() {
            Some(h) => {
                let name = &h.name;
                let value = &h.value;
                let page = self.registry.render(name.as_slice(), value).unwrap();
                Some(page)
            },
            None => {
                None
            }
        };

        if page.is_some() {
            resp.headers.set(headers::ContentType(FromStr::from_str("text/html;charset=utf-8").unwrap()));
            resp.set_mut(page.unwrap());
        }

        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serialize::json::ToJson;
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_string(), "Handlebars on Iron".to_json());

        Ok(resp.set(Template::new("index", data)))
    }

    #[test]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Some(h) => {
                assert_eq!(h.name, "index".to_string());
                assert_eq!(h.value.as_object().unwrap()
                           .get(&"title".to_string()).unwrap()
                           .as_string().unwrap(),
                           "Handlebars on Iron");
            },
            None => panic!("template expected")
        }
    }
}
<|endoftext|>