<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::mem;

use parse;
use enums;

/// Translates all the structs that are contained in the SPIR-V document as Rust structs.
pub fn write_structs(doc: &parse::Spirv) -> String {
    let mut result = String::new();

    for instruction in &doc.instructions {
        match *instruction {
            parse::Instruction::TypeStruct { result_id, ref member_types } => {
                result.push_str(&write_struct(doc, result_id, member_types));
                result.push_str("\n");
            },
            _ => ()
        }
    }

    result
}

/// Writes a single struct.
fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
    let name = ::name_from_id(doc, struct_id);

    let mut members_defs = Vec::with_capacity(members.len());

    // Contains the offset of the next field.
    // Equals to `None` if there's a runtime-sized field in there.
    let mut current_rust_offset = Some(0);

    for (num, &member) in members.iter().enumerate() {
        let (ty, rust_size, rust_align) = type_from_id(doc, member);
        let member_name = ::member_name_from_id(doc, struct_id, num as u32);

        // Ignore the whole struct is a member is built in, which includes
        // `gl_Position` for example.
        if is_builtin_member(doc, struct_id, num as u32) {
            return String::new();
        }

        let spirv_offset = doc.instructions.iter().filter_map(|i| {
            match *i {
                parse::Instruction::MemberDecorate { target_id, member,
                                                   decoration: enums::Decoration::DecorationOffset,
                                                   ref params } if target_id == struct_id &&
                                                                   member as usize == num =>
                {
                    return Some(params[0]);
                },
                _ => ()
            };

            None
        }).next();

        // Some structs don't have `Offset` decorations, in the case they are used as local
        // variables only. Ignoring these.
        let spirv_offset = match spirv_offset {
            Some(o) => o as usize,
            None => return String::new()
        };

        // We need to add a dummy field if necessary.
        {
            let current_rust_offset = current_rust_offset.as_mut().expect("Found runtime-sized member in non-final position");

            // Updating current_rust_offset to take the alignment of the next field into account
            *current_rust_offset = if *current_rust_offset == 0 {
                0
            } else {
                (1 + (*current_rust_offset - 1) / rust_align) * rust_align
            };

            if spirv_offset != *current_rust_offset {
                let diff = spirv_offset.checked_sub(*current_rust_offset).unwrap();
                members_defs.push(format!("_dummy: [u8; {}]", diff));       // FIXME: fix name if there are multiple dummies
                *current_rust_offset += diff;
            }
        }

        // Updating `current_rust_offset`.
        if let Some(s) = rust_size {
            *current_rust_offset.as_mut().unwrap() += s;
        } else {
            current_rust_offset = None;
        }

        members_defs.push(format!("pub {name}: {ty}  /* offset: {offset} */",
                                  name = member_name, ty = ty, offset = spirv_offset));
    }

    // We can only derive common traits if there's no unsized member in the struct.
    let derive = if current_rust_offset.is_some() {
        "#[derive(Copy, Clone, Debug, Default)]\n"
    } else {
        ""
    };

    format!("#[repr(C)]\n{derive}\
             pub struct {name} {{\n\t{members}\n}}\n",
            derive = derive, name = name, members = members_defs.join(",\n\t"))
}

/// Returns true if a `BuiltIn` decorator is applied on a struct member.
fn is_builtin_member(doc: &parse::Spirv, id: u32, member_id: u32) -> bool {
    for instruction in &doc.instructions {
        match *instruction {
            parse::Instruction::MemberDecorate { target_id, member,
                                                 decoration: enums::Decoration::DecorationBuiltIn,
                                                 .. } if target_id == id && member == member_id =>
            {
                return true;
            },
            _ => ()
        }
    }

    false
}

/// Returns the type name to put in the Rust struct, and its size and alignment.
///
/// The size can be `None` if it's only known at runtime.
fn type_from_id(doc: &parse::Spirv, searched: u32) -> (String, Option<usize>, usize) {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return ("bool".to_owned(), Some(mem::size_of::<bool>()), mem::align_of::<bool>())
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                // FIXME: width
                return ("i32".to_owned(), Some(mem::size_of::<i32>()), mem::align_of::<i32>())
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                // FIXME: width
                return ("f32".to_owned(), Some(mem::size_of::<f32>()), mem::align_of::<f32>())
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, component_id);
                return (format!("[{}; {}]", t, count), t_size.map(|s| s * count as usize), t_align);
            },
            &parse::Instruction::TypeMatrix { result_id, column_type_id, column_count } if result_id == searched => {
                // FIXME: row-major or column-major
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, column_type_id);
                return (format!("[{}; {}]", t, column_count), t_size.map(|s| s * column_count as usize), t_align);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return (format!("[{}; {}]", t, len), t_size.map(|s| s * len as usize), t_align);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, _, t_align) = type_from_id(doc, type_id);
                return (format!("[{}]", t), None, t_align);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = ::name_from_id(doc, result_id);
                let size = member_types.iter().filter_map(|&t| type_from_id(doc, t).1).fold(0, |a,b|a+b);
                let align = member_types.iter().map(|&t| type_from_id(doc, t).2).max().unwrap_or(1);
                return (name, Some(size), align);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}
<commit_msg>Print the array stride for debugging purposes as well<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::mem;

use parse;
use enums;

/// Translates all the structs that are contained in the SPIR-V document as Rust structs.
pub fn write_structs(doc: &parse::Spirv) -> String {
    let mut result = String::new();

    for instruction in &doc.instructions {
        match *instruction {
            parse::Instruction::TypeStruct { result_id, ref member_types } => {
                result.push_str(&write_struct(doc, result_id, member_types));
                result.push_str("\n");
            },
            _ => ()
        }
    }

    result
}

/// Writes a single struct.
fn write_struct(doc: &parse::Spirv, struct_id: u32, members: &[u32]) -> String {
    let name = ::name_from_id(doc, struct_id);

    let mut members_defs = Vec::with_capacity(members.len());

    // Contains the offset of the next field.
    // Equals to `None` if there's a runtime-sized field in there.
    let mut current_rust_offset = Some(0);

    for (num, &member) in members.iter().enumerate() {
        let (ty, rust_size, rust_align) = type_from_id(doc, member);
        let member_name = ::member_name_from_id(doc, struct_id, num as u32);

        // Ignore the whole struct is a member is built in, which includes
        // `gl_Position` for example.
        if is_builtin_member(doc, struct_id, num as u32) {
            return String::new();
        }

        let spirv_offset = doc.instructions.iter().filter_map(|i| {
            match *i {
                parse::Instruction::MemberDecorate { target_id, member,
                                                   decoration: enums::Decoration::DecorationOffset,
                                                   ref params } if target_id == struct_id &&
                                                                   member as usize == num =>
                {
                    return Some(params[0]);
                },
                _ => ()
            };

            None
        }).next();

        let spirv_stride = doc.instructions.iter().filter_map(|i| {
            match *i {
                parse::Instruction::Decorate { target_id,
                                               decoration: enums::Decoration::DecorationArrayStride,
                                               ref params } if target_id == member =>
                {
                    return Some(params[0]);
                },
                _ => ()
            };

            None
        }).next();

        // Some structs don't have `Offset` decorations, in the case they are used as local
        // variables only. Ignoring these.
        let spirv_offset = match spirv_offset {
            Some(o) => o as usize,
            None => return String::new()
        };

        // We need to add a dummy field if necessary.
        {
            let current_rust_offset = current_rust_offset.as_mut().expect("Found runtime-sized member in non-final position");

            // Updating current_rust_offset to take the alignment of the next field into account
            *current_rust_offset = if *current_rust_offset == 0 {
                0
            } else {
                (1 + (*current_rust_offset - 1) / rust_align) * rust_align
            };

            if spirv_offset != *current_rust_offset {
                let diff = spirv_offset.checked_sub(*current_rust_offset).unwrap();
                members_defs.push(format!("_dummy: [u8; {}]", diff));       // FIXME: fix name if there are multiple dummies
                *current_rust_offset += diff;
            }
        }

        // Updating `current_rust_offset`.
        if let Some(s) = rust_size {
            *current_rust_offset.as_mut().unwrap() += s;
        } else {
            current_rust_offset = None;
        }

        members_defs.push(format!("pub {name}: {ty}  /* offset: {offset}, stride: {stride:?} */",
                                  name = member_name, ty = ty, offset = spirv_offset, stride = spirv_stride));
    }

    // We can only derive common traits if there's no unsized member in the struct.
    let derive = if current_rust_offset.is_some() {
        "#[derive(Copy, Clone, Debug, Default)]\n"
    } else {
        ""
    };

    format!("#[repr(C)]\n{derive}\
             pub struct {name} {{\n\t{members}\n}}\n",
            derive = derive, name = name, members = members_defs.join(",\n\t"))
}

/// Returns true if a `BuiltIn` decorator is applied on a struct member.
fn is_builtin_member(doc: &parse::Spirv, id: u32, member_id: u32) -> bool {
    for instruction in &doc.instructions {
        match *instruction {
            parse::Instruction::MemberDecorate { target_id, member,
                                                 decoration: enums::Decoration::DecorationBuiltIn,
                                                 .. } if target_id == id && member == member_id =>
            {
                return true;
            },
            _ => ()
        }
    }

    false
}

/// Returns the type name to put in the Rust struct, and its size and alignment.
///
/// The size can be `None` if it's only known at runtime.
fn type_from_id(doc: &parse::Spirv, searched: u32) -> (String, Option<usize>, usize) {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return ("bool".to_owned(), Some(mem::size_of::<bool>()), mem::align_of::<bool>())
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                // FIXME: width
                return ("i32".to_owned(), Some(mem::size_of::<i32>()), mem::align_of::<i32>())
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                // FIXME: width
                return ("f32".to_owned(), Some(mem::size_of::<f32>()), mem::align_of::<f32>())
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, component_id);
                return (format!("[{}; {}]", t, count), t_size.map(|s| s * count as usize), t_align);
            },
            &parse::Instruction::TypeMatrix { result_id, column_type_id, column_count } if result_id == searched => {
                // FIXME: row-major or column-major
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, column_type_id);
                return (format!("[{}; {}]", t, column_count), t_size.map(|s| s * column_count as usize), t_align);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, t_size, t_align) = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return (format!("[{}; {}]", t, len), t_size.map(|s| s * len as usize), t_align);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                debug_assert_eq!(mem::align_of::<[u32; 3]>(), mem::align_of::<u32>());
                let (t, _, t_align) = type_from_id(doc, type_id);
                return (format!("[{}]", t), None, t_align);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = ::name_from_id(doc, result_id);
                let size = member_types.iter().filter_map(|&t| type_from_id(doc, t).1).fold(0, |a,b|a+b);
                let align = member_types.iter().map(|&t| type_from_id(doc, t).2).max().unwrap_or(1);
                return (name, Some(size), align);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}
<|endoftext|>


<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,
}
<commit_msg>Improve formatting<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>//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `Definition` trait.
//!
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `Definition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```no_run
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::Buffer;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = unsafe { std::mem::uninitialized() };
//! # let queue: Arc<Queue> = unsafe { std::mem::uninitialized() };
//!
//! struct Vertex {
//!     position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//!     vertex_buffer: true,
//!     .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = Buffer::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//!                                                     .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
//!
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

/// Information about a single attribute within a vertex.
pub struct AttributeInfo {
    /// Number of bytes between the start of a vertex and the location of attribute.
    pub offset: usize,
    /// Data type of the attribute.
    pub format: Format,
}

/// Trait for types that contain a definition of the vertex input used by a graphics pipeline.
pub unsafe trait Definition {
    /// Iterator used to enumerate the list of buffers.
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer (within the iterator
    /// returned by `buffers`) in which the attribute is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

/// Extension for `Definition` trait. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait Source<L>: Definition {
    /// Iterator used by `decode`.
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Checks and returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

/// Implementation of `Definition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

/// Trait for data types that can be used as vertex attributes. Used by the `impl_vertex!` macro.
pub unsafe trait Data {
    /// Returns the format of the attribute.
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for u32 {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for [u32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for [u32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}

unsafe impl Data for (u32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for (u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for (u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for (u32, u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}
<commit_msg>Fix OneVertexOneInstanceDefinition being wrongly implemented<commit_after>//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `Definition` trait.
//!
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `Definition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```no_run
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::Buffer;
//! use vulkano::buffer::Usage as BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = unsafe { std::mem::uninitialized() };
//! # let queue: Arc<Queue> = unsafe { std::mem::uninitialized() };
//!
//! struct Vertex {
//!     position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//!     vertex_buffer: true,
//!     .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = Buffer::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//!                                                     .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
//!
use std::marker::PhantomData;
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;

use buffer::Buffer;
use buffer::AbstractBuffer;
use format::Format;
use memory::MemorySourceChunk;
use vk;

#[derive(Copy, Clone, Debug)]
#[repr(u32)]
pub enum InputRate {
    Vertex = vk::VERTEX_INPUT_RATE_VERTEX,
    Instance = vk::VERTEX_INPUT_RATE_INSTANCE,
}

/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
/// from a vertex shader.
pub unsafe trait Vertex {
    /// Returns the characteristics of a vertex attribute.
    fn attrib(name: &str) -> Option<AttributeInfo>;
}

/// Information about a single attribute within a vertex.
pub struct AttributeInfo {
    /// Number of bytes between the start of a vertex and the location of attribute.
    pub offset: usize,
    /// Data type of the attribute.
    pub format: Format,
}

/// Trait for types that contain a definition of the vertex input used by a graphics pipeline.
pub unsafe trait Definition {
    /// Iterator used to enumerate the list of buffers.
    type InfoIter: ExactSizeIterator<Item = (usize, InputRate)>;

    /// Returns information about an attribute, and the index of the buffer (within the iterator
    /// returned by `buffers`) in which the attribute is found.
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)>;

    /// Produces an iterator that returns the stride (in bytes) and input rate of each buffer.
    fn buffers(&self) -> Self::InfoIter;
}

/// Extension for `Definition` trait. The `L` parameter is an acceptable vertex source for this
/// vertex definition.
pub unsafe trait Source<L>: Definition {
    /// Iterator used by `decode`.
    type Iter: ExactSizeIterator<Item = Arc<AbstractBuffer>>;

    /// Checks and returns the list of buffers, number of vertices and number of instances.
    fn decode(&self, L) -> (Self::Iter, usize, usize);
}

/// Implementation of `Definition` for a single vertex buffer.
pub struct SingleBufferDefinition<T>(pub PhantomData<T>);

impl<T> SingleBufferDefinition<T> {
    #[inline]
    pub fn new() -> SingleBufferDefinition<T> { SingleBufferDefinition(PhantomData) }
}

unsafe impl<T> Definition for SingleBufferDefinition<T> where T: Vertex {
    type InfoIter = OptionIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        <T as Vertex>::attrib(name).map(|info| (0, info))
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        Some((mem::size_of::<T>(), InputRate::Vertex)).into_iter()
    }
}

unsafe impl<'a, V, M> Source<&'a Arc<Buffer<[V], M>>> for SingleBufferDefinition<V>
    where V: Vertex + 'static, M: MemorySourceChunk + 'static
{
    type Iter = OptionIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: &'a Arc<Buffer<[V], M>>)
              -> (OptionIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = Some(source.clone() as Arc<_>).into_iter();
        (iter, source.len(), 1)
    }
}

/// Unstable.
// TODO: shouldn't be just `Two` but `Multi`
pub struct TwoBuffersDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> TwoBuffersDefinition<T, U> {
    #[inline]
    pub fn new() -> TwoBuffersDefinition<T, U> { TwoBuffersDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for TwoBuffersDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Vertex)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for TwoBuffersDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, [source.0.len(), source.1.len()].iter().cloned().min().unwrap(), 1)
    }
}

/// Unstable.
// TODO: bad way to do things
pub struct OneVertexOneInstanceDefinition<T, U>(pub PhantomData<(T, U)>);

impl<T, U> OneVertexOneInstanceDefinition<T, U> {
    #[inline]
    pub fn new() -> OneVertexOneInstanceDefinition<T, U> { OneVertexOneInstanceDefinition(PhantomData) }
}

unsafe impl<T, U> Definition for OneVertexOneInstanceDefinition<T, U> where T: Vertex, U: Vertex {
    type InfoIter = VecIntoIter<(usize, InputRate)>;

    #[inline]
    fn attrib(&self, name: &str) -> Option<(usize, AttributeInfo)> {
        if let Some(a) = <T as Vertex>::attrib(name) {
            Some((0, a))
        } else if let Some(a) = <U as Vertex>::attrib(name) {
            Some((1, a))
        } else {
            None
        }
    }

    #[inline]
    fn buffers(&self) -> Self::InfoIter {
        vec![
            (mem::size_of::<T>(), InputRate::Vertex),
            (mem::size_of::<U>(), InputRate::Instance)
        ].into_iter()
    }
}

unsafe impl<'a, T, U, Mt, Mu> Source<(&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>)> for OneVertexOneInstanceDefinition<T, U>
    where T: Vertex + 'static, Mt: MemorySourceChunk + 'static,
          U: Vertex + 'static, Mu: MemorySourceChunk + 'static
{
    type Iter = VecIntoIter<Arc<AbstractBuffer>>;

    #[inline]
    fn decode(&self, source: (&'a Arc<Buffer<[T], Mt>>, &'a Arc<Buffer<[U], Mu>>))
              -> (VecIntoIter<Arc<AbstractBuffer>>, usize, usize)
    {
        let iter = vec![source.0.clone() as Arc<_>, source.1.clone() as Arc<_>].into_iter();
        (iter, source.0.len(), source.1.len())
    }
}

/// Implements the `Vertex` trait on a struct.
// TODO: add example
#[macro_export]
macro_rules! impl_vertex {
    ($out:ident $(, $member:ident)*) => (
        unsafe impl $crate::pipeline::vertex::Vertex for $out {
            #[inline(always)]
            fn attrib(name: &str) -> Option<$crate::pipeline::vertex::AttributeInfo> {
                $(
                    if name == stringify!($member) {
                        return Some($crate::pipeline::vertex::AttributeInfo {
                            offset: unsafe {
                                let dummy = 0usize as *const $out;
                                let member = (&(&*dummy).$member) as *const _;
                                member as usize
                            },

                            format: unsafe {
                                #[inline] fn f<T: $crate::pipeline::vertex::Data>(_: &T) -> $crate::format::Format { T::format() }
                                let dummy = 0usize as *const $out;
                                f(&(&*dummy).$member)
                            },
                        });
                    }
                )*

                None
            }
        }
    )
}

/// Trait for data types that can be used as vertex attributes. Used by the `impl_vertex!` macro.
pub unsafe trait Data {
    /// Returns the format of the attribute.
    fn format() -> Format;
}

unsafe impl Data for f32 {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for [f32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for [f32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for [f32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for (f32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Sfloat
    }
}

unsafe impl Data for (f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Sfloat
    }
}

unsafe impl Data for (f32, f32, f32, f32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Sfloat
    }
}

unsafe impl Data for u32 {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 1] {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for [u32; 2] {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for [u32; 3] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for [u32; 4] {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}

unsafe impl Data for (u32,) {
    #[inline]
    fn format() -> Format {
        Format::R32Uint
    }
}

unsafe impl Data for (u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32Uint
    }
}

unsafe impl Data for (u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32Uint
    }
}

unsafe impl Data for (u32, u32, u32, u32) {
    #[inline]
    fn format() -> Format {
        Format::R32G32B32A32Uint
    }
}
<|endoftext|>


<commit_before>use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => cfg!(feature = "lazy-blob") || IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest).map_err(|err| {
                format!("could not read tests from file {}: {}", path.display(), err)
            })?;
        }
    }
    Ok(())
}

fn read_all_tests(path: &Path) -> Result<Vec<Test<WasmTest>>, Box<dyn Error>> {
    let mut tests = Vec::new();
    read_tests_from_dir(path, &mut tests)?;
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_tests_from_dir(&proposals_dir.join($name), &mut tests)?;
            }
        };
    }

    read_proposal_tests!("tail-call");

    if tests.is_empty() {
        return Err("Couldn't find any tests. Did you run `git submodule update --init`?".into());
    }

    Ok(tests)
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let module = match (
        Module::decode_from(test.module.as_slice()),
        &test.expect_result,
    ) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error:\n{:#}",
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    if cfg!(feature = "lazy-blob") {
        eprintln!("Warning: tests are being run in a lazy mode and will be incomplete.");
    }
    let tests = read_all_tests(&Path::new("tests").join("testsuite")).unwrap_or_else(|err| {
        panic!("{}", err);
    });
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<commit_msg>Provide a bit more details on failure<commit_after>use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::error::Error;
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::Module;
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            } => (span, module, Err(message)),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match expect_result {
                Ok(()) => false,
                Err(err) => cfg!(feature = "lazy-blob") || IGNORED_ERRORS.contains(&err),
            },
            is_bench: false,
            data: WasmTest {
                module: module.encode()?,
                expect_result: expect_result.map_err(|err| err.to_owned()),
            },
        });
    }
    Ok(())
}

fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>) -> Result<(), Box<dyn Error>> {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest).map_err(|err| {
                format!("could not read tests from file {}: {}", path.display(), err)
            })?;
        }
    }
    Ok(())
}

fn read_all_tests(path: &Path) -> Result<Vec<Test<WasmTest>>, Box<dyn Error>> {
    let mut tests = Vec::new();
    read_tests_from_dir(path, &mut tests)?;
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_tests_from_dir(&proposals_dir.join($name), &mut tests)?;
            }
        };
    }

    read_proposal_tests!("tail-call");
    read_proposal_tests!("bulk-memory-operations");

    if tests.is_empty() {
        return Err("Couldn't find any tests. Did you run `git submodule update --init`?".into());
    }

    Ok(tests)
}

fn run_test(test: &WasmTest) -> Result<(), Box<dyn Error>> {
    let mut slice = test.module.as_slice();
    let module = match (Module::decode_from(&mut slice), &test.expect_result) {
        (Ok(_), Err(err)) => {
            return Err(format!(
                "Expected an invalid module definition with an error: {}",
                err
            )
            .into());
        }
        (Err(err), Ok(())) => {
            return Err(format!(
                "Expected a valid module definition, but got an error\nParsed part: {:02X?}\nUnparsed part: {:02X?}\nError: {:#}",
                &test.module[..test.module.len() - slice.len()],
                slice,
                err
            )
            .into());
        }
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return Ok(()),
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            return Err(format!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module, module2
            )
            .into());
        }
    }
    Ok(())
}

fn main() {
    if cfg!(feature = "lazy-blob") {
        eprintln!("Warning: tests are being run in a lazy mode and will be incomplete.");
    }
    let tests = read_all_tests(&Path::new("tests").join("testsuite")).unwrap_or_else(|err| {
        panic!("{}", err);
    });
    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit()
}
<|endoftext|>


<commit_before>extern crate websocat;

extern crate env_logger;
extern crate futures;
extern crate tokio_core;
extern crate tokio_timer;

use futures::future::Future;

use tokio_core::reactor::Core;
use websocat::{spec, WebsocatConfiguration};

#[test]
fn trivial() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let s1 = spec("literal:qwerty").unwrap();
    let s2 = spec("assert:qwerty").unwrap();
    let websocat = WebsocatConfiguration {
        opts: Default::default(),
        s1,
        s2,
    };

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|_| {
            panic!();
        }),
    );

    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
fn tcp() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert2y").unwrap();
        let s2 = spec("tcp-l:127.0.0.1:45912").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("tcp:127.0.0.1:45912").unwrap();
        let s2 = spec("assert:qwert2y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
fn ws() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert3y").unwrap();
        let s2 = spec("ws-l:127.0.0.1:45913").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("ws://127.0.0.1:45913/ololo").unwrap();
        let s2 = spec("assert:qwert3y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
#[cfg(unix)]
fn unix() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert3y").unwrap();
        let s2 = spec("unix-l:zxc").unwrap();

        let mut opts: websocat::Options = Default::default();
        opts.unlink_unix_socket = true;
        let websocat = WebsocatConfiguration { opts, s1, s2 };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("unix-c:zxc").unwrap();
        let s2 = spec("assert:qwert3y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
    let _ = ::std::fs::remove_file("zxc");
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn abstract_() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert4y").unwrap();
        let s2 = spec("abstract-l:zxc").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("abstract-c:zxc").unwrap();
        let s2 = spec("assert:qwert4y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}
<commit_msg>Add a failing testcase<commit_after>extern crate websocat;

extern crate env_logger;
extern crate futures;
extern crate tokio_core;
extern crate tokio_timer;

use futures::future::Future;

use tokio_core::reactor::Core;
use websocat::{spec, WebsocatConfiguration};

#[test]
fn trivial() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let s1 = spec("literal:qwerty").unwrap();
    let s2 = spec("assert:qwerty").unwrap();
    let websocat = WebsocatConfiguration {
        opts: Default::default(),
        s1,
        s2,
    };

    let prog = websocat.serve(
        core.handle(),
        std::rc::Rc::new(|_| {
            panic!();
        }),
    );

    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
fn tcp() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert2y").unwrap();
        let s2 = spec("tcp-l:127.0.0.1:45912").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("tcp:127.0.0.1:45912").unwrap();
        let s2 = spec("assert:qwert2y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
fn ws() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert3y").unwrap();
        let s2 = spec("ws-l:127.0.0.1:45913").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("ws://127.0.0.1:45913/ololo").unwrap();
        let s2 = spec("assert:qwert3y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
fn ws_persist() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("ws-l:127.0.0.1:45914").unwrap();
        let s2 = spec("literal:qwert4y").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("literal:invalid_connection_request").unwrap();
        let s2 = spec("tcp:127.0.0.1:45914").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };
    let prog3 = {
        let s1 = spec("ws://127.0.0.1:45914/ololo").unwrap();
        let s2 = spec("assert:qwert4y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    core.handle().spawn(prog1);
    core.handle().spawn(prog2);
    let prog = prog3;
    core.run(prog).map_err(|()| panic!()).unwrap();
}

#[test]
#[cfg(unix)]
fn unix() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert3y").unwrap();
        let s2 = spec("unix-l:zxc").unwrap();

        let mut opts: websocat::Options = Default::default();
        opts.unlink_unix_socket = true;
        let websocat = WebsocatConfiguration { opts, s1, s2 };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("unix-c:zxc").unwrap();
        let s2 = spec("assert:qwert3y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
    let _ = ::std::fs::remove_file("zxc");
}

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn abstract_() {
    let _ = env_logger::try_init();
    let mut core = Core::new().unwrap();

    let prog1 = {
        let s1 = spec("literal:qwert4y").unwrap();
        let s2 = spec("abstract-l:zxc").unwrap();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        websocat.serve(
            core.handle(),
            std::rc::Rc::new(|e| {
                eprintln!("{}", e);
                panic!();
            }),
        )
    };
    let prog2 = {
        let s1 = spec("abstract-c:zxc").unwrap();
        let s2 = spec("assert:qwert4y").unwrap();
        let h2 = core.handle();

        let websocat = WebsocatConfiguration {
            opts: Default::default(),
            s1,
            s2,
        };

        let t = tokio_timer::wheel().build();
        let delay = t.sleep(std::time::Duration::new(0, 200_000_000))
            .map_err(|_| ());

        delay.and_then(|()| {
            websocat.serve(
                h2,
                std::rc::Rc::new(|e| {
                    eprintln!("{}", e);
                    panic!();
                }),
            )
        })
    };

    let prog = prog1.join(prog2);
    core.run(prog).map_err(|()| panic!()).unwrap();
}
<|endoftext|>


<commit_before>use std::cmp::Eq;
use core::fmt::Show;
use std::fmt::Formatter;
use std::fmt::Result;

#[cfg(test)]
mod coords_test;

pub struct Position2D{
    pub x: int,
    pub y: int,
}

impl Eq for Position2D{

}

impl PartialEq for Position2D{
    fn eq(&self, other: &Position2D) -> bool{
        self.x == other.x && self.y == other.y
    }
}

impl Show for Position2D{
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "Position ({},{})", self.x, self.y)
    }
}
<commit_msg>use lowercase name for position<commit_after>use std::cmp::Eq;
use core::fmt::Show;
use std::fmt::Formatter;
use std::fmt::Result;

#[cfg(test)]
mod coords_test;

pub struct Position2D{
    pub x: int,
    pub y: int,
}

impl Eq for Position2D{

}

impl PartialEq for Position2D{
    fn eq(&self, other: &Position2D) -> bool{
        self.x == other.x && self.y == other.y
    }
}

impl Show for Position2D{
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "position ({},{})", self.x, self.y)
    }
}
<|endoftext|>


<commit_before>///! Helper functions for tests
use std::{fs::read_to_string, path::PathBuf};

/// Get the path of the home directory of this repository
pub fn home() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .to_path_buf()
}

/// Get the path of the `fixtures` directory
pub fn fixtures() -> PathBuf {
    home().join("fixtures")
}

/// Generate snapshots from the string content of fixtures matching
/// a glob pattern.
pub fn snapshot_content<F: FnMut(&str)>(pattern: &str, mut func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_prepend_module_to_snapshot(false);
    settings.bind(|| {
        insta::_macro_support::glob_exec(&fixtures(), pattern, |path| {
            let content = read_to_string(path).unwrap();
            func(&content)
        });
    });
}
<commit_msg>docs(Tests): Details on snapshot_content function<commit_after>///! Helper functions for tests
use std::{fs::read_to_string, path::PathBuf};

/// Get the path of the home directory of this repository
pub fn home() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .to_path_buf()
}

/// Get the path of the `fixtures` directory
pub fn fixtures() -> PathBuf {
    home().join("fixtures")
}

/// Generate snapshots from the string content of fixtures matching
/// a glob pattern.
///
/// # Arguments
///
/// - `pattern`: glob pattern _within_ the fixtures folder
/// - `func`: the test function to run on the string content of each
///           file matching the `pattern`.
///
/// `insta`'s `glob` macro seems to have difficulties with our Rust module
/// layout (workspaces and nested modules). This function deals with that
/// by making the pattern relative to the fixtures and adding some other
/// conveniences.
pub fn snapshot_content<F: FnMut(&str)>(pattern: &str, mut func: F) {
    let mut settings = insta::Settings::clone_current();
    settings.set_prepend_module_to_snapshot(false);
    settings.bind(|| {
        insta::_macro_support::glob_exec(&fixtures(), pattern, |path| {
            let content = read_to_string(path).unwrap();
            func(&content)
        });
    });
}
<|endoftext|>


<commit_before>extern crate actix;
extern crate actix_http;
extern crate actix_net;
extern crate actix_web;
extern crate futures;

use std::thread;

use actix::System;
use actix_net::server::Server;
use actix_web::{client, test};
use futures::future;

use actix_http::server::KeepAlive;
use actix_http::{h1, Error, HttpResponse, ServiceConfig};

#[test]
fn test_h1_v2() {
    let addr = test::TestServer::unused_addr();
    thread::spawn(move || {
        Server::new()
            .bind("test", addr, move || {
                let settings = ServiceConfig::build()
                    .keep_alive(KeepAlive::Disabled)
                    .client_timeout(1000)
                    .client_shutdown(1000)
                    .server_hostname("localhost")
                    .server_address(addr)
                    .finish();

                h1::H1Service::new(settings, |req| {
                    println!("REQ: {:?}", req);
                    future::ok::<_, Error>(HttpResponse::Ok().finish())
                })
            }).unwrap()
            .run();
    });

    let mut sys = System::new("test");
    {
        let req = client::ClientRequest::get(format!("http://{}/", addr).as_str())
            .finish()
            .unwrap();
        let response = sys.block_on(req.send()).unwrap();
        assert!(response.status().is_success());
    }
}
<commit_msg>Update test_h1v2.rs<commit_after>extern crate actix;
extern crate actix_http;
extern crate actix_net;
extern crate actix_web;
extern crate futures;

use std::thread;

use actix::System;
use actix_net::server::Server;
use actix_web::{client, test};
use futures::future;

use actix_http::server::KeepAlive;
use actix_http::{h1, Error, HttpResponse, ServiceConfig};

#[test]
fn test_h1_v2() {
    let addr = test::TestServer::unused_addr();
    thread::spawn(move || {
        Server::new()
            .bind("test", addr, move || {
                let settings = ServiceConfig::build()
                    .keep_alive(KeepAlive::Disabled)
                    .client_timeout(1000)
                    .client_disconnect(1000)
                    .server_hostname("localhost")
                    .server_address(addr)
                    .finish();

                h1::H1Service::new(settings, |req| {
                    println!("REQ: {:?}", req);
                    future::ok::<_, Error>(HttpResponse::Ok().finish())
                })
            }).unwrap()
            .run();
    });

    let mut sys = System::new("test");
    {
        let req = client::ClientRequest::get(format!("http://{}/", addr).as_str())
            .finish()
            .unwrap();
        let response = sys.block_on(req.send()).unwrap();
        assert!(response.status().is_success());
    }
}
<|endoftext|>