<commit_before>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod {
        tag: U1,
        class_index: U2,
        name_and_type_index: U2,
    },
    String { tag: U1, string_index: U2 },
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType {
        tag: U1,
        name_index: U2,
        descriptor_index: U2,
    },
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String { .. } => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod { .. } =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType { .. } => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    pub fn retrieve_item(index: usize,
                         constant_pool: &Vec<ConstantPoolItem>)
                         -> ParserResult<&ConstantPoolItem> {
        let actual_index = Self::shift_index(index);
        return constant_pool.get(index)
            .ok_or(ParserError::ConstantPoolIndexOutOfBounds(actual_index));
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<commit_msg>Convert String ConstantPoolItem to struct<commit_after>use super::{ParserError, ParserResult};
use super::primitives::{PrimitiveIterator, U1, U2, U4};

use std::ops::Deref;
use std::rc::Rc;

macro_rules! generate_constant_pool_retrieval_method {
    ($variant_name:ident, $struct_name:ident, $method_name:ident) => {
        pub fn $method_name(index: usize,
                            constant_pool: &Vec<ConstantPoolItem>)
            -> ParserResult<Rc<$struct_name>> {
                let actual_index = ConstantPoolItem::shift_index(index);

                if let Some(item) = constant_pool.get(actual_index) {
                    match item {
                        &ConstantPoolItem::$variant_name(ref val) => return Ok(val.clone()),
                        item @ _ => {
                            let name = item.to_friendly_name();
                            return Err(ParserError::UnexpectedConstantPoolItem(name))
                        }
                    }
                }

                Err(ParserError::ConstantPoolIndexOutOfBounds(actual_index))
            }

    }
}

#[derive(Debug)]
pub struct ClassInfo {
    pub tag: U1,
    pub name_index: U2,
}

#[derive(Debug)]
pub struct StringInfo {
    pub tag: U1,
    pub string_index: U2,
}

#[derive(Debug)]
pub struct Utf8Info {
    pub tag: U1,
    pub length: U2,
    pub value: String,
}

impl Deref for Utf8Info {
    type Target = str;

    fn deref(&self) -> &str {
        &self.value
    }
}

#[derive(Debug)]
pub enum ConstantPoolItem {
    Class(Rc<ClassInfo>),
    FieldOrMethodOrInterfaceMethod {
        tag: U1,
        class_index: U2,
        name_and_type_index: U2,
    },
    String(Rc<StringInfo>),
    IntegerOrFloat { tag: U1, bytes: U1 },
    LongOrDouble {
        tag: U1,
        high_bytes: U4,
        low_bytes: U4,
    },
    NameAndType {
        tag: U1,
        name_index: U2,
        descriptor_index: U2,
    },
    Utf8(Rc<Utf8Info>),
    MethodHandle {
        tag: U1,
        reference_kind: U1,
        reference_index: U2,
    },
    MethodType { tag: U1, descriptor_index: U2 },
    InvokeDynamic {
        tag: U1,
        bootstrap_method_attr_index: U2,
        name_and_type_index: U2,
    },
}

impl ConstantPoolItem {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ConstantPoolItem> {
        let tag = try!(iter.next_u1());

        match tag {
            1 => {
                let length = try!(iter.next_u2());

                let mut byte_vec = vec![];
                for _ in 0..length {
                    byte_vec.push(try!(iter.next_u1()));
                }

                let value = try!(String::from_utf8(byte_vec));

                Ok(ConstantPoolItem::Utf8(Rc::new(Utf8Info {
                    tag: tag,
                    length: length,
                    value: value,
                })))
            }
            7 => {
                Ok(ConstantPoolItem::Class(Rc::new(ClassInfo {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                })))
            }
            8 => {
                Ok(ConstantPoolItem::String(Rc::new(StringInfo {
                    tag: tag,
                    string_index: try!(iter.next_u2()),
                })))
            }
            9 | 10 | 11 => {
                Ok(ConstantPoolItem::FieldOrMethodOrInterfaceMethod {
                    tag: tag,
                    class_index: try!(iter.next_u2()),
                    name_and_type_index: try!(iter.next_u2()),
                })
            }
            12 => {
                Ok(ConstantPoolItem::NameAndType {
                    tag: tag,
                    name_index: try!(iter.next_u2()),
                    descriptor_index: try!(iter.next_u2()),
                })
            }
            _ => Err(ParserError::UnknownConstantPoolTag(tag)),
        }
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn to_friendly_name(&self) -> &'static str {
        match self {
            &ConstantPoolItem::Utf8(..) => "Utf8",
            &ConstantPoolItem::Class(..) => "Class",
            &ConstantPoolItem::String(..) => "String",
            &ConstantPoolItem::FieldOrMethodOrInterfaceMethod { .. } =>
                "Field|Method|InterfaceMethod",
                &ConstantPoolItem::NameAndType { .. } => "NameAndType",
                _ => "Not yet implemented",
        }
    }

    pub fn retrieve_item(index: usize,
                         constant_pool: &Vec<ConstantPoolItem>)
                         -> ParserResult<&ConstantPoolItem> {
        let actual_index = Self::shift_index(index);
        return constant_pool.get(index)
            .ok_or(ParserError::ConstantPoolIndexOutOfBounds(actual_index));
    }

    generate_constant_pool_retrieval_method!(Class, ClassInfo, retrieve_class_info);
    generate_constant_pool_retrieval_method!(Utf8, Utf8Info, retrieve_utf8_info);

    fn shift_index(unshifted_index: usize) -> usize {
        unshifted_index - 1 // references to the constant pool start from one
    }
}

#[derive(Debug)]
pub struct CodeAttribute {
    pub attribute_name: Rc<Utf8Info>,
    pub max_stack: U2,
    pub max_locals: U2,
    pub code_length: U4,
    pub code: Vec<U1>,
    pub exception_table_length: U2,
    pub exception_table: Vec<ExceptionHandler>,
    pub attributes_count: U2,
    pub attributes: Vec<Attribute>,
}

impl CodeAttribute {
    pub fn from<T: PrimitiveIterator>(attribute_name: Rc<Utf8Info>,
                                      iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<CodeAttribute> {
        let max_stack = try!(iter.next_u2());
        let max_locals = try!(iter.next_u2());

        let code_length = try!(iter.next_u4());
        let mut code = vec![];
        for _ in 0..code_length {
            code.push(try!(iter.next_u1()));
        }

        let exception_table_length = try!(iter.next_u2());
        let mut exception_table = vec![];
        for _ in 0..exception_table_length {
            exception_table.push(try!(ExceptionHandler::from(iter)));
        }

        let attributes_count = try!(iter.next_u2());
        let mut attributes = vec![];
        for _ in 0..attributes_count {
            attributes.push(try!(Attribute::from(iter, constant_pool)));
        }

        Ok(CodeAttribute {
            attribute_name: attribute_name,
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code,
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    }
}

#[derive(Debug)]
pub struct ExceptionHandler {
    pub start_pc: U2,
    pub end_pc: U2,
    pub handler_pc: U2,
    pub catch_type: U2,
}

impl ExceptionHandler {
    pub fn from<T: PrimitiveIterator>(iter: &mut T) -> ParserResult<ExceptionHandler> {
        let start_pc = try!(iter.next_u2());
        let end_pc = try!(iter.next_u2());
        let handler_pc = try!(iter.next_u2());
        let catch_type = try!(iter.next_u2());

        Ok(ExceptionHandler {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    }
}

#[derive(Debug)]
pub enum Attribute {
    Code(Rc<CodeAttribute>),
    Unknown {
        attribute_name: Rc<Utf8Info>,
        info: Vec<U1>,
    },
}

impl Attribute {
    pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                      constant_pool: &Vec<ConstantPoolItem>)
                                      -> ParserResult<Attribute> {
        let attribute_name_index = try!(iter.next_u2());
        let attribute_name =
            try!(ConstantPoolItem::retrieve_utf8_info(attribute_name_index as usize,
                                                      constant_pool));

        let attribute_length = try!(iter.next_u4());

        match &**attribute_name {
            "Code" => {
                Ok(Attribute::Code(Rc::new(try!(CodeAttribute::from(attribute_name,
                                                                    iter,
                                                                    constant_pool)))))
            }
            _ => {
                let mut info = vec![];
                for _ in 0..attribute_length {
                    info.push(try!(iter.next_u1()));
                }

                Ok(Attribute::Unknown {
                    attribute_name: attribute_name,
                    info: info,
                })
            }
        }
    }
}

macro_rules! generate_method_or_field_parser_impl {
    ($impl_name:ident) => {
        impl $impl_name {
            pub fn from<T: PrimitiveIterator>(iter: &mut T,
                                              constant_pool: &Vec<ConstantPoolItem>)
                -> ParserResult<$impl_name> {
                    let access_flags = try!(iter.next_u2());

                    let name_index = try!(iter.next_u2());
                    let name = try!(ConstantPoolItem::retrieve_utf8_info(name_index as usize,
                                                                         constant_pool));

                    let descriptor_index = try!(iter.next_u2());
                    let descriptor = try!(ConstantPoolItem::retrieve_utf8_info(
                            descriptor_index as usize,
                            constant_pool));

                    let attributes_count = try!(iter.next_u2());
                    let mut attributes = vec![];
                    for _ in 0..attributes_count {
                        attributes.push(Rc::new(try!(Attribute::from(iter, constant_pool))));
                    }

                    Ok($impl_name {
                        access_flags: access_flags,
                        name: name,
                        descriptor: descriptor,
                        attributes_count: attributes_count,
                        attributes: attributes,
                    })

                }
        }
    }
}

#[derive(Debug)]
pub struct Field {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

#[derive(Debug)]
pub struct Method {
    pub access_flags: U2,
    pub name: Rc<Utf8Info>,
    pub descriptor: Rc<Utf8Info>,
    pub attributes_count: U2,
    pub attributes: Vec<Rc<Attribute>>,
}

generate_method_or_field_parser_impl!(Field);
generate_method_or_field_parser_impl!(Method);

pub struct AccessFlags;

impl AccessFlags {
    pub fn is_public(access_flags: U2) -> bool {
        (access_flags & 0x0001) != 0
    }

    pub fn is_private(access_flags: U2) -> bool {
        (access_flags & 0x0002) != 0
    }

    pub fn is_protected(access_flags: U2) -> bool {
        (access_flags & 0x0004) != 0
    }

    pub fn is_static(access_flags: U2) -> bool {
        (access_flags & 0x0008) != 0
    }

    pub fn is_final(access_flags: U2) -> bool {
        (access_flags & 0x0010) != 0
    }

    pub fn is_super(access_flags: U2) -> bool {
        (access_flags & 0x0020) != 0
    }

    pub fn is_volatile(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_bridge(access_flags: U2) -> bool {
        (access_flags & 0x0040) != 0
    }

    pub fn is_transient(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_varargs(access_flags: U2) -> bool {
        (access_flags & 0x0080) != 0
    }

    pub fn is_native(access_flags: U2) -> bool {
        (access_flags & 0x0100) != 0
    }

    pub fn is_interface(access_flags: U2) -> bool {
        (access_flags & 0x0200) != 0
    }

    pub fn is_abstract(access_flags: U2) -> bool {
        (access_flags & 0x0400) != 0
    }

    pub fn is_strict(access_flags: U2) -> bool {
        (access_flags & 0x0800) != 0
    }

    pub fn is_synthetic(access_flags: U2) -> bool {
        (access_flags & 0x1000) != 0
    }

    pub fn is_annotation(access_flags: U2) -> bool {
        (access_flags & 0x2000) != 0
    }

    pub fn is_enum(access_flags: U2) -> bool {
        (access_flags & 0x4000) != 0
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Seek};
use byteorder::{ReadBytesExt, LittleEndian};

use image::ImageError;
use image::ImageResult;
use image::ImageDecoder;
use image::DecodingResult;
use color::ColorType;

enum ImageType {
    NoImageData = 0,
    /// Uncompressed images
    RawColorMap = 1,
    RawTrueColor = 2,
    RawGrayScale = 3,
    /// Run length encoded images
    RunColorMap = 9,
    RunTrueColor = 10,
    RunGrayScale = 11,
    Unknown,
}

impl ImageType {
    /// Create a new image type from a u8
    fn new(img_type: u8) -> ImageType {
        match img_type {
            0  => ImageType::NoImageData,

            1  => ImageType::RawColorMap,
            2  => ImageType::RawTrueColor,
            3  => ImageType::RawGrayScale,

            9  => ImageType::RunColorMap,
            10 => ImageType::RunTrueColor,
            11 => ImageType::RunGrayScale,

            _  => ImageType::Unknown,
        }
    }

    /// Check if the image format uses colors as opposed to gray scale
    fn is_color(&self) -> bool {
        match *self {
            ImageType::RawColorMap  |
            ImageType::RawTrueColor |
            ImageType::RunTrueColor |
            ImageType::RunColorMap => true,
            _ => false,
        }
    }

    /// Does the image use a color map
    fn is_color_mapped(&self) -> bool {
        match *self {
            ImageType::RawColorMap |
            ImageType::RunColorMap => true,
            _ => false,
        }
    }

    /// Is the image run length encoded
    fn is_encoded(&self) -> bool {
        match *self {
            ImageType::RunColorMap |
            ImageType::RunTrueColor |
            ImageType::RunGrayScale => true,
            _ => false,
        }
    }
}

/// Header used by TGA image files
#[derive(Debug)]
struct Header {
    id_length: u8,         // length of ID string
    map_type: u8,          // color map type
    image_type: u8,        // image type code
    map_origin: u16,       // starting index of map
    map_length: u16,      // length of map
    map_entry_size: u8,    // size of map entries in bits
    x_origin: u16,         // x-origin of image
    y_origin: u16,         // y-origin of image
    image_width: u16,      // width of image
    image_height: u16,     // height of image
    pixel_depth: u8,       // bits per pixel
    image_desc: u8,        // image descriptor
}

impl Header {
    /// Create a header with all valuse set to zero
    fn new() -> Header {
        Header {
            id_length: 0,
            map_type: 0,
            image_type: 0,
            map_origin: 0,
            map_length: 0,
            map_entry_size: 0,
            x_origin: 0,
            y_origin: 0,
            image_width: 0,
            image_height: 0,
            pixel_depth: 0,
            image_desc: 0,
        }
    }

    /// Load the header with values from the reader
    fn from_reader(r: &mut Read) -> ImageResult<Header> {
        Ok(Header {
            id_length:         try!(r.read_u8()),
            map_type:          try!(r.read_u8()),
            image_type:        try!(r.read_u8()),
            map_origin:        try!(r.read_u16::<LittleEndian>()),
            map_length:        try!(r.read_u16::<LittleEndian>()),
            map_entry_size:    try!(r.read_u8()),
            x_origin:          try!(r.read_u16::<LittleEndian>()),
            y_origin:          try!(r.read_u16::<LittleEndian>()),
            image_width:       try!(r.read_u16::<LittleEndian>()),
            image_height:      try!(r.read_u16::<LittleEndian>()),
            pixel_depth:       try!(r.read_u8()),
            image_desc:        try!(r.read_u8()),
        })
    }
}

struct ColorMap {
    /// sizes in bytes
    start_offset: usize,
    entry_size: usize,
    bytes: Vec<u8>,
}

impl ColorMap {
    pub fn from_reader(r: &mut Read,
                       start_offset: u16,
                       num_entries: u16,
                       bits_per_entry: u8)
        -> ImageResult<ColorMap> {
            let bytes_per_entry = (bits_per_entry as usize + 7) / 8;

            let mut bytes = vec![0; bytes_per_entry * num_entries as usize];
            try!(r.read_exact(&mut bytes));

            Ok(ColorMap {
                entry_size: bytes_per_entry,
                start_offset: start_offset as usize,
                bytes: bytes,
            })
        }

    /// Get one entry from the color map
    pub fn get(&self, index: usize) -> &[u8] {
        let entry = self.start_offset + self.entry_size * index;
        &self.bytes[entry..entry + self.entry_size]
    }
}

/// The representation of a TGA decoder
pub struct TGADecoder<R> {
    r: R,

    width: usize,
    height: usize,
    bytes_per_pixel: usize,
    has_loaded_metadata: bool,

    image_type: ImageType,
    color_type: ColorType,

    header: Header,
    color_map: Option<ColorMap>,
}

impl<R: Read + Seek> TGADecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(r: R) -> TGADecoder<R> {
        TGADecoder {
            r: r,

            width: 0,
            height: 0,
            bytes_per_pixel: 0,
            has_loaded_metadata: false,

            image_type: ImageType::Unknown,
            color_type: ColorType::Gray(1),

            header: Header::new(),
            color_map: None,
        }
    }

    fn read_header(&mut self) -> ImageResult<()> {
        self.header = try!(Header::from_reader(&mut self.r));
        self.image_type = ImageType::new(self.header.image_type);
        self.width = self.header.image_width as usize;
        self.height = self.header.image_height as usize;
        self.bytes_per_pixel = (self.header.pixel_depth as usize + 7) / 8;
        Ok(())
    }

    fn read_metadata(&mut self) -> ImageResult<()> {
        if !self.has_loaded_metadata {
            try!(self.read_header());
            try!(self.read_image_id());
            try!(self.read_color_map());
            try!(self.read_color_information());
            self.has_loaded_metadata = true;
        }
        Ok(())
    }

    /// Loads the color information for the decoder
    ///
    /// To keep things simple, we won't handle bit depths that aren't divisible
    /// by 8 and are less than 32.
    fn read_color_information(&mut self) -> ImageResult<()> {
        if self.header.pixel_depth % 8 != 0 {
            return Err(ImageError::UnsupportedError("\
                Bit depth must be divisible by 8".to_string()));
        }
        if self.header.pixel_depth > 32 {
            return Err(ImageError::UnsupportedError("\
                Bit depth must be less than 32".to_string()));
        }

        let num_alpha_bits = self.header.image_desc & 0b1111;

        let other_channel_bits = if self.header.map_type != 0 {
            self.header.map_entry_size
        } else {
            self.header.pixel_depth - num_alpha_bits
        };
        let color = self.image_type.is_color();

        match (num_alpha_bits, other_channel_bits, color) {
            // really, the encoding is BGR and BGRA, this is fixed
            // up with `TGADecoder::reverse_encoding`.
            (8, 24, true) => self.color_type = ColorType::RGBA(8),
            (0, 24, true) => self.color_type = ColorType::RGB(8),
            (8, 8, false) => self.color_type = ColorType::GrayA(8),
            (0, 8, false) => self.color_type = ColorType::Gray(8),
            _ => return Err(ImageError::UnsupportedError(format!("\
                    Color format not supported. Bit depth: {}, Alpha bits: {}",
                    other_channel_bits, num_alpha_bits).to_string())),
        }
        Ok(())
    }

    /// Read the image id field
    ///
    /// We're not interested in this field, so this function skips it if it
    /// is present
    fn read_image_id(&mut self) -> ImageResult<()> {
        try!(self.r.seek(io::SeekFrom::Current(self.header.id_length as i64)));
        Ok(())
    }

    fn read_color_map(&mut self) -> ImageResult<()> {
        if self.header.map_type == 1 {
            self.color_map = Some(try!(
                ColorMap::from_reader(&mut self.r,
                                      self.header.map_origin,
                                      self.header.map_length,
                                      self.header.map_entry_size)));
        }
        Ok(())
    }

    /// Expands indices into its mapped color
    fn expand_color_map(&mut self, pixel_data: Vec<u8>) -> Vec<u8> {
        #[inline]
        fn bytes_to_index(bytes: &[u8]) -> usize {
            let mut result = 0usize;
            for byte in bytes.iter() {
                result = result << 8 | *byte as usize;
            }
            result
        }

        let bytes_per_entry = (self.header.map_entry_size as usize + 7) / 8;
        let mut result = Vec::with_capacity(self.width * self.height *
                                            bytes_per_entry);

        let color_map = match self.color_map {
            Some(ref color_map) => color_map,
            None => unreachable!(),
        };

        for chunk in pixel_data.chunks(self.bytes_per_pixel) {
            let index = bytes_to_index(chunk);
            result.extend(color_map.get(index).iter().map(|&c| c));
        }

        result
    }

    fn read_image_data(&mut self) -> ImageResult<Vec<u8>> {
        // read the pixels from the data region
        let mut pixel_data = if self.image_type.is_encoded() {
            try!(self.read_encoded_data())
        } else {
            let num_raw_bytes = self.width * self.height * self.bytes_per_pixel;
            let mut buf = vec![0; num_raw_bytes];
            try!(self.r.by_ref().read_exact(&mut buf));
            buf
        };

        // expand the indices using the color map if necessary
        if self.image_type.is_color_mapped() {
            pixel_data = self.expand_color_map(pixel_data)
        }

        self.reverse_encoding(&mut pixel_data);
        Ok(pixel_data)
    }

    /// Reads a run length encoded packet
    fn read_encoded_data(&mut self) -> ImageResult<Vec<u8>> {
        let num_bytes = self.width * self.height * self.bytes_per_pixel;
        let mut pixel_data = Vec::with_capacity(num_bytes);

        while pixel_data.len() < num_bytes {
            let run_packet = try!(self.r.read_u8());
            // If the highest bit in `run_packet` is set, then we repeat pixels
            //
            // Note: the TGA format adds 1 to both counts because having a count
            // of 0 would be pointless.
            if (run_packet & 0x80) != 0 {
                // high bit set, so we will repeat the data
                let repeat_count = ((run_packet & !0x80) + 1) as usize;
                let mut data = Vec::with_capacity(self.bytes_per_pixel);
                try!(self.r.by_ref().take(self.bytes_per_pixel as u64).read_to_end(&mut data));
                for _ in 0usize..repeat_count {
                    pixel_data.extend(data.iter().map(|&c| c));
                }
            } else {
                // not set, so `run_packet+1` is the number of non-encoded pixels
                let num_raw_bytes = (run_packet + 1) as usize * self.bytes_per_pixel;
                try!(self.r.by_ref().take(num_raw_bytes as u64).read_to_end(&mut pixel_data));
            }
        }

        Ok(pixel_data)
    }

    /// Reverse from BGR encoding to RGB encoding
    ///
    /// TGA files are stored in the BGRA encoding. This function swaps
    /// the blue and red bytes in the `pixels` array.
    fn reverse_encoding(&mut self, pixels: &mut [u8]) {
        // We only need to reverse the encoding of color images
        match self.color_type {
            ColorType::RGB(8) => {
                for chunk in pixels.chunks_mut(self.bytes_per_pixel) {
                    let r = chunk[0];
                    chunk[0] = chunk[2];
                    chunk[2] = r;
                }
            }
            ColorType::RGBA(8) => {
                for chunk in pixels.chunks_mut(self.bytes_per_pixel) {
                    let r = chunk[0];
                    chunk[0] = chunk[2];
                    chunk[2] = r;
                }
            }
            _ => { }
        }
    }

    /// Flip the image vertically depending on the screen origin bit
    ///
    /// The bit in position 5 of the image descriptor byte is the screen origin bit.
    /// If it's 1, the origin is in the top left corner.
    /// If it's 0, the origin is in the bottom left corner.
    /// This function checks the bit, and if it's 0, flips the image vertically.
    fn flip_vertically(&mut self, pixels: &mut [u8]) {
        let screen_origin_bit = 0b100000 & self.header.image_desc != 0;

        if !screen_origin_bit {
            let num_bytes = pixels.len();

            // Make a copy of the current pixels that we can take values from when flipping.
            let mut pixels_copy = Vec::with_capacity(num_bytes);
            for i in 0..pixels.len() {
                pixels_copy.push(pixels[i]);
            }

            let width_bytes = num_bytes / self.height;

            // Flip the image vertically.
            for vertical_index in 0..self.height {
                let vertical_target = (self.height - vertical_index) * width_bytes - width_bytes;

                for horizontal_index in 0..width_bytes {
                    let source = vertical_index * width_bytes + horizontal_index;
                    let target = vertical_target + horizontal_index;

                    pixels[target] = pixels_copy[source];
                }
            }
        }
    }
}

impl<R: Read + Seek> ImageDecoder for TGADecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        try!(self.read_metadata());

        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<ColorType> {
        try!(self.read_metadata());

        Ok(self.color_type)
    }

    fn row_len(&mut self) -> ImageResult<usize> {
        try!(self.read_metadata());

        Ok(self.bytes_per_pixel * 8 * self.width)
    }

    fn read_scanline(&mut self, _buf: &mut [u8]) -> ImageResult<u32> {
        unimplemented!();
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        try!(self.read_metadata());
        self.read_image_data().map(|v| DecodingResult::U8(v) )
    }
}
<commit_msg>Forgot to actually use the flipping function<commit_after>use std::io;
use std::io::{Read, Seek};
use byteorder::{ReadBytesExt, LittleEndian};

use image::ImageError;
use image::ImageResult;
use image::ImageDecoder;
use image::DecodingResult;
use color::ColorType;

enum ImageType {
    NoImageData = 0,
    /// Uncompressed images
    RawColorMap = 1,
    RawTrueColor = 2,
    RawGrayScale = 3,
    /// Run length encoded images
    RunColorMap = 9,
    RunTrueColor = 10,
    RunGrayScale = 11,
    Unknown,
}

impl ImageType {
    /// Create a new image type from a u8
    fn new(img_type: u8) -> ImageType {
        match img_type {
            0  => ImageType::NoImageData,

            1  => ImageType::RawColorMap,
            2  => ImageType::RawTrueColor,
            3  => ImageType::RawGrayScale,

            9  => ImageType::RunColorMap,
            10 => ImageType::RunTrueColor,
            11 => ImageType::RunGrayScale,

            _  => ImageType::Unknown,
        }
    }

    /// Check if the image format uses colors as opposed to gray scale
    fn is_color(&self) -> bool {
        match *self {
            ImageType::RawColorMap  |
            ImageType::RawTrueColor |
            ImageType::RunTrueColor |
            ImageType::RunColorMap => true,
            _ => false,
        }
    }

    /// Does the image use a color map
    fn is_color_mapped(&self) -> bool {
        match *self {
            ImageType::RawColorMap |
            ImageType::RunColorMap => true,
            _ => false,
        }
    }

    /// Is the image run length encoded
    fn is_encoded(&self) -> bool {
        match *self {
            ImageType::RunColorMap |
            ImageType::RunTrueColor |
            ImageType::RunGrayScale => true,
            _ => false,
        }
    }
}

/// Header used by TGA image files
#[derive(Debug)]
struct Header {
    id_length: u8,         // length of ID string
    map_type: u8,          // color map type
    image_type: u8,        // image type code
    map_origin: u16,       // starting index of map
    map_length: u16,      // length of map
    map_entry_size: u8,    // size of map entries in bits
    x_origin: u16,         // x-origin of image
    y_origin: u16,         // y-origin of image
    image_width: u16,      // width of image
    image_height: u16,     // height of image
    pixel_depth: u8,       // bits per pixel
    image_desc: u8,        // image descriptor
}

impl Header {
    /// Create a header with all valuse set to zero
    fn new() -> Header {
        Header {
            id_length: 0,
            map_type: 0,
            image_type: 0,
            map_origin: 0,
            map_length: 0,
            map_entry_size: 0,
            x_origin: 0,
            y_origin: 0,
            image_width: 0,
            image_height: 0,
            pixel_depth: 0,
            image_desc: 0,
        }
    }

    /// Load the header with values from the reader
    fn from_reader(r: &mut Read) -> ImageResult<Header> {
        Ok(Header {
            id_length:         try!(r.read_u8()),
            map_type:          try!(r.read_u8()),
            image_type:        try!(r.read_u8()),
            map_origin:        try!(r.read_u16::<LittleEndian>()),
            map_length:        try!(r.read_u16::<LittleEndian>()),
            map_entry_size:    try!(r.read_u8()),
            x_origin:          try!(r.read_u16::<LittleEndian>()),
            y_origin:          try!(r.read_u16::<LittleEndian>()),
            image_width:       try!(r.read_u16::<LittleEndian>()),
            image_height:      try!(r.read_u16::<LittleEndian>()),
            pixel_depth:       try!(r.read_u8()),
            image_desc:        try!(r.read_u8()),
        })
    }
}

struct ColorMap {
    /// sizes in bytes
    start_offset: usize,
    entry_size: usize,
    bytes: Vec<u8>,
}

impl ColorMap {
    pub fn from_reader(r: &mut Read,
                       start_offset: u16,
                       num_entries: u16,
                       bits_per_entry: u8)
        -> ImageResult<ColorMap> {
            let bytes_per_entry = (bits_per_entry as usize + 7) / 8;

            let mut bytes = vec![0; bytes_per_entry * num_entries as usize];
            try!(r.read_exact(&mut bytes));

            Ok(ColorMap {
                entry_size: bytes_per_entry,
                start_offset: start_offset as usize,
                bytes: bytes,
            })
        }

    /// Get one entry from the color map
    pub fn get(&self, index: usize) -> &[u8] {
        let entry = self.start_offset + self.entry_size * index;
        &self.bytes[entry..entry + self.entry_size]
    }
}

/// The representation of a TGA decoder
pub struct TGADecoder<R> {
    r: R,

    width: usize,
    height: usize,
    bytes_per_pixel: usize,
    has_loaded_metadata: bool,

    image_type: ImageType,
    color_type: ColorType,

    header: Header,
    color_map: Option<ColorMap>,
}

impl<R: Read + Seek> TGADecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(r: R) -> TGADecoder<R> {
        TGADecoder {
            r: r,

            width: 0,
            height: 0,
            bytes_per_pixel: 0,
            has_loaded_metadata: false,

            image_type: ImageType::Unknown,
            color_type: ColorType::Gray(1),

            header: Header::new(),
            color_map: None,
        }
    }

    fn read_header(&mut self) -> ImageResult<()> {
        self.header = try!(Header::from_reader(&mut self.r));
        self.image_type = ImageType::new(self.header.image_type);
        self.width = self.header.image_width as usize;
        self.height = self.header.image_height as usize;
        self.bytes_per_pixel = (self.header.pixel_depth as usize + 7) / 8;
        Ok(())
    }

    fn read_metadata(&mut self) -> ImageResult<()> {
        if !self.has_loaded_metadata {
            try!(self.read_header());
            try!(self.read_image_id());
            try!(self.read_color_map());
            try!(self.read_color_information());
            self.has_loaded_metadata = true;
        }
        Ok(())
    }

    /// Loads the color information for the decoder
    ///
    /// To keep things simple, we won't handle bit depths that aren't divisible
    /// by 8 and are less than 32.
    fn read_color_information(&mut self) -> ImageResult<()> {
        if self.header.pixel_depth % 8 != 0 {
            return Err(ImageError::UnsupportedError("\
                Bit depth must be divisible by 8".to_string()));
        }
        if self.header.pixel_depth > 32 {
            return Err(ImageError::UnsupportedError("\
                Bit depth must be less than 32".to_string()));
        }

        let num_alpha_bits = self.header.image_desc & 0b1111;

        let other_channel_bits = if self.header.map_type != 0 {
            self.header.map_entry_size
        } else {
            self.header.pixel_depth - num_alpha_bits
        };
        let color = self.image_type.is_color();

        match (num_alpha_bits, other_channel_bits, color) {
            // really, the encoding is BGR and BGRA, this is fixed
            // up with `TGADecoder::reverse_encoding`.
            (8, 24, true) => self.color_type = ColorType::RGBA(8),
            (0, 24, true) => self.color_type = ColorType::RGB(8),
            (8, 8, false) => self.color_type = ColorType::GrayA(8),
            (0, 8, false) => self.color_type = ColorType::Gray(8),
            _ => return Err(ImageError::UnsupportedError(format!("\
                    Color format not supported. Bit depth: {}, Alpha bits: {}",
                    other_channel_bits, num_alpha_bits).to_string())),
        }
        Ok(())
    }

    /// Read the image id field
    ///
    /// We're not interested in this field, so this function skips it if it
    /// is present
    fn read_image_id(&mut self) -> ImageResult<()> {
        try!(self.r.seek(io::SeekFrom::Current(self.header.id_length as i64)));
        Ok(())
    }

    fn read_color_map(&mut self) -> ImageResult<()> {
        if self.header.map_type == 1 {
            self.color_map = Some(try!(
                ColorMap::from_reader(&mut self.r,
                                      self.header.map_origin,
                                      self.header.map_length,
                                      self.header.map_entry_size)));
        }
        Ok(())
    }

    /// Expands indices into its mapped color
    fn expand_color_map(&mut self, pixel_data: Vec<u8>) -> Vec<u8> {
        #[inline]
        fn bytes_to_index(bytes: &[u8]) -> usize {
            let mut result = 0usize;
            for byte in bytes.iter() {
                result = result << 8 | *byte as usize;
            }
            result
        }

        let bytes_per_entry = (self.header.map_entry_size as usize + 7) / 8;
        let mut result = Vec::with_capacity(self.width * self.height *
                                            bytes_per_entry);

        let color_map = match self.color_map {
            Some(ref color_map) => color_map,
            None => unreachable!(),
        };

        for chunk in pixel_data.chunks(self.bytes_per_pixel) {
            let index = bytes_to_index(chunk);
            result.extend(color_map.get(index).iter().map(|&c| c));
        }

        result
    }

    fn read_image_data(&mut self) -> ImageResult<Vec<u8>> {
        // read the pixels from the data region
        let mut pixel_data = if self.image_type.is_encoded() {
            try!(self.read_encoded_data())
        } else {
            let num_raw_bytes = self.width * self.height * self.bytes_per_pixel;
            let mut buf = vec![0; num_raw_bytes];
            try!(self.r.by_ref().read_exact(&mut buf));
            buf
        };

        // expand the indices using the color map if necessary
        if self.image_type.is_color_mapped() {
            pixel_data = self.expand_color_map(pixel_data)
        }

        self.reverse_encoding(&mut pixel_data);

        self.flip_vertically(&mut pixel_data);

        Ok(pixel_data)
    }

    /// Reads a run length encoded packet
    fn read_encoded_data(&mut self) -> ImageResult<Vec<u8>> {
        let num_bytes = self.width * self.height * self.bytes_per_pixel;
        let mut pixel_data = Vec::with_capacity(num_bytes);

        while pixel_data.len() < num_bytes {
            let run_packet = try!(self.r.read_u8());
            // If the highest bit in `run_packet` is set, then we repeat pixels
            //
            // Note: the TGA format adds 1 to both counts because having a count
            // of 0 would be pointless.
            if (run_packet & 0x80) != 0 {
                // high bit set, so we will repeat the data
                let repeat_count = ((run_packet & !0x80) + 1) as usize;
                let mut data = Vec::with_capacity(self.bytes_per_pixel);
                try!(self.r.by_ref().take(self.bytes_per_pixel as u64).read_to_end(&mut data));
                for _ in 0usize..repeat_count {
                    pixel_data.extend(data.iter().map(|&c| c));
                }
            } else {
                // not set, so `run_packet+1` is the number of non-encoded pixels
                let num_raw_bytes = (run_packet + 1) as usize * self.bytes_per_pixel;
                try!(self.r.by_ref().take(num_raw_bytes as u64).read_to_end(&mut pixel_data));
            }
        }

        Ok(pixel_data)
    }

    /// Reverse from BGR encoding to RGB encoding
    ///
    /// TGA files are stored in the BGRA encoding. This function swaps
    /// the blue and red bytes in the `pixels` array.
    fn reverse_encoding(&mut self, pixels: &mut [u8]) {
        // We only need to reverse the encoding of color images
        match self.color_type {
            ColorType::RGB(8) => {
                for chunk in pixels.chunks_mut(self.bytes_per_pixel) {
                    let r = chunk[0];
                    chunk[0] = chunk[2];
                    chunk[2] = r;
                }
            }
            ColorType::RGBA(8) => {
                for chunk in pixels.chunks_mut(self.bytes_per_pixel) {
                    let r = chunk[0];
                    chunk[0] = chunk[2];
                    chunk[2] = r;
                }
            }
            _ => { }
        }
    }

    /// Flip the image vertically depending on the screen origin bit
    ///
    /// The bit in position 5 of the image descriptor byte is the screen origin bit.
    /// If it's 1, the origin is in the top left corner.
    /// If it's 0, the origin is in the bottom left corner.
    /// This function checks the bit, and if it's 0, flips the image vertically.
    fn flip_vertically(&mut self, pixels: &mut [u8]) {
        let screen_origin_bit = 0b100000 & self.header.image_desc != 0;

        if !screen_origin_bit {
            let num_bytes = pixels.len();

            // Make a copy of the current pixels that we can take values from when flipping.
            let mut pixels_copy = Vec::with_capacity(num_bytes);
            for i in 0..pixels.len() {
                pixels_copy.push(pixels[i]);
            }

            let width_bytes = num_bytes / self.height;

            // Flip the image vertically.
            for vertical_index in 0..self.height {
                let vertical_target = (self.height - vertical_index) * width_bytes - width_bytes;

                for horizontal_index in 0..width_bytes {
                    let source = vertical_index * width_bytes + horizontal_index;
                    let target = vertical_target + horizontal_index;

                    pixels[target] = pixels_copy[source];
                }
            }
        }
    }
}

impl<R: Read + Seek> ImageDecoder for TGADecoder<R> {
    fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
        try!(self.read_metadata());

        Ok((self.width as u32, self.height as u32))
    }

    fn colortype(&mut self) -> ImageResult<ColorType> {
        try!(self.read_metadata());

        Ok(self.color_type)
    }

    fn row_len(&mut self) -> ImageResult<usize> {
        try!(self.read_metadata());

        Ok(self.bytes_per_pixel * 8 * self.width)
    }

    fn read_scanline(&mut self, _buf: &mut [u8]) -> ImageResult<u32> {
        unimplemented!();
    }

    fn read_image(&mut self) -> ImageResult<DecodingResult> {
        try!(self.read_metadata());
        self.read_image_data().map(|v| DecodingResult::U8(v) )
    }
}
<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/_template_procedural_macro_meta/latest/_template_procedural_macro_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! Protocol of modularity unifying interface of a module.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

mod impls;

///
/// Protocol of modularity unifying interface of a module.
///

#[ proc_macro ]
pub fn procedural_macro( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = impls::impls( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<commit_msg>fixing meta modules<commit_after>// #![ cfg_attr( not( feature = "use_std" ), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/_template_procedural_macro_meta/latest/_template_procedural_macro_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! Protocol of modularity unifying interface of a module.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

mod impls;

///
/// Protocol of modularity unifying interface of a module.
///

#[ proc_macro ]
pub fn procedural_macro( input : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let result = impls::impls( input );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<|endoftext|>


<commit_before>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::IntValue;

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let AnyTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let AnyTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_function_type(self) -> bool {
        if let AnyTypeEnum::FunctionType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let AnyTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let AnyTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let AnyTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let AnyTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_void_type(self) -> bool {
        if let AnyTypeEnum::VoidType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let BasicTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let BasicTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let BasicTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let BasicTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let BasicTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let BasicTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<commit_msg>Add BasicTypeEnum::const_zero.<commit_after>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let AnyTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let AnyTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_function_type(self) -> bool {
        if let AnyTypeEnum::FunctionType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let AnyTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let AnyTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let AnyTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let AnyTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_void_type(self) -> bool {
        if let AnyTypeEnum::VoidType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let BasicTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let BasicTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let BasicTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let BasicTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let BasicTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let BasicTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    /// Creates a constant `BasicValueZero`.
    ///
    /// # Example
    /// ```
    /// use inkwell::context::Context;
    /// use crate::inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type().as_basic_type_enum();
    /// let f32_zero = f32_type.const_zero();
    /// ```
    pub fn const_zero(self) -> BasicValueEnum<'ctx> {
        match self {
            BasicTypeEnum::ArrayType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::FloatType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::IntType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::PointerType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::StructType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::VectorType(ty) => ty.const_zero().as_basic_value_enum(),
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<|endoftext|>