<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::borrow::Cow;
use std::marker::PhantomData;
use std::mem;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use std::ffi::CStr;
use std::vec::IntoIter as VecIntoIter;

use format::Format;
use pipeline::input_assembly::PrimitiveTopology;

use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Contains SPIR-V code with one or more entry points.
///
/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
/// each shader.
pub struct ShaderModule {
    device: Arc<Device>,
    module: vk::ShaderModule,
}

impl ShaderModule {
    /// Builds a new shader module from SPIR-V.
    ///
    /// # Safety
    ///
    /// - The SPIR-V code is not validated.
    /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
    ///   this function either.
    ///
    pub unsafe fn new(device: &Arc<Device>, spirv: &[u8])
                      -> Result<Arc<ShaderModule>, OomError>
    {
        let vk = device.pointers();

        assert!((spirv.len() % 4) == 0);

        let module = {
            let infos = vk::ShaderModuleCreateInfo {
                sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                codeSize: spirv.len(),
                pCode: spirv.as_ptr() as *const _,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateShaderModule(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ShaderModule {
            device: device.clone(),
            module: module,
        }))
    }

    pub unsafe fn vertex_shader_entry_point<'a, S, V, L>(&'a self, name: &'a CStr, layout: L,
                                                         vertex_input: V)
                                                         -> VertexShaderEntryPoint<'a, S, V, L>
    {
        VertexShaderEntryPoint {
            module: self,
            name: name,
            vertex_input: vertex_input,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_control_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                              -> TessControlShaderEntryPoint<'a, S, I, O, L>
    {
        TessControlShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_evaluation_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                                     -> TessEvaluationShaderEntryPoint<'a, S, I, O, L>
    {
        TessEvaluationShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn geometry_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, primitives: GeometryShaderExecutionMode, layout: L)
                                                              -> GeometryShaderEntryPoint<'a, S, I, O, L>
    {
        GeometryShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            primitives: primitives,
            marker: PhantomData,
        }
    }

    /// Gets access to an entry point contained in this module.
    ///
    /// This is purely a *logical* operation. It returns a struct that *represents* the entry
    /// point but doesn't actually do anything.
    ///
    /// # Safety
    ///
    /// - The user must check that the entry point exists in the module, as this is not checked
    ///   by Vulkan.
    /// - Calling this function also determines the template parameters associated to the
    ///   `EntryPoint` struct. Therefore care must be taken that the values there are correct.
    ///
    pub unsafe fn fragment_shader_entry_point<'a, S, F, L>(&'a self, name: &'a CStr, layout: L)
                                                           -> FragmentShaderEntryPoint<'a, S, F, L>
    {
        FragmentShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
                                                       -> ComputeShaderEntryPoint<'a, S, L>
    {
        ComputeShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }
}

unsafe impl VulkanObject for ShaderModule {
    type Object = vk::ShaderModule;

    #[inline]
    fn internal_object(&self) -> vk::ShaderModule {
        self.module
    }
}

impl Drop for ShaderModule {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyShaderModule(self.device.internal_object(), self.module, ptr::null());
        }
    }
}

pub struct VertexShaderEntryPoint<'a, S, V, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    vertex_input: V,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, V, L> VertexShaderEntryPoint<'a, S, V, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }

    #[inline]
    pub fn input_definition(&self) -> &V {
        &self.vertex_input
    }
}

pub struct TessControlShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessControlShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct GeometryShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    primitives: GeometryShaderExecutionMode,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> GeometryShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    /// Returns the kind of primitives expected by the geometry shader.
    #[inline]
    pub fn primitives(&self) -> GeometryShaderExecutionMode {
        self.primitives
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

/// Declares which type of primitives are expected by the geometry shader.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum GeometryShaderExecutionMode {
    Points,
    Lines,
    LinesWithAdjacency,
    Triangles,
    TrianglesWithAdjacency,
}

impl GeometryShaderExecutionMode {
    /// Returns true if the given primitive topology can be used with this execution mode.
    #[inline]
    pub fn matches(&self, input: PrimitiveTopology) -> bool {
        match (*self, input) {
            (GeometryShaderExecutionMode::Points, PrimitiveTopology::PointList) => true,
            (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineList) => true,
            (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineStrip) => true,
            (GeometryShaderExecutionMode::LinesWithAdjacency,
             PrimitiveTopology::LineListWithAdjacency) => true,
            (GeometryShaderExecutionMode::LinesWithAdjacency,
             PrimitiveTopology::LineStripWithAdjacency) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleList) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleStrip) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleFan) => true,
            (GeometryShaderExecutionMode::TrianglesWithAdjacency,
             PrimitiveTopology::TriangleListWithAdjancecy) => true,
            (GeometryShaderExecutionMode::TrianglesWithAdjacency,
             PrimitiveTopology::TriangleStripWithAdjacency) => true,
            _ => false,
        }
    }
}

pub struct FragmentShaderEntryPoint<'a, S, F, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, F)>,
}

impl<'a, S, F, L> FragmentShaderEntryPoint<'a, S, F, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct ComputeShaderEntryPoint<'a, S, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, L> ComputeShaderEntryPoint<'a, S, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

/// Structs that contain the definition of an interface between two shader stages, or between
/// the outside and a shader stage.
///
/// # Safety
///
/// - Must only provide one entry per location.
/// - The format must not be larger than 128 bits.
///
pub unsafe trait ShaderInterfaceDef {
    /// Iterator returned by `elements`.
    type Iter: ExactSizeIterator<Item = ShaderInterfaceDefEntry>;

    /// Iterates over the elements of the interface.
    fn elements(&self) -> Self::Iter;
}

// FIXME: temporary ; remove as it is unsafe
unsafe impl ShaderInterfaceDef for Vec<ShaderInterfaceDefEntry> {
    type Iter = VecIntoIter<ShaderInterfaceDefEntry>;

    #[inline]
    fn elements(&self) -> Self::Iter {
        self.clone().into_iter()
    }
}

/// Entry of a shader interface definition.
#[derive(Debug, Clone)]
pub struct ShaderInterfaceDefEntry {
    /// Range of locations covered by the element.
    pub location: Range<u32>,
    /// Format of a each location of the element.
    pub format: Format,
    /// Name of the element, or `None` if the name is unknown.
    pub name: Option<Cow<'static, str>>,
}

/// Extension trait for `ShaderInterfaceDef` that specifies that the interface is potentially
/// compatible with another one.
pub unsafe trait ShaderInterfaceDefMatch<I>: ShaderInterfaceDef where I: ShaderInterfaceDef {
    /// Returns true if the two definitions match.
    // TODO: return a descriptive error instead
    fn matches(&self, other: &I) -> bool;
}

// TODO: turn this into a default impl that can be specialized
unsafe impl<T, I> ShaderInterfaceDefMatch<I> for T
    where T: ShaderInterfaceDef, I: ShaderInterfaceDef
{
    fn matches(&self, other: &I) -> bool {
        if self.elements().len() != other.elements().len() {
            return false;
        }

        for a in self.elements() {
            for loc in a.location.clone() {
                let b = match other.elements().find(|e| loc >= e.location.start && loc < e.location.end) {
                    None => return false,
                    Some(b) => b,
                };

                if a.format != b.format {
                    return false;
                }

                // TODO: enforce this?
                /*match (a.name, b.name) {
                    (Some(ref an), Some(ref bn)) => if an != bn { return false },
                    _ => ()
                };*/
            }
        }

        true
    }
}

/// Trait to describe structs that contain specialization data for shaders.
///
/// It is implemented on `()` for shaders that don't have any specialization constant.
pub unsafe trait SpecializationConstants {
    /// Returns descriptors of the struct's layout.
    fn descriptors() -> &'static [SpecializationMapEntry];
}

unsafe impl SpecializationConstants for () {
    #[inline]
    fn descriptors() -> &'static [SpecializationMapEntry] {
        &[]
    }
}

/// Describes an indiviual constant to set in the shader. Also a field in the struct.
// Has the same memory representation as a `VkSpecializationMapEntry`.
#[repr(C)]
pub struct SpecializationMapEntry {
    /// Identifier of the constant in the shader that corresponds to this field.
    pub constant_id: u32,
    /// Offset within this struct for the data.
    pub offset: u32,
    /// Size of the data in bytes.
    pub size: usize,
}

/// Trait to describe structs that contain push constants for shaders.
///
/// It is implemented on `()` for shaders that don't have any push constant.
pub unsafe trait PushConstants {
    // TODO:
}

unsafe impl PushConstants for () {
}
<commit_msg>Remove old useless trait<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::borrow::Cow;
use std::marker::PhantomData;
use std::mem;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use std::ffi::CStr;
use std::vec::IntoIter as VecIntoIter;

use format::Format;
use pipeline::input_assembly::PrimitiveTopology;

use device::Device;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Contains SPIR-V code with one or more entry points.
///
/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
/// each shader.
pub struct ShaderModule {
    device: Arc<Device>,
    module: vk::ShaderModule,
}

impl ShaderModule {
    /// Builds a new shader module from SPIR-V.
    ///
    /// # Safety
    ///
    /// - The SPIR-V code is not validated.
    /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
    ///   this function either.
    ///
    pub unsafe fn new(device: &Arc<Device>, spirv: &[u8])
                      -> Result<Arc<ShaderModule>, OomError>
    {
        let vk = device.pointers();

        assert!((spirv.len() % 4) == 0);

        let module = {
            let infos = vk::ShaderModuleCreateInfo {
                sType: vk::STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                codeSize: spirv.len(),
                pCode: spirv.as_ptr() as *const _,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateShaderModule(device.internal_object(), &infos,
                                                    ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(ShaderModule {
            device: device.clone(),
            module: module,
        }))
    }

    pub unsafe fn vertex_shader_entry_point<'a, S, V, L>(&'a self, name: &'a CStr, layout: L,
                                                         vertex_input: V)
                                                         -> VertexShaderEntryPoint<'a, S, V, L>
    {
        VertexShaderEntryPoint {
            module: self,
            name: name,
            vertex_input: vertex_input,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_control_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                              -> TessControlShaderEntryPoint<'a, S, I, O, L>
    {
        TessControlShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn tess_evaluation_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, layout: L)
                                                                     -> TessEvaluationShaderEntryPoint<'a, S, I, O, L>
    {
        TessEvaluationShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    pub unsafe fn geometry_shader_entry_point<'a, S, I, O, L>(&'a self, name: &'a CStr, primitives: GeometryShaderExecutionMode, layout: L)
                                                              -> GeometryShaderEntryPoint<'a, S, I, O, L>
    {
        GeometryShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            primitives: primitives,
            marker: PhantomData,
        }
    }

    /// Gets access to an entry point contained in this module.
    ///
    /// This is purely a *logical* operation. It returns a struct that *represents* the entry
    /// point but doesn't actually do anything.
    ///
    /// # Safety
    ///
    /// - The user must check that the entry point exists in the module, as this is not checked
    ///   by Vulkan.
    /// - Calling this function also determines the template parameters associated to the
    ///   `EntryPoint` struct. Therefore care must be taken that the values there are correct.
    ///
    pub unsafe fn fragment_shader_entry_point<'a, S, F, L>(&'a self, name: &'a CStr, layout: L)
                                                           -> FragmentShaderEntryPoint<'a, S, F, L>
    {
        FragmentShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }

    #[inline]
    pub unsafe fn compute_shader_entry_point<'a, S, L>(&'a self, name: &'a CStr, layout: L)
                                                       -> ComputeShaderEntryPoint<'a, S, L>
    {
        ComputeShaderEntryPoint {
            module: self,
            name: name,
            layout: layout,
            marker: PhantomData,
        }
    }
}

unsafe impl VulkanObject for ShaderModule {
    type Object = vk::ShaderModule;

    #[inline]
    fn internal_object(&self) -> vk::ShaderModule {
        self.module
    }
}

impl Drop for ShaderModule {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyShaderModule(self.device.internal_object(), self.module, ptr::null());
        }
    }
}

pub struct VertexShaderEntryPoint<'a, S, V, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    vertex_input: V,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, V, L> VertexShaderEntryPoint<'a, S, V, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }

    #[inline]
    pub fn input_definition(&self) -> &V {
        &self.vertex_input
    }
}

pub struct TessControlShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessControlShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> TessEvaluationShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct GeometryShaderEntryPoint<'a, S, I, O, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    primitives: GeometryShaderExecutionMode,
    marker: PhantomData<(S, I, O)>,
}

impl<'a, S, I, O, L> GeometryShaderEntryPoint<'a, S, I, O, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    /// Returns the kind of primitives expected by the geometry shader.
    #[inline]
    pub fn primitives(&self) -> GeometryShaderExecutionMode {
        self.primitives
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

/// Declares which type of primitives are expected by the geometry shader.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum GeometryShaderExecutionMode {
    Points,
    Lines,
    LinesWithAdjacency,
    Triangles,
    TrianglesWithAdjacency,
}

impl GeometryShaderExecutionMode {
    /// Returns true if the given primitive topology can be used with this execution mode.
    #[inline]
    pub fn matches(&self, input: PrimitiveTopology) -> bool {
        match (*self, input) {
            (GeometryShaderExecutionMode::Points, PrimitiveTopology::PointList) => true,
            (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineList) => true,
            (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineStrip) => true,
            (GeometryShaderExecutionMode::LinesWithAdjacency,
             PrimitiveTopology::LineListWithAdjacency) => true,
            (GeometryShaderExecutionMode::LinesWithAdjacency,
             PrimitiveTopology::LineStripWithAdjacency) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleList) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleStrip) => true,
            (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleFan) => true,
            (GeometryShaderExecutionMode::TrianglesWithAdjacency,
             PrimitiveTopology::TriangleListWithAdjancecy) => true,
            (GeometryShaderExecutionMode::TrianglesWithAdjacency,
             PrimitiveTopology::TriangleStripWithAdjacency) => true,
            _ => false,
        }
    }
}

pub struct FragmentShaderEntryPoint<'a, S, F, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<(S, F)>,
}

impl<'a, S, F, L> FragmentShaderEntryPoint<'a, S, F, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

pub struct ComputeShaderEntryPoint<'a, S, L> {
    module: &'a ShaderModule,
    name: &'a CStr,
    layout: L,
    marker: PhantomData<S>,
}

impl<'a, S, L> ComputeShaderEntryPoint<'a, S, L> {
    #[inline]
    pub fn module(&self) -> &'a ShaderModule {
        self.module
    }

    #[inline]
    pub fn name(&self) -> &'a CStr {
        self.name
    }

    #[inline]
    pub fn layout(&self) -> &L {
        &self.layout
    }
}

/// Structs that contain the definition of an interface between two shader stages, or between
/// the outside and a shader stage.
///
/// # Safety
///
/// - Must only provide one entry per location.
/// - The format must not be larger than 128 bits.
///
pub unsafe trait ShaderInterfaceDef {
    /// Iterator returned by `elements`.
    type Iter: ExactSizeIterator<Item = ShaderInterfaceDefEntry>;

    /// Iterates over the elements of the interface.
    fn elements(&self) -> Self::Iter;
}

// FIXME: temporary ; remove as it is unsafe
unsafe impl ShaderInterfaceDef for Vec<ShaderInterfaceDefEntry> {
    type Iter = VecIntoIter<ShaderInterfaceDefEntry>;

    #[inline]
    fn elements(&self) -> Self::Iter {
        self.clone().into_iter()
    }
}

/// Entry of a shader interface definition.
#[derive(Debug, Clone)]
pub struct ShaderInterfaceDefEntry {
    /// Range of locations covered by the element.
    pub location: Range<u32>,
    /// Format of a each location of the element.
    pub format: Format,
    /// Name of the element, or `None` if the name is unknown.
    pub name: Option<Cow<'static, str>>,
}

/// Extension trait for `ShaderInterfaceDef` that specifies that the interface is potentially
/// compatible with another one.
pub unsafe trait ShaderInterfaceDefMatch<I>: ShaderInterfaceDef where I: ShaderInterfaceDef {
    /// Returns true if the two definitions match.
    // TODO: return a descriptive error instead
    fn matches(&self, other: &I) -> bool;
}

// TODO: turn this into a default impl that can be specialized
unsafe impl<T, I> ShaderInterfaceDefMatch<I> for T
    where T: ShaderInterfaceDef, I: ShaderInterfaceDef
{
    fn matches(&self, other: &I) -> bool {
        if self.elements().len() != other.elements().len() {
            return false;
        }

        for a in self.elements() {
            for loc in a.location.clone() {
                let b = match other.elements().find(|e| loc >= e.location.start && loc < e.location.end) {
                    None => return false,
                    Some(b) => b,
                };

                if a.format != b.format {
                    return false;
                }

                // TODO: enforce this?
                /*match (a.name, b.name) {
                    (Some(ref an), Some(ref bn)) => if an != bn { return false },
                    _ => ()
                };*/
            }
        }

        true
    }
}

/// Trait to describe structs that contain specialization data for shaders.
///
/// It is implemented on `()` for shaders that don't have any specialization constant.
pub unsafe trait SpecializationConstants {
    /// Returns descriptors of the struct's layout.
    fn descriptors() -> &'static [SpecializationMapEntry];
}

unsafe impl SpecializationConstants for () {
    #[inline]
    fn descriptors() -> &'static [SpecializationMapEntry] {
        &[]
    }
}

/// Describes an indiviual constant to set in the shader. Also a field in the struct.
// Has the same memory representation as a `VkSpecializationMapEntry`.
#[repr(C)]
pub struct SpecializationMapEntry {
    /// Identifier of the constant in the shader that corresponds to this field.
    pub constant_id: u32,
    /// Offset within this struct for the data.
    pub offset: u32,
    /// Size of the data in bytes.
    pub size: usize,
}
<|endoftext|>


<commit_before>use gl;

pub trait Image2d {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn format(&self) -> ImageFormat;
    fn textel_bytes(&self) -> &[u8];
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Pixel {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

gl_enum! {
    pub gl_enum TextelType {
        UnsignedByte as UNSIGNED_BYTE_TEXTEL = gl::UNSIGNED_BYTE,
        UnsignedShort565 as UNSIGNED_SHORT_5_6_5 = gl::UNSIGNED_SHORT_5_6_5,
        UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,
        UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    pub gl_enum TextelFormat {
        Alpha as ALPHA = gl::ALPHA,
        RGB as RGB = gl::RGB,
        RGBA as RGBA = gl::RGBA
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    pub textel_type: TextelType,
    pub textel_format: TextelFormat
}
<commit_msg>Add `ImageFormat::rgba8()`<commit_after>use gl;

pub trait Image2d {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn format(&self) -> ImageFormat;
    fn textel_bytes(&self) -> &[u8];
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Pixel {
    r: u8,
    g: u8,
    b: u8,
    a: u8
}

pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

gl_enum! {
    pub gl_enum TextelType {
        UnsignedByte as UNSIGNED_BYTE_TEXTEL = gl::UNSIGNED_BYTE,
        UnsignedShort565 as UNSIGNED_SHORT_5_6_5 = gl::UNSIGNED_SHORT_5_6_5,
        UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,
        UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    pub gl_enum TextelFormat {
        Alpha as ALPHA = gl::ALPHA,
        RGB as RGB = gl::RGB,
        RGBA as RGBA = gl::RGBA
    }
}

#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    pub textel_type: TextelType,
    pub textel_format: TextelFormat
}

impl ImageFormat {
    fn rgba8() -> Self {
        ImageFormat {
            textel_type: TextelType::UnsignedByte,
            textel_format: TextelFormat::RGBA
        }
    }
}
<|endoftext|>


<commit_before>extern crate camera_controllers;
extern crate gfx;
extern crate piston_window;
extern crate terra;
extern crate vecmath;

use piston_window::*;
use camera_controllers::{FirstPersonSettings, FirstPerson, CameraPerspective,
                         model_view_projection};

use terra::{Clipmap, DemSource, TerrainFileParams, MaterialSet};
use terra::cache::GeneratedAsset;

fn main() {
    let terrain_file = TerrainFileParams {
        latitude: 44,
        longitude: -74,
        source: DemSource::Usgs30m,
    }.load()
        .unwrap();

    let mut window: PistonWindow = WindowSettings::new("terra preview", [640, 480])
        .exit_on_esc(true)
        .opengl(OpenGL::V3_3)
        .samples(1)
        .build()
        .unwrap();
    window.set_capture_cursor(true);

    let materials = MaterialSet::load(&mut window.factory, &mut window.encoder).unwrap();
    window.encoder.flush(&mut window.device);

    let mut terrain = Clipmap::new(
        terrain_file,
        materials,
        window.factory.clone(),
        &mut window.encoder,
        &window.output_color,
        &window.output_stencil,
    );

    let get_projection = |w: &PistonWindow| {
        let draw_size = w.window.draw_size();
        CameraPerspective {
            fov: 90.0,
            near_clip: 0.5,
            far_clip: 100000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32),
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new([0.0, 0.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 50.0;
    first_person.settings.speed_horizontal = 200.0;

    while let Some(e) = window.next() {
        first_person.event(&e);

        if let Some(_) = e.resize_args() {
            projection = get_projection(&window);
        }

        window.draw_3d(&e, |window| {
            let args = e.render_args().unwrap();

            window.encoder.clear(
                &window.output_color,
                [0.3, 0.3, 0.3, 1.0],
            );
            window.encoder.clear_depth(&window.output_stencil, 1.0);

            let mut camera = first_person.camera(args.ext_dt);
            if let Some(h) = terrain.get_approximate_height(
                [camera.position[0], camera.position[2]],
            )
            {
                camera.position[1] += h + 2.0;
            }
            terrain.update(
                model_view_projection(vecmath::mat4_id(), camera.orthogonal(), projection),
                camera.position,
                &mut window.encoder,
            );
            terrain.render(&mut window.encoder);
        });
    }
}
<commit_msg>Add invisible walls in preview<commit_after>extern crate camera_controllers;
extern crate gfx;
extern crate piston_window;
extern crate terra;
extern crate vecmath;

use piston_window::*;
use camera_controllers::{FirstPersonSettings, FirstPerson, CameraPerspective,
                         model_view_projection};

use terra::{Clipmap, DemSource, TerrainFileParams, MaterialSet};
use terra::cache::GeneratedAsset;

fn main() {
    let terrain_file = TerrainFileParams {
        latitude: 44,
        longitude: -74,
        source: DemSource::Usgs30m,
    }.load()
        .unwrap();

    let mut window: PistonWindow = WindowSettings::new("terra preview", [640, 480])
        .exit_on_esc(true)
        .opengl(OpenGL::V3_3)
        .samples(1)
        .build()
        .unwrap();
    window.set_capture_cursor(true);

    let materials = MaterialSet::load(&mut window.factory, &mut window.encoder).unwrap();
    window.encoder.flush(&mut window.device);

    let mut terrain = Clipmap::new(
        terrain_file,
        materials,
        window.factory.clone(),
        &mut window.encoder,
        &window.output_color,
        &window.output_stencil,
    );

    let get_projection = |w: &PistonWindow| {
        let draw_size = w.window.draw_size();
        CameraPerspective {
            fov: 90.0,
            near_clip: 0.5,
            far_clip: 100000.0,
            aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32),
        }.projection()
    };

    let mut projection = get_projection(&window);
    let mut first_person = FirstPerson::new([0.0, 0.0, 0.0], FirstPersonSettings::keyboard_wasd());
    first_person.settings.speed_vertical = 50.0;
    first_person.settings.speed_horizontal = 200.0;

    while let Some(e) = window.next() {
        first_person.event(&e);

        if let Some(_) = e.resize_args() {
            projection = get_projection(&window);
        }

        window.draw_3d(&e, |window| {
            let args = e.render_args().unwrap();

            window.encoder.clear(
                &window.output_color,
                [0.3, 0.3, 0.3, 1.0],
            );
            window.encoder.clear_depth(&window.output_stencil, 1.0);

            first_person.position[0] = f32::max(first_person.position[0], -3000.0).min(3000.0);
            first_person.position[2] = f32::max(first_person.position[2], -3000.0).min(3000.0);

            let mut camera = first_person.camera(args.ext_dt);
            if let Some(h) = terrain.get_approximate_height(
                [camera.position[0], camera.position[2]],
            )
            {
                camera.position[1] += h + 2.0;
            }
            terrain.update(
                model_view_projection(vecmath::mat4_id(), camera.orthogonal(), projection),
                camera.position,
                &mut window.encoder,
            );
            terrain.render(&mut window.encoder);
        });
    }
}
<|endoftext|>


<commit_before>/*
Functions for printing output/layout
*/

use Settings;

use term::{
    color,
    self
};

use meminfo::MemInfo;
use cpuinfo::CPUInfo;
use graph::Graph;

use std::io::Stdout;

use printutils::*;

//so I don't have to write "let _ = write!(..)" all the time
macro_rules! p {
    ($t:expr, $($s:expr),+) => {
        let _ = write!($t, $($s),+);
    }
}

macro_rules! pl {
    ($t:expr, $($s:expr)+) => {
        let _ = writeln!($t, $($s,)+);
    }
}

//normal mode
pub fn print(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
             cpu: &CPUInfo, mem: &MemInfo, graph: &mut Graph) {
	let mut lines_printed = 19;

	//CPU

	//"x processes on x cores"
	print_header(term, &settings, 57, String::from("CPU"));
	print_highlighted(term, &settings, format!("{}", cpu.processes));
	if cpu.processes > 1 {
		p!(term, " active processes on ");
	} else {
	   	p!(term, " active process on ");
	}
	print_highlighted(term, &settings, format!("{}", cpu.cores));
	pl!(term, " cores      ");
	pl!(term, "");

	//print bars
	print_highlighted(term, &settings, String::from("TOTAL: "));
	let total_percentage = calc_cpu_load_percentage(&cpu.total_load);
	graph.push(total_percentage); //push new data
	print_progress_bar(term, &settings, total_percentage, 40, color::RED);
	print_highlighted(term, &settings, format!(" {} %   ", format_float(total_percentage)));
	pl!(term, "");

	let mut core_counter = 1;
	for core_load in &cpu.cores_load {
		p!(term, "CPU {}: ", core_counter);
		let core_percentage = calc_cpu_load_percentage(&core_load);
		print_progress_bar(term, &settings, core_percentage, 40, color::GREEN);
		p!(term, " {} %   ", format_float(core_percentage));
		pl!(term, "");
		lines_printed += 1;
		core_counter += 1;
	}
	pl!(term, "");

	//print graph
	if settings.enable_graph {
    	print_graph(&mut term, &settings, graph);
	}
	else {
	    lines_printed -= 6;
	}

	//MEMORY

	print_header(term, &settings, 57, String::from("MEMORY"));
	pl!(term, "");

	let memory_use: f64 = mem.memory_use();
	let swap_use: f64 = mem.swap_use();

	p!(term, "  RAM: "); //RAM BAR
	print_progress_bar(term, &settings, memory_use, 40, color::GREEN);
	pl!(term, "");
	print_highlighted(term, &settings, format!("             {}",
         format_gib(mem.total - mem.free - mem.cached)));
	p!(term, " GiB / ");
	print_highlighted(term, &settings, format!("{}", format_gib(mem.total)));
	p!(term, " GiB (");
	print_highlighted(term, &settings, format!(" {}% ", format_float(memory_use)));
	p!(term, ")");
	pl!(term, "\n");

	p!(term, " SWAP: "); //SWAP BAR
	print_progress_bar(term, &settings, swap_use, 40, color::GREEN);
	pl!(term, "");
	print_highlighted(term, &settings, format!("               {}", format_gib(mem.swap_used)));
	p!(term, " GiB / ");
	print_highlighted(term, &settings, format!("{}", format_gib(mem.swap_total)));
	p!(term, " GiB (");
	print_highlighted(term, &settings, format!(" {}% ", format_float(swap_use)));
	p!(term, ")");
	pl!(term, "\n");

	for _ in 0..lines_printed {
		let _ = term.cursor_up();
	}
}

pub fn print_small_mode(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
                        cpu: &CPUInfo, mem: &MemInfo) {
    let mut lines_printed = 9;

    print_header(term, &settings, 28, "CPU:".to_owned());

    //CPU

    pl!(term, "");
   	let cpuload_string = format_float(calc_cpu_load_percentage(&cpu.total_load));
    print_highlighted(term, &settings, format!("{}%  \n", cpuload_string));
    let mut core_counter = 1;
    for core_load in &cpu.cores_load {
		let core_percentage = calc_cpu_load_percentage(&core_load);
		p!(term, "{}", &pad_string(format!("{}% ", format_float(core_percentage)), 7));
        if core_counter == 4 {
            pl!(term, "");
            lines_printed += 1;
        }
        core_counter += 1;
	}
    pl!(term, "");

    //Memory

    print_header(term, &settings, 28, "RAM:".to_owned());
    pl!(term, "");

	let memory_use: f64 = mem.memory_use();
	let swap_use: f64 = mem.swap_use();

    print_highlighted(term, &settings, format_gib(mem.total - mem.free - mem.cached));
    p!(term, " GiB ( ");
    print_highlighted(term, &settings, format!("{}%", format_float(memory_use)));
    p!(term, " ) + \n");
    print_highlighted(term, &settings, format_gib(mem.swap_used));
    p!(term, " GiB Swap ( ");
    print_highlighted(term, &settings, format!("{}%", format_float(swap_use)));
    p!(term, " )");
    pl!(term, "");

    pl!(term, "");
    for _ in 0..lines_printed {
        let _ = term.cursor_up();
    }
}

//a simpler version of print (-l flag)
pub fn print_log_mode(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
                      cpu: &CPUInfo, mem: &MemInfo) {
	let seperator = "    ";

	let time = ::time::now();
	let timestamp = format!("{}m/{}d/{}y-{}h:{}m:{}s",
         time.tm_mon+1, time.tm_mday, time.tm_year+1900, time.tm_hour, time.tm_min, time.tm_sec);
	let cpuload_string = format_float(calc_cpu_load_percentage(&cpu.total_load));
	let mem_string = format_gib(mem.total - mem.free - mem.cached);
	let swap_string = format_gib(mem.swap_used);

	p!(term, "{}{}CPU:", timestamp, seperator);
	print_highlighted(term, &settings, format!("{}%", cpuload_string));
	p!(term, "{}RAM:", seperator);
	print_highlighted(term, &settings, format!("{}Gib", mem_string));
	if mem.swap_used != 0 {
		p!(term, "{}SWAP:", seperator);
		print_highlighted(term, &settings, format!("{}Gib", swap_string));
	}

	pl!(term, "");
}
<commit_msg>changed the small mode interface<commit_after>/*
Functions for printing output/layout
*/

use Settings;

use term::{
    color,
    self
};

use meminfo::MemInfo;
use cpuinfo::CPUInfo;
use graph::Graph;

use std::io::Stdout;

use printutils::*;

//so I don't have to write "let _ = write!(..)" all the time
macro_rules! p {
    ($t:expr, $($s:expr),+) => {
        let _ = write!($t, $($s),+);
    }
}

macro_rules! pl {
    ($t:expr, $($s:expr)+) => {
        let _ = writeln!($t, $($s,)+);
    }
}

//normal mode
pub fn print(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
             cpu: &CPUInfo, mem: &MemInfo, graph: &mut Graph) {
	let mut lines_printed = 19;

	//CPU

	//"x processes on x cores"
	print_header(term, &settings, 57, String::from("CPU"));
	print_highlighted(term, &settings, format!("{}", cpu.processes));
	if cpu.processes > 1 {
		p!(term, " active processes on ");
	} else {
	   	p!(term, " active process on ");
	}
	print_highlighted(term, &settings, format!("{}", cpu.cores));
	pl!(term, " cores      ");
	pl!(term, "");

	//print bars
	print_highlighted(term, &settings, String::from("TOTAL: "));
	let total_percentage = calc_cpu_load_percentage(&cpu.total_load);
	graph.push(total_percentage); //push new data
	print_progress_bar(term, &settings, total_percentage, 40, color::RED);
	print_highlighted(term, &settings, format!(" {} %   ", format_float(total_percentage)));
	pl!(term, "");

	let mut core_counter = 1;
	for core_load in &cpu.cores_load {
		p!(term, "CPU {}: ", core_counter);
		let core_percentage = calc_cpu_load_percentage(&core_load);
		print_progress_bar(term, &settings, core_percentage, 40, color::GREEN);
		p!(term, " {} %   ", format_float(core_percentage));
		pl!(term, "");
		lines_printed += 1;
		core_counter += 1;
	}
	pl!(term, "");

	//print graph
	if settings.enable_graph {
    	print_graph(&mut term, &settings, graph);
	}
	else {
	    lines_printed -= 6;
	}

	//MEMORY

	print_header(term, &settings, 57, String::from("MEMORY"));
	pl!(term, "");

	let memory_use: f64 = mem.memory_use();
	let swap_use: f64 = mem.swap_use();

	p!(term, "  RAM: "); //RAM BAR
	print_progress_bar(term, &settings, memory_use, 40, color::GREEN);
	pl!(term, "");
	print_highlighted(term, &settings, format!("             {}",
         format_gib(mem.total - mem.free - mem.cached)));
	p!(term, " GiB / ");
	print_highlighted(term, &settings, format!("{}", format_gib(mem.total)));
	p!(term, " GiB (");
	print_highlighted(term, &settings, format!(" {}% ", format_float(memory_use)));
	p!(term, ")");
	pl!(term, "\n");

	p!(term, " SWAP: "); //SWAP BAR
	print_progress_bar(term, &settings, swap_use, 40, color::GREEN);
	pl!(term, "");
	print_highlighted(term, &settings, format!("               {}", format_gib(mem.swap_used)));
	p!(term, " GiB / ");
	print_highlighted(term, &settings, format!("{}", format_gib(mem.swap_total)));
	p!(term, " GiB (");
	print_highlighted(term, &settings, format!(" {}% ", format_float(swap_use)));
	p!(term, ")");
	pl!(term, "\n");

	for _ in 0..lines_printed {
		let _ = term.cursor_up();
	}
}

pub fn print_small_mode(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
                        cpu: &CPUInfo, mem: &MemInfo) {
    let mut lines_printed = 4;
    //CPU
	print_highlighted(term, &settings, format!("TOTAL: "));
    let total_percentage = calc_cpu_load_percentage(&cpu.total_load);
    print_progress_bar(term, &settings, total_percentage, 40, color::RED);
    p!(term, " {} %   ", format_float(total_percentage));
    pl!(term, "");
    let mut core_counter = 1;
    for core_load in &cpu.cores_load {
        p!(term, "CPU {}: ", core_counter);
        let core_percentage = calc_cpu_load_percentage(&core_load);
        print_progress_bar(term, &settings, core_percentage, 40, color::GREEN);
        p!(term, " {} %   ", format_float(core_percentage));
        pl!(term, "");
        lines_printed += 1;
        core_counter += 1;
    }
    pl!(term, "");
    //MEM
	let memory_use: f64 = mem.memory_use();
	let swap_use: f64 = mem.swap_use();
    print_highlighted(term, &settings, format!("RAM:   "));
    print_progress_bar(term, &settings, memory_use, 40, color::YELLOW);
    p!(term, " {} %   ", format_float(memory_use));
    pl!(term, "");
    if swap_use > 0.0 {
        print_highlighted(term, &settings, format!("SWAP:  "));
        print_progress_bar(term, &settings, swap_use, 40, color::RED);
        p!(term, " {}   ", format_float(swap_use));
        pl!(term, "");
        lines_printed += 1;
    }
    pl!(term, "");

    for _ in 0..lines_printed {
        let _ = term.cursor_up();
    }
}

//a one-line version of print that can be used to log the data (-l flag)
pub fn print_log_mode(mut term: &mut Box<term::Terminal<Output=Stdout> + Send>, settings: &Settings,
                      cpu: &CPUInfo, mem: &MemInfo) {
	let seperator = "    ";

	let time = ::time::now();
	let timestamp = format!("{}m/{}d/{}y-{}h:{}m:{}s",
         time.tm_mon+1, time.tm_mday, time.tm_year+1900, time.tm_hour, time.tm_min, time.tm_sec);
	let cpuload_string = format_float(calc_cpu_load_percentage(&cpu.total_load));
	let mem_string = format_gib(mem.total - mem.free - mem.cached);
	let swap_string = format_gib(mem.swap_used);

	p!(term, "{}{}CPU:", timestamp, seperator);
	print_highlighted(term, &settings, format!("{}%", cpuload_string));
	p!(term, "{}RAM:", seperator);
	print_highlighted(term, &settings, format!("{}Gib", mem_string));
	if mem.swap_used != 0 {
		p!(term, "{}SWAP:", seperator);
		print_highlighted(term, &settings, format!("{}Gib", swap_string));
	}

	pl!(term, "");
}
<|endoftext|>


<commit_before>use std::path::Path;

use regex::bytes::Regex;
use term::{Attr, Terminal};
use term::color;

use pathutil::strip_prefix;
use types::FileTypeDef;

/// Printer encapsulates all output logic for searching.
///
/// Note that we currently ignore all write errors. It's probably worthwhile
/// to fix this, but printers are only ever used for writes to stdout or
/// writes to memory, neither of which commonly fail.
pub struct Printer<W> {
    /// The underlying writer.
    wtr: W,
    /// Whether anything has been printed to wtr yet.
    has_printed: bool,
    /// Whether to show column numbers for the first match or not.
    column: bool,
    /// The string to use to separate non-contiguous runs of context lines.
    context_separator: Vec<u8>,
    /// The end-of-line terminator used by the printer. In general, eols are
    /// printed via the match directly, but occasionally we need to insert them
    /// ourselves (for example, to print a context separator).
    eol: u8,
    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    heading: bool,
    /// Whether to show every match on its own line.
    line_per_match: bool,
    /// Whether to suppress all output.
    quiet: bool,
    /// A string to use as a replacement of each match in a matching line.
    replace: Option<Vec<u8>>,
    /// Whether to prefix each match with the corresponding file name.
    with_filename: bool,
}

impl<W: Terminal + Send> Printer<W> {
    /// Create a new printer that writes to wtr.
    pub fn new(wtr: W) -> Printer<W> {
        Printer {
            wtr: wtr,
            has_printed: false,
            column: false,
            context_separator: "--".to_string().into_bytes(),
            eol: b'\n',
            heading: false,
            line_per_match: false,
            quiet: false,
            replace: None,
            with_filename: false,
        }
    }

    /// When set, column numbers will be printed for the first match on each
    /// line.
    pub fn column(mut self, yes: bool) -> Printer<W> {
        self.column = yes;
        self
    }

    /// Set the context separator. The default is `--`.
    pub fn context_separator(mut self, sep: Vec<u8>) -> Printer<W> {
        self.context_separator = sep;
        self
    }

    /// Set the end-of-line terminator. The default is `\n`.
    pub fn eol(mut self, eol: u8) -> Printer<W> {
        self.eol = eol;
        self
    }

    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    pub fn heading(mut self, yes: bool) -> Printer<W> {
        self.heading = yes;
        self
    }

    /// Whether to show every match on its own line.
    pub fn line_per_match(mut self, yes: bool) -> Printer<W> {
        self.line_per_match = yes;
        self
    }

    /// When set, all output is suppressed.
    pub fn quiet(mut self, yes: bool) -> Printer<W> {
        self.quiet = yes;
        self
    }

    /// Replace every match in each matching line with the replacement string
    /// given.
    ///
    /// The replacement string syntax is documented here:
    /// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
    pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
        self.replace = Some(replacement);
        self
    }

    /// When set, each match is prefixed with the file name that it came from.
    pub fn with_filename(mut self, yes: bool) -> Printer<W> {
        self.with_filename = yes;
        self
    }

    /// Returns true if and only if something has been printed.
    pub fn has_printed(&self) -> bool {
        self.has_printed
    }

    /// Returns true if the printer has been configured to be quiet.
    pub fn is_quiet(&self) -> bool {
        self.quiet
    }

    /// Flushes the underlying writer and returns it.
    pub fn into_inner(mut self) -> W {
        let _ = self.wtr.flush();
        self.wtr
    }

    /// Prints a type definition.
    pub fn type_def(&mut self, def: &FileTypeDef) {
        self.write(def.name().as_bytes());
        self.write(b": ");
        let mut first = true;
        for pat in def.patterns() {
            if !first {
                self.write(b", ");
            }
            self.write(pat.as_bytes());
            first = false;
        }
        self.write_eol();
    }

    /// Prints the given path.
    pub fn path<P: AsRef<Path>>(&mut self, path: P) {
        let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
        self.write_path(path);
        self.write_eol();
    }

    /// Prints the given path and a count of the number of matches found.
    pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
        if self.with_filename {
            self.write_path(path);
            self.write(b":");
        }
        self.write(count.to_string().as_bytes());
        self.write_eol();
    }

    /// Prints the context separator.
    pub fn context_separate(&mut self) {
        // N.B. We can't use `write` here because of borrowing restrictions.
        if self.quiet {
            return;
        }
        if self.context_separator.is_empty() {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(&self.context_separator);
        let _ = self.wtr.write_all(&[self.eol]);
    }

    pub fn matched<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if !self.line_per_match {
            let column =
                if self.column {
                    Some(re.find(&buf[start..end])
                           .map(|(s, _)| s + 1).unwrap_or(0) as u64)
                } else {
                    None
                };
            return self.write_match(
                re, path, buf, start, end, line_number, column);
        }
        for (s, _) in re.find_iter(&buf[start..end]) {
            let column = if self.column { Some(s as u64) } else { None };
            self.write_match(
                re, path.as_ref(), buf, start, end, line_number, column);
        }
    }

    fn write_match<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
        column: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b":");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b':');
        }
        if let Some(c) = column {
            self.write((c + 1).to_string().as_bytes());
            self.write(b":");
        }
        if self.replace.is_some() {
            let line = re.replace_all(
                &buf[start..end], &**self.replace.as_ref().unwrap());
            self.write(&line);
        } else {
            self.write_matched_line(re, &buf[start..end]);
        }
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
        if !self.wtr.supports_color() {
            self.write(buf);
            return;
        }
        let mut last_written = 0;
        for (s, e) in re.find_iter(buf) {
            self.write(&buf[last_written..s]);
            let _ = self.wtr.fg(color::BRIGHT_RED);
            let _ = self.wtr.attr(Attr::Bold);
            self.write(&buf[s..e]);
            let _ = self.wtr.reset();
            last_written = e;
        }
        self.write(&buf[last_written..]);
    }

    pub fn context<P: AsRef<Path>>(
        &mut self,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b"-");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b'-');
        }
        self.write(&buf[start..end]);
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_heading<P: AsRef<Path>>(&mut self, path: P) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_GREEN);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write_path(path.as_ref());
        self.write_eol();
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
    }

    fn line_number(&mut self, n: u64, sep: u8) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_BLUE);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write(n.to_string().as_bytes());
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
        self.write(&[sep]);
    }

    #[cfg(unix)]
    fn write_path<P: AsRef<Path>>(&mut self, path: P) {
        use std::os::unix::ffi::OsStrExt;

        let path = path.as_ref().as_os_str().as_bytes();
        self.write(path);
    }

    #[cfg(not(unix))]
    fn write_path<P: AsRef<Path>>(&mut self, p: P) {
        self.write(path.as_ref().to_string_lossy().as_bytes());
    }

    fn write(&mut self, buf: &[u8]) {
        if self.quiet {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(buf);
    }

    fn write_eol(&mut self) {
        let eol = self.eol;
        self.write(&[eol]);
    }
}
<commit_msg>fix windows<commit_after>use std::path::Path;

use regex::bytes::Regex;
use term::{Attr, Terminal};
use term::color;

use pathutil::strip_prefix;
use types::FileTypeDef;

/// Printer encapsulates all output logic for searching.
///
/// Note that we currently ignore all write errors. It's probably worthwhile
/// to fix this, but printers are only ever used for writes to stdout or
/// writes to memory, neither of which commonly fail.
pub struct Printer<W> {
    /// The underlying writer.
    wtr: W,
    /// Whether anything has been printed to wtr yet.
    has_printed: bool,
    /// Whether to show column numbers for the first match or not.
    column: bool,
    /// The string to use to separate non-contiguous runs of context lines.
    context_separator: Vec<u8>,
    /// The end-of-line terminator used by the printer. In general, eols are
    /// printed via the match directly, but occasionally we need to insert them
    /// ourselves (for example, to print a context separator).
    eol: u8,
    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    heading: bool,
    /// Whether to show every match on its own line.
    line_per_match: bool,
    /// Whether to suppress all output.
    quiet: bool,
    /// A string to use as a replacement of each match in a matching line.
    replace: Option<Vec<u8>>,
    /// Whether to prefix each match with the corresponding file name.
    with_filename: bool,
}

impl<W: Terminal + Send> Printer<W> {
    /// Create a new printer that writes to wtr.
    pub fn new(wtr: W) -> Printer<W> {
        Printer {
            wtr: wtr,
            has_printed: false,
            column: false,
            context_separator: "--".to_string().into_bytes(),
            eol: b'\n',
            heading: false,
            line_per_match: false,
            quiet: false,
            replace: None,
            with_filename: false,
        }
    }

    /// When set, column numbers will be printed for the first match on each
    /// line.
    pub fn column(mut self, yes: bool) -> Printer<W> {
        self.column = yes;
        self
    }

    /// Set the context separator. The default is `--`.
    pub fn context_separator(mut self, sep: Vec<u8>) -> Printer<W> {
        self.context_separator = sep;
        self
    }

    /// Set the end-of-line terminator. The default is `\n`.
    pub fn eol(mut self, eol: u8) -> Printer<W> {
        self.eol = eol;
        self
    }

    /// Whether to show file name as a heading or not.
    ///
    /// N.B. If with_filename is false, then this setting has no effect.
    pub fn heading(mut self, yes: bool) -> Printer<W> {
        self.heading = yes;
        self
    }

    /// Whether to show every match on its own line.
    pub fn line_per_match(mut self, yes: bool) -> Printer<W> {
        self.line_per_match = yes;
        self
    }

    /// When set, all output is suppressed.
    pub fn quiet(mut self, yes: bool) -> Printer<W> {
        self.quiet = yes;
        self
    }

    /// Replace every match in each matching line with the replacement string
    /// given.
    ///
    /// The replacement string syntax is documented here:
    /// https://doc.rust-lang.org/regex/regex/bytes/struct.Captures.html#method.expand
    pub fn replace(mut self, replacement: Vec<u8>) -> Printer<W> {
        self.replace = Some(replacement);
        self
    }

    /// When set, each match is prefixed with the file name that it came from.
    pub fn with_filename(mut self, yes: bool) -> Printer<W> {
        self.with_filename = yes;
        self
    }

    /// Returns true if and only if something has been printed.
    pub fn has_printed(&self) -> bool {
        self.has_printed
    }

    /// Returns true if the printer has been configured to be quiet.
    pub fn is_quiet(&self) -> bool {
        self.quiet
    }

    /// Flushes the underlying writer and returns it.
    pub fn into_inner(mut self) -> W {
        let _ = self.wtr.flush();
        self.wtr
    }

    /// Prints a type definition.
    pub fn type_def(&mut self, def: &FileTypeDef) {
        self.write(def.name().as_bytes());
        self.write(b": ");
        let mut first = true;
        for pat in def.patterns() {
            if !first {
                self.write(b", ");
            }
            self.write(pat.as_bytes());
            first = false;
        }
        self.write_eol();
    }

    /// Prints the given path.
    pub fn path<P: AsRef<Path>>(&mut self, path: P) {
        let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref());
        self.write_path(path);
        self.write_eol();
    }

    /// Prints the given path and a count of the number of matches found.
    pub fn path_count<P: AsRef<Path>>(&mut self, path: P, count: u64) {
        if self.with_filename {
            self.write_path(path);
            self.write(b":");
        }
        self.write(count.to_string().as_bytes());
        self.write_eol();
    }

    /// Prints the context separator.
    pub fn context_separate(&mut self) {
        // N.B. We can't use `write` here because of borrowing restrictions.
        if self.quiet {
            return;
        }
        if self.context_separator.is_empty() {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(&self.context_separator);
        let _ = self.wtr.write_all(&[self.eol]);
    }

    pub fn matched<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if !self.line_per_match {
            let column =
                if self.column {
                    Some(re.find(&buf[start..end])
                           .map(|(s, _)| s + 1).unwrap_or(0) as u64)
                } else {
                    None
                };
            return self.write_match(
                re, path, buf, start, end, line_number, column);
        }
        for (s, _) in re.find_iter(&buf[start..end]) {
            let column = if self.column { Some(s as u64) } else { None };
            self.write_match(
                re, path.as_ref(), buf, start, end, line_number, column);
        }
    }

    fn write_match<P: AsRef<Path>>(
        &mut self,
        re: &Regex,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
        column: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b":");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b':');
        }
        if let Some(c) = column {
            self.write((c + 1).to_string().as_bytes());
            self.write(b":");
        }
        if self.replace.is_some() {
            let line = re.replace_all(
                &buf[start..end], &**self.replace.as_ref().unwrap());
            self.write(&line);
        } else {
            self.write_matched_line(re, &buf[start..end]);
        }
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_matched_line(&mut self, re: &Regex, buf: &[u8]) {
        if !self.wtr.supports_color() {
            self.write(buf);
            return;
        }
        let mut last_written = 0;
        for (s, e) in re.find_iter(buf) {
            self.write(&buf[last_written..s]);
            let _ = self.wtr.fg(color::BRIGHT_RED);
            let _ = self.wtr.attr(Attr::Bold);
            self.write(&buf[s..e]);
            let _ = self.wtr.reset();
            last_written = e;
        }
        self.write(&buf[last_written..]);
    }

    pub fn context<P: AsRef<Path>>(
        &mut self,
        path: P,
        buf: &[u8],
        start: usize,
        end: usize,
        line_number: Option<u64>,
    ) {
        if self.heading && self.with_filename && !self.has_printed {
            self.write_heading(path.as_ref());
        } else if !self.heading && self.with_filename {
            self.write_path(path.as_ref());
            self.write(b"-");
        }
        if let Some(line_number) = line_number {
            self.line_number(line_number, b'-');
        }
        self.write(&buf[start..end]);
        if buf[start..end].last() != Some(&self.eol) {
            self.write_eol();
        }
    }

    fn write_heading<P: AsRef<Path>>(&mut self, path: P) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_GREEN);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write_path(path.as_ref());
        self.write_eol();
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
    }

    fn line_number(&mut self, n: u64, sep: u8) {
        if self.wtr.supports_color() {
            let _ = self.wtr.fg(color::BRIGHT_BLUE);
            let _ = self.wtr.attr(Attr::Bold);
        }
        self.write(n.to_string().as_bytes());
        if self.wtr.supports_color() {
            let _ = self.wtr.reset();
        }
        self.write(&[sep]);
    }

    #[cfg(unix)]
    fn write_path<P: AsRef<Path>>(&mut self, path: P) {
        use std::os::unix::ffi::OsStrExt;

        let path = path.as_ref().as_os_str().as_bytes();
        self.write(path);
    }

    #[cfg(not(unix))]
    fn write_path<P: AsRef<Path>>(&mut self, path: P) {
        self.write(path.as_ref().to_string_lossy().as_bytes());
    }

    fn write(&mut self, buf: &[u8]) {
        if self.quiet {
            return;
        }
        self.has_printed = true;
        let _ = self.wtr.write_all(buf);
    }

    fn write_eol(&mut self) {
        let eol = self.eol;
        self.write(&[eol]);
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone,Copy)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            match self.status {
                ProgramStatus::Normal => {
                    while index < self.instructions.len() {
                        match self.instructions[index] {
                            Command::JumpForward => {
                                let (tmp_index, status) = self.start_jump_forward(vm, index);
                                self.status = status;
                                index = tmp_index;
                            },
                            Command::JumpBackward => index = self.jump_backward(&vm, index),
                            command => {
                                vm.apply(command);
                                index += 1;
                            }
                        }
                        self.instruction_pointer = Some(index);
                    }
                },
                ProgramStatus::Seeking(goal_depth) => {
                    let (new_index, new_status) = self.seek_forward(index, goal_depth);
                    self.instruction_pointer = Some(new_index);
                    self.status = new_status;
                    self.execute(vm);
                }
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {},
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal)
            }
        }
        return (self.instructions.len(), self.status)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match vm.cells[vm.data_pointer] {
            0 => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            },
            _ => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }
        }
    }
}
<commit_msg>Fix styling in program.jump_backward<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone,Copy)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            match self.status {
                ProgramStatus::Normal => {
                    while index < self.instructions.len() {
                        match self.instructions[index] {
                            Command::JumpForward => {
                                let (tmp_index, status) = self.start_jump_forward(vm, index);
                                self.status = status;
                                index = tmp_index;
                            },
                            Command::JumpBackward => index = self.jump_backward(&vm, index),
                            command => {
                                vm.apply(command);
                                index += 1;
                            }
                        }
                        self.instruction_pointer = Some(index);
                    }
                },
                ProgramStatus::Seeking(goal_depth) => {
                    let (new_index, new_status) = self.seek_forward(index, goal_depth);
                    self.instruction_pointer = Some(new_index);
                    self.status = new_status;
                    self.execute(vm);
                }
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth -= 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {},
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal)
            }
        }
        return (self.instructions.len(), self.status)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match vm.cells[vm.data_pointer] {
            0 => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            },
            _ => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }
        }
    }
}
<|endoftext|>