<commit_before>mod ScInternal {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]
    include!(concat!("bindings.rs"));
}

macro_rules! check {
    ($check:expr) => {{
        let result = $check;
        if ScInternalResult::Success != result {
            return match result {
                _ => Err(ErrorCode::Unhandled)
            }
        }
    }}
}

pub mod compile {
    use ScInternal::root::*;
    use std::ptr;
    use std::ffi::CStr;
    use std::os::raw::c_void;

    #[derive(Debug)]
    pub enum ErrorCode {
        Unhandled = 1,
    }

    #[derive(Debug, Clone)]
    pub struct SpirvModule<'a> {
        ir: &'a [u32],
    }

    impl<'a> SpirvModule<'a> {
        pub fn new(ir: &[u32]) -> SpirvModule {
            SpirvModule { ir }
        }
    }

    pub struct ParsedSpirvModule {
        // TODO: Currently parsing and compilation must occur with the same compiler instance
        // (i.e. as opposed to splitting the parser/compiler which would be the ideal)
        // So temporarily we create the compiler instance during parse and reuse it during compilation
        // See https://github.com/KhronosGroup/SPIRV-Cross/issues/287
        internal_compiler: *mut c_void,
        internal_delete_compiler: fn(*mut c_void),
    }

    impl Drop for ParsedSpirvModule {
        fn drop(&mut self) {
            (self.internal_delete_compiler)(self.internal_compiler);
        }
    }

    #[derive(Debug, Clone)]
    pub struct SpirvParseOptions;

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

    #[derive(Debug, Clone)]
    pub struct HlslCompileOptions;

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

    fn internal_delete_compiler_hlsl(internal_compiler: *mut c_void) {
        unsafe {
            if ScInternalResult::Success != sc_internal_compiler_hlsl_delete(internal_compiler) {
                panic!("Cannot delete compiler");
            }
        }
    }

    #[derive(Debug, Clone)]
    pub struct HlslCompiler;

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

        pub fn parse(
            &self,
            module: &SpirvModule,
            _options: &SpirvParseOptions,
        ) -> Result<ParsedSpirvModule, ErrorCode> {
            let ptr = module.ir.as_ptr() as *const u32;
            let mut compiler = ptr::null_mut();
            unsafe {
                check!(sc_internal_compiler_hlsl_new(
                    &mut compiler,
                    ptr,
                    module.ir.len() as usize
                ));

                Ok(ParsedSpirvModule {
                    internal_compiler: compiler,
                    internal_delete_compiler: internal_delete_compiler_hlsl,
                })
            }
        }

        pub fn compile(
            &self,
            module: &ParsedSpirvModule,
            _options: &HlslCompileOptions,
        ) -> Result<String, ErrorCode> {
            let compiler = module.internal_compiler;
            unsafe {
                let mut hlsl_ptr = ptr::null_mut();
                check!(sc_internal_compiler_hlsl_compile(compiler, &mut hlsl_ptr));
                let hlsl = match CStr::from_ptr(hlsl_ptr).to_owned().into_string() {
                    Err(_) => return Err(ErrorCode::Unhandled),
                    Ok(v) => v,
                };
                check!(sc_internal_deallocate_string(hlsl_ptr));
                Ok(hlsl)
            }
        }
    }
}
<commit_msg>Format<commit_after>mod ScInternal {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]
    include!(concat!("bindings.rs"));
}

macro_rules! check {
    ($check:expr) => {{
        let result = $check;
        if ScInternalResult::Success != result {
            return match result {
                _ => Err(ErrorCode::Unhandled)
            }
        }
    }}
}

pub mod compile {
    use ScInternal::root::*;
    use std::ptr;
    use std::ffi::CStr;
    use std::os::raw::c_void;

    #[derive(Debug)]
    pub enum ErrorCode {
        Unhandled = 1,
    }

    #[derive(Debug, Clone)]
    pub struct SpirvModule<'a> {
        ir: &'a [u32],
    }

    impl<'a> SpirvModule<'a> {
        pub fn new(ir: &[u32]) -> SpirvModule {
            SpirvModule { ir }
        }
    }

    pub struct ParsedSpirvModule {
        // TODO: Currently parsing and compilation must occur with the same compiler instance
        // (i.e. as opposed to splitting the parser/compiler which would be the ideal)
        // So temporarily we create the compiler instance during parse
        // and reuse it during compilation
        // see https://github.com/KhronosGroup/SPIRV-Cross/issues/287
        internal_compiler: *mut c_void,
        internal_delete_compiler: fn(*mut c_void),
    }

    impl Drop for ParsedSpirvModule {
        fn drop(&mut self) {
            (self.internal_delete_compiler)(self.internal_compiler);
        }
    }

    #[derive(Debug, Clone)]
    pub struct SpirvParseOptions;

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

    #[derive(Debug, Clone)]
    pub struct HlslCompileOptions;

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

    fn internal_delete_compiler_hlsl(internal_compiler: *mut c_void) {
        unsafe {
            if ScInternalResult::Success != sc_internal_compiler_hlsl_delete(internal_compiler) {
                panic!("Cannot delete compiler");
            }
        }
    }

    #[derive(Debug, Clone)]
    pub struct HlslCompiler;

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

        pub fn parse(
            &self,
            module: &SpirvModule,
            _options: &SpirvParseOptions,
        ) -> Result<ParsedSpirvModule, ErrorCode> {
            let ptr = module.ir.as_ptr() as *const u32;
            let mut compiler = ptr::null_mut();
            unsafe {
                check!(sc_internal_compiler_hlsl_new(
                    &mut compiler,
                    ptr,
                    module.ir.len() as usize,
                ));

                Ok(ParsedSpirvModule {
                    internal_compiler: compiler,
                    internal_delete_compiler: internal_delete_compiler_hlsl,
                })
            }
        }

        pub fn compile(
            &self,
            module: &ParsedSpirvModule,
            _options: &HlslCompileOptions,
        ) -> Result<String, ErrorCode> {
            let compiler = module.internal_compiler;
            unsafe {
                let mut hlsl_ptr = ptr::null_mut();
                check!(sc_internal_compiler_hlsl_compile(compiler, &mut hlsl_ptr));
                let hlsl = match CStr::from_ptr(hlsl_ptr).to_owned().into_string() {
                    Err(_) => return Err(ErrorCode::Unhandled),
                    Ok(v) => v,
                };
                check!(sc_internal_deallocate_string(hlsl_ptr));
                Ok(hlsl)
            }
        }
    }
}
<|endoftext|>


<commit_before>#[deriving(PartialEq, Show)]
pub enum Card {
    JokerA,
    JokerB,
    Clubs(int),
    Diamonds(int),
    Hearts(int),
    Spades(int),
}

impl Card {
    pub fn count_cut_index(&self) -> int {
        match *self {
            Clubs(i) => i,
            Diamonds(i) => i + 13,
            Hearts(i) => i + 26,
            Spades(i) => i + 39,
            JokerA => 53,
            JokerB => 53,
        }
    }

    pub fn is_joker(&self) -> bool {
        match *self {
            JokerA => true,
            JokerB => true,
            _ => false,
        }
    }

    pub fn is_red(&self) -> bool {
        match *self {
            Diamonds(_) => true,
            Hearts(_) => true,
            _ => false,
        }
    }

}

#[test]
fn test_count_cut_index() {
    let a = JokerA;
    assert_eq!(a.count_cut_index(), 53);
    let b = Hearts(4);
    assert_eq!(b.count_cut_index(), 30);
}
<commit_msg>Delete card.rs<commit_after><|endoftext|>


<commit_before>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::device::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                if let Some(cap) = capability_name(cap) {
                    output.push_str(&format!(r#"
                        if !device.enabled_features().{cap} {{
                            panic!("capability not supported")  // FIXME: error
                            //return Err(CapabilityNotSupported);
                        }}"#, cap = cap));
                }
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data).unwrap()    // FIXME: try!()
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

impl From<IoError> for Error {
    #[inline]
    fn from(err: IoError) -> Error {
        Error::IoError(err)
    }
}

impl From<ParseError> for Error {
    #[inline]
    fn from(err: ParseError) -> Error {
        Error::ParseError(err)
    }
}

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let (ty, f_name) = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            let mut input_types = Vec::new();

            // TODO: sort types by location

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassInput, .. }
                                    if &result_id == interface =>
                        {
                            input_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            let t = format!("::vulkano::shader::VertexShaderEntryPoint<({input})>",
                            input = input_types.join(", ") + ",");
            (t, "vertex_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            (format!("::vulkano::shader::TessControlShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            (format!("::vulkano::shader::TessEvaluationShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            (format!("::vulkano::shader::GeometryShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            let t = format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                            output = output_types.join(", ") + ",");
            (t, "fragment_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            (format!("::vulkano::shader::ComputeShaderEntryPoint"), "compute_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];
            self.shader.{f_name}(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _))
        }}
    }}
            "#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
                encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
                                         .collect::<Vec<String>>().join(", "),
                f_name = f_name)
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = 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);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

/// Returns the name of the Vulkan something that corresponds to an `OpCapability`.
///
/// Returns `None` if irrelevant.
// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> Option<&'static str> {
    match *cap {
        enums::Capability::CapabilityMatrix => Some("Matrix"),
        enums::Capability::CapabilityShader => None,
        enums::Capability::CapabilityGeometry => Some("Geometry"),
        enums::Capability::CapabilityTessellation => Some("Tessellation"),
        enums::Capability::CapabilityAddresses => Some("Addresses"),
        enums::Capability::CapabilityLinkage => Some("Linkage"),
        enums::Capability::CapabilityKernel => Some("Kernel"),
        enums::Capability::CapabilityVector16 => Some("Vector16"),
        enums::Capability::CapabilityFloat16Buffer => Some("Float16Buffer"),
        enums::Capability::CapabilityFloat16 => Some("Float16"),
        enums::Capability::CapabilityFloat64 => Some("Float64"),
        enums::Capability::CapabilityInt64 => Some("Int64"),
        enums::Capability::CapabilityInt64Atomics => Some("Int64Atomics"),
        enums::Capability::CapabilityImageBasic => Some("ImageBasic"),
        enums::Capability::CapabilityImageReadWrite => Some("ImageReadWrite"),
        enums::Capability::CapabilityImageMipmap => Some("ImageMipmap"),
        enums::Capability::CapabilityPipes => Some("Pipes"),
        enums::Capability::CapabilityGroups => Some("Groups"),
        enums::Capability::CapabilityDeviceEnqueue => Some("DeviceEnqueue"),
        enums::Capability::CapabilityLiteralSampler => Some("LiteralSampler"),
        enums::Capability::CapabilityAtomicStorage => Some("AtomicStorage"),
        enums::Capability::CapabilityInt16 => Some("Int16"),
        enums::Capability::CapabilityTessellationPointSize => Some("TessellationPointSize"),
        enums::Capability::CapabilityGeometryPointSize => Some("GeometryPointSize"),
        enums::Capability::CapabilityImageGatherExtended => Some("ImageGatherExtended"),
        enums::Capability::CapabilityStorageImageMultisample => Some("StorageImageMultisample"),
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => Some("UniformBufferArrayDynamicIndexing"),
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => Some("SampledImageArrayDynamicIndexing"),
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => Some("StorageBufferArrayDynamicIndexing"),
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => Some("StorageImageArrayDynamicIndexing"),
        enums::Capability::CapabilityClipDistance => Some("ClipDistance"),
        enums::Capability::CapabilityCullDistance => Some("CullDistance"),
        enums::Capability::CapabilityImageCubeArray => Some("ImageCubeArray"),
        enums::Capability::CapabilitySampleRateShading => Some("SampleRateShading"),
        enums::Capability::CapabilityImageRect => Some("ImageRect"),
        enums::Capability::CapabilitySampledRect => Some("SampledRect"),
        enums::Capability::CapabilityGenericPointer => Some("GenericPointer"),
        enums::Capability::CapabilityInt8 => Some("Int8"),
        enums::Capability::CapabilityInputAttachment => Some("InputAttachment"),
        enums::Capability::CapabilitySparseResidency => Some("SparseResidency"),
        enums::Capability::CapabilityMinLod => Some("MinLod"),
        enums::Capability::CapabilitySampled1D => Some("Sampled1D"),
        enums::Capability::CapabilityImage1D => Some("Image1D"),
        enums::Capability::CapabilitySampledCubeArray => Some("SampledCubeArray"),
        enums::Capability::CapabilitySampledBuffer => Some("SampledBuffer"),
        enums::Capability::CapabilityImageBuffer => Some("ImageBuffer"),
        enums::Capability::CapabilityImageMSArray => Some("ImageMSArray"),
        enums::Capability::CapabilityStorageImageExtendedFormats => Some("StorageImageExtendedFormats"),
        enums::Capability::CapabilityImageQuery => Some("ImageQuery"),
        enums::Capability::CapabilityDerivativeControl => Some("DerivativeControl"),
        enums::Capability::CapabilityInterpolationFunction => Some("InterpolationFunction"),
        enums::Capability::CapabilityTransformFeedback => Some("TransformFeedback"),
        enums::Capability::CapabilityGeometryStreams => Some("GeometryStreams"),
        enums::Capability::CapabilityStorageImageReadWithoutFormat => Some("StorageImageReadWithoutFormat"),
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => Some("StorageImageWriteWithoutFormat"),
    }
}
<commit_msg>Generated structs public again (oops)<commit_after>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
pub struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::device::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                if let Some(cap) = capability_name(cap) {
                    output.push_str(&format!(r#"
                        if !device.enabled_features().{cap} {{
                            panic!("capability not supported")  // FIXME: error
                            //return Err(CapabilityNotSupported);
                        }}"#, cap = cap));
                }
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data).unwrap()    // FIXME: try!()
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

impl From<IoError> for Error {
    #[inline]
    fn from(err: IoError) -> Error {
        Error::IoError(err)
    }
}

impl From<ParseError> for Error {
    #[inline]
    fn from(err: ParseError) -> Error {
        Error::ParseError(err)
    }
}

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let (ty, f_name) = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            let mut input_types = Vec::new();

            // TODO: sort types by location

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassInput, .. }
                                    if &result_id == interface =>
                        {
                            input_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            let t = format!("::vulkano::shader::VertexShaderEntryPoint<({input})>",
                            input = input_types.join(", ") + ",");
            (t, "vertex_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            (format!("::vulkano::shader::TessControlShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            (format!("::vulkano::shader::TessEvaluationShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            (format!("::vulkano::shader::GeometryShaderEntryPoint"), "")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            let t = format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                            output = output_types.join(", ") + ",");
            (t, "fragment_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            (format!("::vulkano::shader::ComputeShaderEntryPoint"), "compute_shader_entry_point")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];
            self.shader.{f_name}(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _))
        }}
    }}
            "#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
                encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
                                         .collect::<Vec<String>>().join(", "),
                f_name = f_name)
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = 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);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

/// Returns the name of the Vulkan something that corresponds to an `OpCapability`.
///
/// Returns `None` if irrelevant.
// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> Option<&'static str> {
    match *cap {
        enums::Capability::CapabilityMatrix => Some("Matrix"),
        enums::Capability::CapabilityShader => None,
        enums::Capability::CapabilityGeometry => Some("Geometry"),
        enums::Capability::CapabilityTessellation => Some("Tessellation"),
        enums::Capability::CapabilityAddresses => Some("Addresses"),
        enums::Capability::CapabilityLinkage => Some("Linkage"),
        enums::Capability::CapabilityKernel => Some("Kernel"),
        enums::Capability::CapabilityVector16 => Some("Vector16"),
        enums::Capability::CapabilityFloat16Buffer => Some("Float16Buffer"),
        enums::Capability::CapabilityFloat16 => Some("Float16"),
        enums::Capability::CapabilityFloat64 => Some("Float64"),
        enums::Capability::CapabilityInt64 => Some("Int64"),
        enums::Capability::CapabilityInt64Atomics => Some("Int64Atomics"),
        enums::Capability::CapabilityImageBasic => Some("ImageBasic"),
        enums::Capability::CapabilityImageReadWrite => Some("ImageReadWrite"),
        enums::Capability::CapabilityImageMipmap => Some("ImageMipmap"),
        enums::Capability::CapabilityPipes => Some("Pipes"),
        enums::Capability::CapabilityGroups => Some("Groups"),
        enums::Capability::CapabilityDeviceEnqueue => Some("DeviceEnqueue"),
        enums::Capability::CapabilityLiteralSampler => Some("LiteralSampler"),
        enums::Capability::CapabilityAtomicStorage => Some("AtomicStorage"),
        enums::Capability::CapabilityInt16 => Some("Int16"),
        enums::Capability::CapabilityTessellationPointSize => Some("TessellationPointSize"),
        enums::Capability::CapabilityGeometryPointSize => Some("GeometryPointSize"),
        enums::Capability::CapabilityImageGatherExtended => Some("ImageGatherExtended"),
        enums::Capability::CapabilityStorageImageMultisample => Some("StorageImageMultisample"),
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => Some("UniformBufferArrayDynamicIndexing"),
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => Some("SampledImageArrayDynamicIndexing"),
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => Some("StorageBufferArrayDynamicIndexing"),
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => Some("StorageImageArrayDynamicIndexing"),
        enums::Capability::CapabilityClipDistance => Some("ClipDistance"),
        enums::Capability::CapabilityCullDistance => Some("CullDistance"),
        enums::Capability::CapabilityImageCubeArray => Some("ImageCubeArray"),
        enums::Capability::CapabilitySampleRateShading => Some("SampleRateShading"),
        enums::Capability::CapabilityImageRect => Some("ImageRect"),
        enums::Capability::CapabilitySampledRect => Some("SampledRect"),
        enums::Capability::CapabilityGenericPointer => Some("GenericPointer"),
        enums::Capability::CapabilityInt8 => Some("Int8"),
        enums::Capability::CapabilityInputAttachment => Some("InputAttachment"),
        enums::Capability::CapabilitySparseResidency => Some("SparseResidency"),
        enums::Capability::CapabilityMinLod => Some("MinLod"),
        enums::Capability::CapabilitySampled1D => Some("Sampled1D"),
        enums::Capability::CapabilityImage1D => Some("Image1D"),
        enums::Capability::CapabilitySampledCubeArray => Some("SampledCubeArray"),
        enums::Capability::CapabilitySampledBuffer => Some("SampledBuffer"),
        enums::Capability::CapabilityImageBuffer => Some("ImageBuffer"),
        enums::Capability::CapabilityImageMSArray => Some("ImageMSArray"),
        enums::Capability::CapabilityStorageImageExtendedFormats => Some("StorageImageExtendedFormats"),
        enums::Capability::CapabilityImageQuery => Some("ImageQuery"),
        enums::Capability::CapabilityDerivativeControl => Some("DerivativeControl"),
        enums::Capability::CapabilityInterpolationFunction => Some("InterpolationFunction"),
        enums::Capability::CapabilityTransformFeedback => Some("TransformFeedback"),
        enums::Capability::CapabilityGeometryStreams => Some("GeometryStreams"),
        enums::Capability::CapabilityStorageImageReadWithoutFormat => Some("StorageImageReadWithoutFormat"),
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => Some("StorageImageWriteWithoutFormat"),
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::num::{Int, UnsignedInt, NumCast, cast, Float};
use std::collections;
use std::slice;
use std;

use alphabets::{Alphabet, RankTransform};

struct QGrams<'a, Q: UnsignedInt + NumCast> {
    text: slice::Iter<'a, u8>,
    qgram: Q,
    bits: usize,
    mask: Q,
    ranks: RankTransform,
}

impl<'a, Q: UnsignedInt + NumCast> QGrams<'a, Q> {
    pub fn new(q: usize, text: &'a [u8], alphabet: &Alphabet) -> Self {
        let ranks = RankTransform::new(alphabet);
        let mut qgrams = QGrams {
            text: text.iter(),
            qgram: cast(0).unwrap(),
            ranks: ranks,
            bits: (alphabet.len() as f32).log2().ceil() as usize,
            mask: cast((1 << q) - 1).unwrap(),
        };
        for _ in 0..q-1 {
            qgrams.next();
        }

        qgrams
    }

    fn qgram_push(&mut self, a: u8) {
        self.qgram = self.qgram << self.bits;
        self.qgram = (self.qgram | cast(a).unwrap()) & self.mask;
    }
}

impl<'a, Q: UnsignedInt + NumCast> Iterator for QGrams<'a, Q> {
    type Item = Q;

    fn next(&mut self) -> Option<Q> {
        match self.text.next() {
            Some(a) => {
                let b = self.ranks.get(*a);
                self.qgram_push(b);
                Some(self.qgram)
            },
            None    => None
        }
    }
}

pub struct QGramIndex<'a> {
    q: usize,
    alphabet: &'a Alphabet,
    address: Vec<usize>,
    pos: Vec<usize>,
}

impl<'a> QGramIndex<'a> {
    pub fn new(q: usize, text: &[u8], alphabet: &'a Alphabet) -> Self {
        QGramIndex::with_max_count(q, text, alphabet, std::usize::MAX)
    }

    pub fn with_max_count(q: usize, text: &[u8], alphabet: &'a Alphabet, max_count: usize) -> Self {
        let qgram_count = alphabet.len().pow(q as u32);
        let mut address = vec![0; qgram_count + 1];
        let mut pos = vec![0; text.len()];

        for qgram in QGrams::<u32>::new(q, text, alphabet) {
            address[qgram as usize] += 1;
        }

        for g in 1..address.len() {
            if address[g] > max_count {
                // mask qgram
                address[g] = 0;
            }
        }

        for i in 1..address.len() {
            address[i] += address[i - 1];
        }

        {
            let mut offset = vec![0; qgram_count];
            for (i, qgram) in QGrams::<u32>::new(q, text, alphabet).enumerate() {
                let a = address[qgram as usize];
                if address[qgram as usize + 1] - a != 0 {
                    // if not masked, insert positions
                    pos[a + offset[qgram as usize]] = i;
                    offset[qgram as usize] += 1;
                }
            }
        }

        QGramIndex { q: q, alphabet: alphabet, address: address, pos: pos }
    }

    pub fn matches(&self, qgram: u32) -> &[usize] {
        &self.pos[self.address[qgram as usize]..self.address[qgram as usize + 1]]
    }

    pub fn diagonals(&self, pattern: &[u8]) -> Vec<Diagonal> {
        let mut diagonals = collections::HashMap::new();
        for (i, qgram) in QGrams::<u32>::new(self.q, pattern, self.alphabet).enumerate() {
            for p in self.matches(qgram) {
                let diagonal = p - i;
                if diagonals.contains_key(&diagonal) {
                    diagonals.insert(diagonal, 1);
                }
                else {
                    *diagonals.get_mut(&diagonal).unwrap() += 1;
                }
            }
        }
        diagonals.into_iter().map(|(diagonal, count)| Diagonal { pos: diagonal, count: count }).collect()
    }

    pub fn exact_matches(&self, pattern: &[u8]) -> Vec<ExactMatch> {
        let mut diagonals: collections::HashMap<usize, ExactMatch> = collections::HashMap::new();
        let mut intervals = Vec::new();
        for (i, qgram) in QGrams::<u32>::new(self.q, pattern, self.alphabet).enumerate() {
            for &p in self.matches(qgram) {
                let diagonal = p - i;
                if !diagonals.contains_key(&diagonal) {
                    // nothing yet, start new match
                    diagonals.insert(diagonal, ExactMatch {
                            pattern_start: i,
                            pattern_stop: i + self.q,
                            text_start: p,
                            text_stop: p + self.q
                    });
                }
                else {
                    let interval = diagonals.get_mut(&diagonal).unwrap();
                    if interval.pattern_stop == i {
                        // extend exact match
                        interval.pattern_stop = i + self.q;
                        interval.text_stop = p + self.q;
                    }
                    else {
                        // report previous match
                        intervals.push(*interval);
                        // mismatch or indel, start new match
                        interval.pattern_start = i;
                        interval.pattern_stop = i + self.q;
                        interval.text_start = p;
                        interval.text_stop = p + self.q;
                    }

                }
            }
        }
        // report remaining intervals
        for (_, interval) in diagonals.into_iter() {
            intervals.push(interval);
        }
        intervals
    }
}

pub struct Diagonal {
    pub pos: usize,
    pub count: usize,
}

#[derive(Copy)]
pub struct ExactMatch {
    pub pattern_start: usize,
    pub pattern_stop: usize,
    pub text_start: usize,
    pub text_stop: usize,
}
<commit_msg>Explicit clone instead of copy.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::num::{Int, UnsignedInt, NumCast, cast, Float};
use std::collections;
use std::slice;
use std;

use alphabets::{Alphabet, RankTransform};

struct QGrams<'a, Q: UnsignedInt + NumCast> {
    text: slice::Iter<'a, u8>,
    qgram: Q,
    bits: usize,
    mask: Q,
    ranks: RankTransform,
}

impl<'a, Q: UnsignedInt + NumCast> QGrams<'a, Q> {
    pub fn new(q: usize, text: &'a [u8], alphabet: &Alphabet) -> Self {
        let ranks = RankTransform::new(alphabet);
        let mut qgrams = QGrams {
            text: text.iter(),
            qgram: cast(0).unwrap(),
            ranks: ranks,
            bits: (alphabet.len() as f32).log2().ceil() as usize,
            mask: cast((1 << q) - 1).unwrap(),
        };
        for _ in 0..q-1 {
            qgrams.next();
        }

        qgrams
    }

    fn qgram_push(&mut self, a: u8) {
        self.qgram = self.qgram << self.bits;
        self.qgram = (self.qgram | cast(a).unwrap()) & self.mask;
    }
}

impl<'a, Q: UnsignedInt + NumCast> Iterator for QGrams<'a, Q> {
    type Item = Q;

    fn next(&mut self) -> Option<Q> {
        match self.text.next() {
            Some(a) => {
                let b = self.ranks.get(*a);
                self.qgram_push(b);
                Some(self.qgram)
            },
            None    => None
        }
    }
}

pub struct QGramIndex<'a> {
    q: usize,
    alphabet: &'a Alphabet,
    address: Vec<usize>,
    pos: Vec<usize>,
}

impl<'a> QGramIndex<'a> {
    pub fn new(q: usize, text: &[u8], alphabet: &'a Alphabet) -> Self {
        QGramIndex::with_max_count(q, text, alphabet, std::usize::MAX)
    }

    pub fn with_max_count(q: usize, text: &[u8], alphabet: &'a Alphabet, max_count: usize) -> Self {
        let qgram_count = alphabet.len().pow(q as u32);
        let mut address = vec![0; qgram_count + 1];
        let mut pos = vec![0; text.len()];

        for qgram in QGrams::<u32>::new(q, text, alphabet) {
            address[qgram as usize] += 1;
        }

        for g in 1..address.len() {
            if address[g] > max_count {
                // mask qgram
                address[g] = 0;
            }
        }

        for i in 1..address.len() {
            address[i] += address[i - 1];
        }

        {
            let mut offset = vec![0; qgram_count];
            for (i, qgram) in QGrams::<u32>::new(q, text, alphabet).enumerate() {
                let a = address[qgram as usize];
                if address[qgram as usize + 1] - a != 0 {
                    // if not masked, insert positions
                    pos[a + offset[qgram as usize]] = i;
                    offset[qgram as usize] += 1;
                }
            }
        }

        QGramIndex { q: q, alphabet: alphabet, address: address, pos: pos }
    }

    pub fn matches(&self, qgram: u32) -> &[usize] {
        &self.pos[self.address[qgram as usize]..self.address[qgram as usize + 1]]
    }

    pub fn diagonals(&self, pattern: &[u8]) -> Vec<Diagonal> {
        let mut diagonals = collections::HashMap::new();
        for (i, qgram) in QGrams::<u32>::new(self.q, pattern, self.alphabet).enumerate() {
            for p in self.matches(qgram) {
                let diagonal = p - i;
                if diagonals.contains_key(&diagonal) {
                    diagonals.insert(diagonal, 1);
                }
                else {
                    *diagonals.get_mut(&diagonal).unwrap() += 1;
                }
            }
        }
        diagonals.into_iter().map(|(diagonal, count)| Diagonal { pos: diagonal, count: count }).collect()
    }

    pub fn exact_matches(&self, pattern: &[u8]) -> Vec<ExactMatch> {
        let mut diagonals: collections::HashMap<usize, ExactMatch> = collections::HashMap::new();
        let mut intervals = Vec::new();
        for (i, qgram) in QGrams::<u32>::new(self.q, pattern, self.alphabet).enumerate() {
            for &p in self.matches(qgram) {
                let diagonal = p - i;
                if !diagonals.contains_key(&diagonal) {
                    // nothing yet, start new match
                    diagonals.insert(diagonal, ExactMatch {
                            pattern_start: i,
                            pattern_stop: i + self.q,
                            text_start: p,
                            text_stop: p + self.q
                    });
                }
                else {
                    let interval = diagonals.get_mut(&diagonal).unwrap();
                    if interval.pattern_stop == i {
                        // extend exact match
                        interval.pattern_stop = i + self.q;
                        interval.text_stop = p + self.q;
                    }
                    else {
                        // report previous match
                        intervals.push(interval.clone());
                        // mismatch or indel, start new match
                        interval.pattern_start = i;
                        interval.pattern_stop = i + self.q;
                        interval.text_start = p;
                        interval.text_stop = p + self.q;
                    }

                }
            }
        }
        // report remaining intervals
        for (_, interval) in diagonals.into_iter() {
            intervals.push(interval);
        }
        intervals
    }
}

pub struct Diagonal {
    pub pos: usize,
    pub count: usize,
}

#[derive(Clone)]
pub struct ExactMatch {
    pub pattern_start: usize,
    pub pattern_stop: usize,
    pub text_start: usize,
    pub text_stop: usize,
}
<|endoftext|>


<commit_before>#![cfg(feature = "longest-match-cache")]

//! The cache that speeds up ZopfliFindLongestMatch of lz77.c.

use std::iter;

use util::CACHE_LENGTH;

/// Cache used by ZopfliFindLongestMatch to remember previously found length/dist values.
/// This is needed because the squeeze runs will ask these values multiple times for the
/// same position. Uses large amounts of memory, since it has to remember the distance
/// belonging to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct LongestMatchCache {
    pub length: Vec<u16>,
    pub dist: Vec<u16>,
    sublen: Vec<u8>,
}

impl LongestMatchCache {
    /// Initializes the ZopfliLongestMatchCache.
    pub fn new(blocksize: usize) -> LongestMatchCache {
        // Rather large amount of memory.
        let sublen_size = CACHE_LENGTH * 3 * blocksize;

        // length > 0 and dist 0 is invalid combination, which indicates on purpose
        // that this cache value is not filled in yet.
        LongestMatchCache {
            length: iter::repeat(1).take(blocksize).collect(),
            dist: iter::repeat(0).take(blocksize).collect(),
            sublen: iter::repeat(0).take(sublen_size).collect(),
        }
    }
}

/// Stores sublen array in the cache.
pub unsafe fn sublen_to_cache(sublen: &[u16; 259],
                              pos: usize,
                              length: usize,
                              lmc: &mut LongestMatchCache) {
    if CACHE_LENGTH == 0 {
        return;
    }

    let cache: *mut u8 = &mut lmc.sublen[CACHE_LENGTH * pos * 3];
    if length < 3 {
        return;
    }

    let mut j: usize = 0;
    let mut bestlength: u32 = 0;
    for i in 3..length + 1 {
        if i == length || sublen[i] != sublen[i + 1] {
            *cache.offset(j as isize * 3) = (i - 3) as u8;
            *cache.offset(j as isize * 3 + 1) = (sublen[i] % 256) as u8;
            *cache.offset(j as isize * 3 + 2) = ((sublen[i] >> 8) % 256) as u8;
            bestlength = i as u32;
            j += 1;
            if j >= CACHE_LENGTH {
                break;
            }
        }
    }

    if j < CACHE_LENGTH {
        assert_eq!(bestlength as usize, length);
        *cache.offset((CACHE_LENGTH as isize - 1) * 3) = (bestlength - 3) as u8;
    } else {
        assert!(bestlength as usize <= length,
                "{} <= {}",
                bestlength,
                length);
    }
    assert_eq!(bestlength, max_cached_sublen(lmc, pos, length));
}

/// Extracts sublen array from the cache.
pub unsafe fn cache_to_sublen(lmc: *mut LongestMatchCache,
                              pos: usize,
                              length: usize,
                              sublen: &mut [u16; 259]) {
    if CACHE_LENGTH == 0 {
        return;
    }

    if length < 3 {
        return;
    }
    let cache: *mut u8 = &mut (*lmc).sublen[CACHE_LENGTH * pos * 3];
    let maxlength: u32 = max_cached_sublen(lmc, pos, length);
    let mut prevlength: u32 = 0;
    for j in 0..CACHE_LENGTH {
        let length: u32 = *cache.offset(j as isize * 3) as u32 + 3;
        let dist: u32 = *cache.offset(j as isize * 3 + 1) as u32 +
                        256 * *cache.offset(j as isize * 3 + 2) as u32;
        for i in prevlength..length + 1 {
            sublen[i as usize] = dist as u16;
        }
        if length == maxlength {
            break;
        }
        prevlength = length + 1;
    }
}

/// Returns the length up to which could be stored in the cache.
pub unsafe fn max_cached_sublen(lmc: *const LongestMatchCache, pos: usize, _length: usize) -> u32 {
    if CACHE_LENGTH == 0 {
        return 0;
    }
    let cache: *const u8 = &(*lmc).sublen[CACHE_LENGTH * pos * 3];
    if *cache.offset(1) == 0 && *cache.offset(2) == 0 {
        // No sublen cached.
        return 0;
    }
    *cache.offset(((CACHE_LENGTH - 1) * 3) as isize) as u32 + 3
}
<commit_msg>Remove unsafe code from cache.rs<commit_after>#![cfg(feature = "longest-match-cache")]

//! The cache that speeds up ZopfliFindLongestMatch of lz77.c.

use std::iter;

use util::CACHE_LENGTH;

/// Cache used by ZopfliFindLongestMatch to remember previously found length/dist values.
/// This is needed because the squeeze runs will ask these values multiple times for the
/// same position. Uses large amounts of memory, since it has to remember the distance
/// belonging to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct LongestMatchCache {
    pub length: Vec<u16>,
    pub dist: Vec<u16>,
    sublen: Vec<[u8; CACHE_LENGTH * 3]>,
}

impl LongestMatchCache {
    /// Initializes the ZopfliLongestMatchCache.
    pub fn new(blocksize: usize) -> LongestMatchCache {
        // length > 0 and dist 0 is invalid combination, which indicates on purpose
        // that this cache value is not filled in yet.
        LongestMatchCache {
            length: iter::repeat(1).take(blocksize).collect(),
            dist: iter::repeat(0).take(blocksize).collect(),
            // Rather large amount of memory.
            sublen: iter::repeat([0; CACHE_LENGTH * 3]).take(blocksize).collect(),
        }
    }
}

/// Stores sublen array in the cache.
pub fn sublen_to_cache(sublen: &[u16; 259],
                       pos: usize,
                       length: usize,
                       lmc: &mut LongestMatchCache) {
    if CACHE_LENGTH == 0 {
        return;
    }

    let mut bestlength: u32 = 0;
    {
        let cache: &mut [u8; CACHE_LENGTH * 3] = &mut lmc.sublen[pos];
        if length < 3 {
            return;
        }

        let mut j: usize = 0;
        for i in 3..length + 1 {
            if i == length || sublen[i] != sublen[i + 1] {
                cache[j * 3] = (i - 3) as u8;
                cache[j * 3 + 1] = (sublen[i] % 256) as u8;
                cache[j * 3 + 2] = ((sublen[i] >> 8) % 256) as u8;
                bestlength = i as u32;
                j += 1;
                if j >= CACHE_LENGTH {
                    break;
                }
            }
        }

        if j < CACHE_LENGTH {
            assert_eq!(bestlength as usize, length);
            cache[(CACHE_LENGTH - 1) * 3] = (bestlength - 3) as u8;
        } else {
            assert!(bestlength as usize <= length,
                    "{} <= {}",
                    bestlength,
                    length);
        }
    }
    assert_eq!(bestlength, max_cached_sublen(lmc, pos, length));
}

/// Extracts sublen array from the cache.
pub fn cache_to_sublen(lmc: &mut LongestMatchCache,
                       pos: usize,
                       length: usize,
                       sublen: &mut [u16; 259]) {
    if CACHE_LENGTH == 0 {
        return;
    }

    if length < 3 {
        return;
    }
    let maxlength: u32 = max_cached_sublen(lmc, pos, length);
    let cache: &mut [u8; CACHE_LENGTH * 3] = &mut (*lmc).sublen[pos];
    let mut prevlength: u32 = 0;
    for j in 0..CACHE_LENGTH {
        let length: u32 = cache[j * 3] as u32 + 3;
        let dist: u32 = cache[j * 3 + 1] as u32 + 256 * cache[j * 3 + 2] as u32;
        for i in prevlength..length + 1 {
            sublen[i as usize] = dist as u16;
        }
        if length == maxlength {
            break;
        }
        prevlength = length + 1;
    }
}

/// Returns the length up to which could be stored in the cache.
pub fn max_cached_sublen(lmc: &LongestMatchCache, pos: usize, _length: usize) -> u32 {
    if CACHE_LENGTH == 0 {
        return 0;
    }
    let cache: &[u8; CACHE_LENGTH * 3] = &lmc.sublen[pos];
    if cache[1] == 0 && cache[2] == 0 {
        // No sublen cached.
        return 0;
    }
    cache[(CACHE_LENGTH - 1) * 3] as u32 + 3
}
<|endoftext|>


<commit_before>use crate::config::*;
use crate::errors::RunError;
use cargo_metadata::{parse_messages, Message};
use std::env;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use walkdir::WalkDir;

static DOCTEST_FOLDER: &str = "target/doctests";

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TestBinary {
    path: PathBuf,
    ty: RunType,
}

impl TestBinary {
    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn run_type(&self) -> RunType {
        self.ty
    }
}

pub fn get_tests(config: &Config) -> Result<Vec<TestBinary>, RunError> {
    let mut result = vec![];
    let manifest = match config.manifest.as_path().to_str() {
        Some(s) => s,
        None => "Cargo.toml",
    };
    for ty in &config.run_types {
        let mut cmd = create_command(manifest, config, ty)
            .stdout(Stdio::piped())
            .spawn()
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if ty != &RunType::Doctests {
            for msg in parse_messages(cmd.stdout.take().unwrap()) {
                if let Ok(Message::CompilerArtifact(art)) = msg {
                    if let Some(path) = art.executable {
                        result.push(TestBinary { path, ty: *ty });
                    }
                }
            }
        } else {
            // Need to get the packages...
            let package_roots = config
                .get_packages()
                .iter()
                .filter_map(|x| x.manifest_path.parent())
                .map(|x| x.join(DOCTEST_FOLDER))
                .collect::<Vec<PathBuf>>();

            for dir in &package_roots {
                let walker = WalkDir::new(dir).into_iter();
                for dt in walker
                    .filter_map(|e| e.ok())
                    .filter(|e| match e.metadata() {
                        Ok(ref m) if m.is_file() && m.len() != 0 => true,
                        _ => false,
                    })
                {
                    result.push(TestBinary {
                        path: dt.path().to_path_buf(),
                        ty: *ty,
                    });
                }
            }
        }
        cmd.wait().map_err(|e| RunError::Cargo(e.to_string()))?;
    }
    Ok(result)
}

fn create_command(manifest_path: &str, config: &Config, ty: &RunType) -> Command {
    let mut test_cmd = Command::new("cargo");
    if *ty == RunType::Doctests {
        test_cmd.args(&["+nightly", "test"]);
    } else {
        if let Ok(toolchain) = env::var("RUSTUP_TOOLCHAIN") {
            if toolchain.starts_with("nightly") {
                test_cmd.arg("+nightly");
            } else if toolchain.starts_with("beta") {
                test_cmd.arg("+beta");
            }
        }
        test_cmd.args(&["test", "--no-run"]);
    }
    test_cmd.args(&[
        "--message-format",
        "json",
        "--manifest-path",
        manifest_path,
    ]);
    match ty {
        RunType::Tests => test_cmd.arg("--tests"),
        RunType::Doctests => test_cmd.arg("--doc"),
        RunType::Benchmarks => test_cmd.arg("--benches"),
        RunType::Examples => test_cmd.arg("--examples"),
    };
    init_args(&mut test_cmd, config);
    setup_environment(&mut test_cmd, config);

    test_cmd
}

fn init_args(test_cmd: &mut Command, config: &Config) {
    // TODO Missing +nightly etc commands, flag_quiet/verbosity
    if config.locked {
        test_cmd.arg("--locked");
    }
    if config.frozen {
        test_cmd.arg("--frozen");
    }
    if !config.features.is_empty() {
        let mut args = vec!["--features".to_string()];
        args.extend_from_slice(&config.features);
        test_cmd.args(args);
    }
    if config.all_features {
        test_cmd.arg("--all-features");
    }
    if config.no_default_features {
        test_cmd.arg("--no-default-features");
    }
    if config.all {
        test_cmd.arg("--workspace");
    }
    if config.release {
        test_cmd.arg("--release");
    }
    if let Some(ref target_dir) = config.target_dir {
        let args = vec![
            "--target-dir".to_string(),
            format!("{}", target_dir.display()),
        ];
        test_cmd.args(args);
    }
    if config.offline {
        test_cmd.arg("--offline");
    }
    for feat in &config.unstable_features {
        test_cmd.arg(format!("-Z{}", feat));
    }
    if !config.varargs.is_empty() {
        let mut args = vec!["--".to_string()];
        args.extend_from_slice(&config.varargs);
        test_cmd.args(args);
    }
}

fn setup_environment(cmd: &mut Command, config: &Config) {
    cmd.env("TARPAULIN", "1");
    let rustflags = "RUSTFLAGS";
    let common_opts =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 ";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    cmd.env(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts, DOCTEST_FOLDER
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    cmd.env(rustdoc, value);
}
<commit_msg>fmt run<commit_after>use crate::config::*;
use crate::errors::RunError;
use cargo_metadata::{parse_messages, Message};
use std::env;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use walkdir::WalkDir;

static DOCTEST_FOLDER: &str = "target/doctests";

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TestBinary {
    path: PathBuf,
    ty: RunType,
}

impl TestBinary {
    pub fn path(&self) -> &Path {
        &self.path
    }

    pub fn run_type(&self) -> RunType {
        self.ty
    }
}

pub fn get_tests(config: &Config) -> Result<Vec<TestBinary>, RunError> {
    let mut result = vec![];
    let manifest = match config.manifest.as_path().to_str() {
        Some(s) => s,
        None => "Cargo.toml",
    };
    for ty in &config.run_types {
        let mut cmd = create_command(manifest, config, ty)
            .stdout(Stdio::piped())
            .spawn()
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if ty != &RunType::Doctests {
            for msg in parse_messages(cmd.stdout.take().unwrap()) {
                if let Ok(Message::CompilerArtifact(art)) = msg {
                    if let Some(path) = art.executable {
                        result.push(TestBinary { path, ty: *ty });
                    }
                }
            }
        } else {
            // Need to get the packages...
            let package_roots = config
                .get_packages()
                .iter()
                .filter_map(|x| x.manifest_path.parent())
                .map(|x| x.join(DOCTEST_FOLDER))
                .collect::<Vec<PathBuf>>();

            for dir in &package_roots {
                let walker = WalkDir::new(dir).into_iter();
                for dt in walker
                    .filter_map(|e| e.ok())
                    .filter(|e| match e.metadata() {
                        Ok(ref m) if m.is_file() && m.len() != 0 => true,
                        _ => false,
                    })
                {
                    result.push(TestBinary {
                        path: dt.path().to_path_buf(),
                        ty: *ty,
                    });
                }
            }
        }
        cmd.wait().map_err(|e| RunError::Cargo(e.to_string()))?;
    }
    Ok(result)
}

fn create_command(manifest_path: &str, config: &Config, ty: &RunType) -> Command {
    let mut test_cmd = Command::new("cargo");
    if *ty == RunType::Doctests {
        test_cmd.args(&["+nightly", "test"]);
    } else {
        if let Ok(toolchain) = env::var("RUSTUP_TOOLCHAIN") {
            if toolchain.starts_with("nightly") {
                test_cmd.arg("+nightly");
            } else if toolchain.starts_with("beta") {
                test_cmd.arg("+beta");
            }
        }
        test_cmd.args(&["test", "--no-run"]);
    }
    test_cmd.args(&["--message-format", "json", "--manifest-path", manifest_path]);
    match ty {
        RunType::Tests => test_cmd.arg("--tests"),
        RunType::Doctests => test_cmd.arg("--doc"),
        RunType::Benchmarks => test_cmd.arg("--benches"),
        RunType::Examples => test_cmd.arg("--examples"),
    };
    init_args(&mut test_cmd, config);
    setup_environment(&mut test_cmd, config);

    test_cmd
}

fn init_args(test_cmd: &mut Command, config: &Config) {
    // TODO Missing +nightly etc commands, flag_quiet/verbosity
    if config.locked {
        test_cmd.arg("--locked");
    }
    if config.frozen {
        test_cmd.arg("--frozen");
    }
    if !config.features.is_empty() {
        let mut args = vec!["--features".to_string()];
        args.extend_from_slice(&config.features);
        test_cmd.args(args);
    }
    if config.all_features {
        test_cmd.arg("--all-features");
    }
    if config.no_default_features {
        test_cmd.arg("--no-default-features");
    }
    if config.all {
        test_cmd.arg("--workspace");
    }
    if config.release {
        test_cmd.arg("--release");
    }
    if let Some(ref target_dir) = config.target_dir {
        let args = vec![
            "--target-dir".to_string(),
            format!("{}", target_dir.display()),
        ];
        test_cmd.args(args);
    }
    if config.offline {
        test_cmd.arg("--offline");
    }
    for feat in &config.unstable_features {
        test_cmd.arg(format!("-Z{}", feat));
    }
    if !config.varargs.is_empty() {
        let mut args = vec!["--".to_string()];
        args.extend_from_slice(&config.varargs);
        test_cmd.args(args);
    }
}

fn setup_environment(cmd: &mut Command, config: &Config) {
    cmd.env("TARPAULIN", "1");
    let rustflags = "RUSTFLAGS";
    let common_opts =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 ";
    let mut value = common_opts.to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    cmd.env(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!(
        "{} --persist-doctests {} -Z unstable-options ",
        common_opts, DOCTEST_FOLDER
    );
    if let Ok(vtemp) = env::var(rustdoc) {
        if !vtemp.contains("--persist-doctests") {
            value.push_str(vtemp.as_ref());
        }
    }
    cmd.env(rustdoc, value);
}
<|endoftext|>


<commit_before>use mem::Mem;
use disasm;
use cpu;
use std::num::from_str_radix;
use std::io::{buffered, signal, stdio, File};

//
// Debugger
//

fn disasm<M: Mem>(mem: &mut M, addr: &mut u16) -> ~str {
  let mut d = disasm::Disasm { mem: mem, pc: *addr };
  let result = cpu::decode(&mut d);
  *addr = d.pc;
  result
}

fn disassemble<M: Mem>(mem: &mut M, addr: u16) {
  let mut pc = addr;

  for _ in range(0, 5) {
    let start_addr = pc;
    let instr = disasm(mem, &mut pc);
    let end_addr = pc;
    print!("${:04X}", start_addr);
    for a in range(start_addr, end_addr) {
      print!(" {:02X}", mem.loadb(a));
    }
    println!("\t{:s}", instr);
  }
}

fn print_mem<M: Mem>(mem: &mut M, addr: u16) {
  println("\t  0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F");

  let mut base = addr & 0xfff0;
  let mut start_offset = addr & 0xf;

  for _ in range(0, 4) {
    print!("${:04X}\t", base);
    for offset in range(0u16, 16u16) {
      if offset == 8 {
        print(" ");
      }
      if offset >= start_offset {
        print!(" {:02X}", mem.loadb(base + offset));
      } else {
        print("   ");
      }
    }
    println("");
    base += 0x10;
    start_offset = 0;

    if base < addr { // wrap-around
      break;
    }
  }
}

fn print_regs<M>(cpu: &cpu::Cpu<M>) {
  println!("AF={:02X}{:02X} BC={:02X}{:02X} DE={:02X}{:02X} HL={:02X}{:02X} SP={:04X} PC={:04X} CY={:u}",
           cpu.regs.a, cpu.regs.f,
           cpu.regs.b, cpu.regs.c,
           cpu.regs.d, cpu.regs.e,
           cpu.regs.h, cpu.regs.l,
           cpu.regs.sp,
           cpu.regs.pc,
           cpu.cycles);
}

fn expand_tile_row(tile: &[u8], palette: u8, row: u8, pixels: &mut [u8]) {
  for col in range(0u, 8u) {
    let low_bit  = (tile[2*row]   >> (7 - col)) & 1;
    let high_bit = (tile[2*row+1] >> (7 - col)) & 1;
    let value = (high_bit << 1) | low_bit;
    let color = 3 - ((palette >> (2 * value)) & 0b11);
    pixels[col] = color;
  }
}

fn write_pgm(path: &Path, width: uint, height: uint, data: &[u8]) {
  let mut output = File::create(path).unwrap();
  output.write_line("P5");
  output.write_line(format!("{:u} {:u}", width, height));
  output.write_line("3");
  output.write(data);
}

fn dump_tiles<M: Mem>(m: &mut M) {
  let mut data = [0u8, ..16*24*8*8];

  for num in range(0u, 384u) {
    let mut tile = [0u8, ..16];
    for offset in range(0u, 16u) {
      tile[offset] = m.loadb(0x8000u16 + num as u16 * 16u16 + offset as u16);
    }
    let row = num / 16;
    let col = num % 16;
    let pixels = data.mut_slice_from((row * 16 * 8 + col)*8);
    for row in range(0u, 8u) {
      expand_tile_row(tile, 0xe4, row as u8, pixels.mut_slice_from(16*8*row));
    }
  }

  write_pgm(&Path::new("tiles.pgm"), 16*8, 24*8, data);
}

fn dump_bg<M: Mem>(m: &mut M) {
  let mut tile_base = 0x8800;
  let mut tile_bias = 127u8; // ???
  let mut map_base = 0x9800;

  let lcdc = m.loadb(0xff40);
  if (lcdc & 0b10000) != 0 {
    tile_base = 0x8000;
    tile_bias = 0u8;
  }
  if (lcdc & 0b01000) != 0 {
    map_base = 0x9c000;
  }

  // Load tiles
  let mut tiles = [0xffu8, ..256*16];
  for offset in range(0u, 256*16) {
    tiles[offset] = m.loadb((tile_base + offset) as u16);
  }

  // Load map
  let mut map = [0u8, ..32*32];
  for offset in range(0u, 32u*32u) {
    map[offset] = m.loadb((map_base + offset) as u16);
  }

  // Load palette
  let pal = m.loadb(0xff47);

  let mut data = [0u8, ..32*32*8*8];
  let row_pitch = 32*8;

  for row in range(0u, 32u) {
    for col in range(0u, 32u) {
      let tile_num = (map[row*32 + col] + tile_bias) as uint;
      let tile = tiles.slice_from(tile_num * 16);
      let pixels = data.mut_slice_from((row*row_pitch + col)*8);
      for tile_row in range(0u, 8u) {
        expand_tile_row(tile,
                        pal,
                        tile_row as u8,
                        pixels.mut_slice_from(tile_row*row_pitch));
      }
    }
  }

  write_pgm(&Path::new("bg.pgm"), 32*8, 32*8, data);
}

fn parse_addr(s: &str) -> Option<u16> {
  let mut slice = s;
  let mut radix = 10;
  if slice.starts_with("$") {
    slice = slice.slice_from(1);
    radix = 16;
  }
  from_str_radix::<u16>(slice, radix)
}

pub struct Debugger {
  breakpoints: ~[u16],
  intr_listener: signal::Listener,
}

pub enum DebuggerCommand {
  Quit,
  Step,
  Run,
}

impl Debugger {
  pub fn new() -> Debugger {
    let mut intr_listener = signal::Listener::new();
    intr_listener.register(signal::Interrupt);

    Debugger { breakpoints: ~[], intr_listener: intr_listener }
  }

  fn show_breakpoints(&self) {
    if self.breakpoints.len() == 0 {
      println("No breakpoints");
    } else {
      println("Breakpoints:");
      for bp in self.breakpoints.iter() {
        println!("  ${:04X}", *bp);
      }
    }
  }

  fn add_breakpoint(&mut self, addr: u16) {
    if !self.breakpoints.contains(&addr) {
      self.breakpoints.push(addr);
      self.breakpoints.sort();
      println!("Breakpoint ${:04X} added", addr);
    } else {
      println!("Breakpoint ${:04X} already exists", addr);
    }
  }

  fn remove_breakpoint(&mut self, addr: u16) {
    if self.breakpoints.contains(&addr) {
      self.breakpoints.retain(|&bp| bp != addr);
      println!("Breakpoint ${:04X} removed", addr);
    } else {
      error!("No such breakpoint ${:04X}", addr);
    }
  }

  fn dispatch<M: Mem>(&mut self, cpu: &mut cpu::Cpu<M>, words: &[&str]) -> Option<DebuggerCommand> {
    if words.len() == 0 {
      return None;
    }

    let command = words[0];
    match command {
      &"q" => Some(Quit), // quit
      &"s" => Some(Step), // step
      &"r" => Some(Run), // run
      &"regs" => { print_regs(cpu); None }, // print registers
      &"m" => { // print memory
        if words.len() >= 2 {
          match parse_addr(words[1]) {
            Some(addr) => print_mem(&mut cpu.mem, addr),
            None       => error!("Invalid address: {:s}", words[1]),
          }
        }
        None
      },
      &"d" => { // disasm
        let mut addr = cpu.regs.pc;
        if words.len() >= 2 {
          match parse_addr(words[1]) {
            Some(a) => addr = a,
            None    => error!("Invalid address: {:s}", words[1]),
          }
        }
        disassemble(&mut cpu.mem, addr);
        None
      },
      &"b" => { // breakpoint
        if words.len() == 1 {
          self.show_breakpoints();
        } else if words.len() >= 2 {
          // add/remove breakpoint
          let mut add = true;
          let mut arg = words[1];
          if arg.starts_with("-") {
            arg = arg.slice_from(1);
            add = false;
          }
          match parse_addr(arg) {
            Some(addr) => {
              if add {
                self.add_breakpoint(addr);
              } else {
                self.remove_breakpoint(addr);
              }
            },
            None => error!("Invalid address: {:s}", words[1]),
          }
        }
        None
      },
      &"tiles" => { // dump video tiles
        dump_tiles(&mut cpu.mem);
        None
      },
      &"bg" => { // dump video bg
        dump_bg(&mut cpu.mem);
        None
      },
      _ => {
        error!("Unknown command: {:s}", command);
        None
      }
    }
  }

  pub fn prompt<M: Mem>(&mut self, cpu: &mut cpu::Cpu<M>) -> DebuggerCommand {
    let mut stdin = buffered::BufferedReader::new(stdio::stdin());

    loop {
      print("> ");
      stdio::flush();
      match stdin.read_line() {
        Some(line) => {
          let words = line.words().to_owned_vec();
          match self.dispatch(cpu, words) {
            Some(command) => return command,
            None => (),
          }
        },
        None => {
          println("\nType q to exit");
          self.intr_listener.port.recv(); // grok the interrupt
        }
      }
    }
  }

  pub fn should_break<M>(&self, cpu: &cpu::Cpu<M>) -> bool {
    match self.breakpoints.iter().find(|&bp| *bp == cpu.regs.pc) {
      Some(&bp) => {
        println!("Breakpoint at ${:04X}", bp);
        return true
      },
      None => (),
    }

    match self.intr_listener.port.try_recv() {
      Some(signal::Interrupt) => {
        println("Interrupted");
        return true
      },
      _ => (),
    }

    false
  }
}
<commit_msg>Fixed tile bias in debug::dump_bg<commit_after>use mem::Mem;
use disasm;
use cpu;
use std::num::from_str_radix;
use std::io::{buffered, signal, stdio, File};

//
// Debugger
//

fn disasm<M: Mem>(mem: &mut M, addr: &mut u16) -> ~str {
  let mut d = disasm::Disasm { mem: mem, pc: *addr };
  let result = cpu::decode(&mut d);
  *addr = d.pc;
  result
}

fn disassemble<M: Mem>(mem: &mut M, addr: u16) {
  let mut pc = addr;

  for _ in range(0, 5) {
    let start_addr = pc;
    let instr = disasm(mem, &mut pc);
    let end_addr = pc;
    print!("${:04X}", start_addr);
    for a in range(start_addr, end_addr) {
      print!(" {:02X}", mem.loadb(a));
    }
    println!("\t{:s}", instr);
  }
}

fn print_mem<M: Mem>(mem: &mut M, addr: u16) {
  println("\t  0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F");

  let mut base = addr & 0xfff0;
  let mut start_offset = addr & 0xf;

  for _ in range(0, 4) {
    print!("${:04X}\t", base);
    for offset in range(0u16, 16u16) {
      if offset == 8 {
        print(" ");
      }
      if offset >= start_offset {
        print!(" {:02X}", mem.loadb(base + offset));
      } else {
        print("   ");
      }
    }
    println("");
    base += 0x10;
    start_offset = 0;

    if base < addr { // wrap-around
      break;
    }
  }
}

fn print_regs<M>(cpu: &cpu::Cpu<M>) {
  println!("AF={:02X}{:02X} BC={:02X}{:02X} DE={:02X}{:02X} HL={:02X}{:02X} SP={:04X} PC={:04X} CY={:u}",
           cpu.regs.a, cpu.regs.f,
           cpu.regs.b, cpu.regs.c,
           cpu.regs.d, cpu.regs.e,
           cpu.regs.h, cpu.regs.l,
           cpu.regs.sp,
           cpu.regs.pc,
           cpu.cycles);
}

fn expand_tile_row(tile: &[u8], palette: u8, row: u8, pixels: &mut [u8]) {
  for col in range(0u, 8u) {
    let low_bit  = (tile[2*row]   >> (7 - col)) & 1;
    let high_bit = (tile[2*row+1] >> (7 - col)) & 1;
    let value = (high_bit << 1) | low_bit;
    let color = 3 - ((palette >> (2 * value)) & 0b11);
    pixels[col] = color;
  }
}

fn write_pgm(path: &Path, width: uint, height: uint, data: &[u8]) {
  let mut output = File::create(path).unwrap();
  output.write_line("P5");
  output.write_line(format!("{:u} {:u}", width, height));
  output.write_line("3");
  output.write(data);
}

fn dump_tiles<M: Mem>(m: &mut M) {
  let mut data = [0u8, ..16*24*8*8];

  for num in range(0u, 384u) {
    let mut tile = [0u8, ..16];
    for offset in range(0u, 16u) {
      tile[offset] = m.loadb(0x8000u16 + num as u16 * 16u16 + offset as u16);
    }
    let row = num / 16;
    let col = num % 16;
    let pixels = data.mut_slice_from((row * 16 * 8 + col)*8);
    for row in range(0u, 8u) {
      expand_tile_row(tile, 0xe4, row as u8, pixels.mut_slice_from(16*8*row));
    }
  }

  write_pgm(&Path::new("tiles.pgm"), 16*8, 24*8, data);
}

fn dump_bg<M: Mem>(m: &mut M) {
  let mut tile_base = 0x8800;
  let mut tile_bias = 128u8;
  let mut map_base = 0x9800;

  let lcdc = m.loadb(0xff40);
  if (lcdc & 0b10000) != 0 {
    tile_base = 0x8000;
    tile_bias = 0u8;
  }
  if (lcdc & 0b01000) != 0 {
    map_base = 0x9c000;
  }

  // Load tiles
  let mut tiles = [0xffu8, ..256*16];
  for offset in range(0u, 256*16) {
    tiles[offset] = m.loadb((tile_base + offset) as u16);
  }

  // Load map
  let mut map = [0u8, ..32*32];
  for offset in range(0u, 32u*32u) {
    map[offset] = m.loadb((map_base + offset) as u16);
  }

  // Load palette
  let pal = m.loadb(0xff47);

  let mut data = [0u8, ..32*32*8*8];
  let row_pitch = 32*8;

  for row in range(0u, 32u) {
    for col in range(0u, 32u) {
      let tile_num = (map[row*32 + col] + tile_bias) as uint;
      let tile = tiles.slice_from(tile_num * 16);
      let pixels = data.mut_slice_from((row*row_pitch + col)*8);
      for tile_row in range(0u, 8u) {
        expand_tile_row(tile,
                        pal,
                        tile_row as u8,
                        pixels.mut_slice_from(tile_row*row_pitch));
      }
    }
  }

  write_pgm(&Path::new("bg.pgm"), 32*8, 32*8, data);
}

fn parse_addr(s: &str) -> Option<u16> {
  let mut slice = s;
  let mut radix = 10;
  if slice.starts_with("$") {
    slice = slice.slice_from(1);
    radix = 16;
  }
  from_str_radix::<u16>(slice, radix)
}

pub struct Debugger {
  breakpoints: ~[u16],
  intr_listener: signal::Listener,
}

pub enum DebuggerCommand {
  Quit,
  Step,
  Run,
}

impl Debugger {
  pub fn new() -> Debugger {
    let mut intr_listener = signal::Listener::new();
    intr_listener.register(signal::Interrupt);

    Debugger { breakpoints: ~[], intr_listener: intr_listener }
  }

  fn show_breakpoints(&self) {
    if self.breakpoints.len() == 0 {
      println("No breakpoints");
    } else {
      println("Breakpoints:");
      for bp in self.breakpoints.iter() {
        println!("  ${:04X}", *bp);
      }
    }
  }

  fn add_breakpoint(&mut self, addr: u16) {
    if !self.breakpoints.contains(&addr) {
      self.breakpoints.push(addr);
      self.breakpoints.sort();
      println!("Breakpoint ${:04X} added", addr);
    } else {
      println!("Breakpoint ${:04X} already exists", addr);
    }
  }

  fn remove_breakpoint(&mut self, addr: u16) {
    if self.breakpoints.contains(&addr) {
      self.breakpoints.retain(|&bp| bp != addr);
      println!("Breakpoint ${:04X} removed", addr);
    } else {
      error!("No such breakpoint ${:04X}", addr);
    }
  }

  fn dispatch<M: Mem>(&mut self, cpu: &mut cpu::Cpu<M>, words: &[&str]) -> Option<DebuggerCommand> {
    if words.len() == 0 {
      return None;
    }

    let command = words[0];
    match command {
      &"q" => Some(Quit), // quit
      &"s" => Some(Step), // step
      &"r" => Some(Run), // run
      &"regs" => { print_regs(cpu); None }, // print registers
      &"m" => { // print memory
        if words.len() >= 2 {
          match parse_addr(words[1]) {
            Some(addr) => print_mem(&mut cpu.mem, addr),
            None       => error!("Invalid address: {:s}", words[1]),
          }
        }
        None
      },
      &"d" => { // disasm
        let mut addr = cpu.regs.pc;
        if words.len() >= 2 {
          match parse_addr(words[1]) {
            Some(a) => addr = a,
            None    => error!("Invalid address: {:s}", words[1]),
          }
        }
        disassemble(&mut cpu.mem, addr);
        None
      },
      &"b" => { // breakpoint
        if words.len() == 1 {
          self.show_breakpoints();
        } else if words.len() >= 2 {
          // add/remove breakpoint
          let mut add = true;
          let mut arg = words[1];
          if arg.starts_with("-") {
            arg = arg.slice_from(1);
            add = false;
          }
          match parse_addr(arg) {
            Some(addr) => {
              if add {
                self.add_breakpoint(addr);
              } else {
                self.remove_breakpoint(addr);
              }
            },
            None => error!("Invalid address: {:s}", words[1]),
          }
        }
        None
      },
      &"tiles" => { // dump video tiles
        dump_tiles(&mut cpu.mem);
        None
      },
      &"bg" => { // dump video bg
        dump_bg(&mut cpu.mem);
        None
      },
      _ => {
        error!("Unknown command: {:s}", command);
        None
      }
    }
  }

  pub fn prompt<M: Mem>(&mut self, cpu: &mut cpu::Cpu<M>) -> DebuggerCommand {
    let mut stdin = buffered::BufferedReader::new(stdio::stdin());

    loop {
      print("> ");
      stdio::flush();
      match stdin.read_line() {
        Some(line) => {
          let words = line.words().to_owned_vec();
          match self.dispatch(cpu, words) {
            Some(command) => return command,
            None => (),
          }
        },
        None => {
          println("\nType q to exit");
          self.intr_listener.port.recv(); // grok the interrupt
        }
      }
    }
  }

  pub fn should_break<M>(&self, cpu: &cpu::Cpu<M>) -> bool {
    match self.breakpoints.iter().find(|&bp| *bp == cpu.regs.pc) {
      Some(&bp) => {
        println!("Breakpoint at ${:04X}", bp);
        return true
      },
      None => (),
    }

    match self.intr_listener.port.try_recv() {
      Some(signal::Interrupt) => {
        println("Interrupted");
        return true
      },
      _ => (),
    }

    false
  }
}
<|endoftext|>