<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use memory::PAddr;
use core::fmt;
use super::ElfResult;

// Distinguished section indices.
pub const SHN_UNDEF: u16        = 0;
pub const SHN_LORESERVE: u16    = 0xff00;
pub const SHN_LOPROC: u16       = 0xff00;
pub const SHN_HIPROC: u16       = 0xff1f;
pub const SHN_LOOS: u16         = 0xff20;
pub const SHN_HIOS: u16         = 0xff3f;
pub const SHN_ABS: u16          = 0xfff1;
pub const SHN_COMMON: u16       = 0xfff2;
pub const SHN_XINDEX: u16       = 0xffff;
pub const SHN_HIRESERVE: u16    = 0xffff;

pub const SHT_LOOS: u32   = 0x60000000;
pub const SHT_HIOS: u32   = 0x6fffffff;
pub const SHT_LOPROC: u32 = 0x70000000;
pub const SHT_HIPROC: u32 = 0x7fffffff;
pub const SHT_LOUSER: u32 = 0x80000000;
pub const SHT_HIUSER: u32 = 0xffffffff;

/// Represents an ELF section header
///
/// Refer to the [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Clone, Copy, Debug)]
pub enum Header<'a> {
    ThirtyTwo(&'a HeaderRepr<u32>)
  , SixtyFour(&'a HeaderRepr<u64>)
}

#[derive(Debug)]
#[repr(C)]
pub struct HeaderRepr<Word> {
    /// This member specifies the name of the section.
    ///
    /// Its value is an index into the section header string table section,
    /// giving the location of a null-terminated string.
    name_offset: u32
  , /// This member categorizes the section's contents and semantics.
    ty: TypeRepr
  , flags: Flags
  , address: Word
  , offset: Word
  , length: Word
  , link: u32
  , info: u32
  , address_align: Word
  , entry_length: Word
}

pub trait AsHeader {
    fn as_header(&self) -> Header;
}

impl AsHeader for HeaderRepr<u32> {
    #[inline] fn as_header(&self) -> Header {
        Header::ThirtyTwo(self)
    }
}

impl AsHeader for HeaderRepr<u64> {
    #[inline] fn as_header(&self) -> Header {
        Header::SixtyFour(self)
    }
}

bitflags! {
    pub flags Flags: usize {
        // Flags (SectionHeader::flags)
        const SHF_WRITE            =        0x1
      , const SHF_ALLOC            =        0x2
      , const SHF_EXECINSTR        =        0x4
      , const SHF_MERGE            =       0x10
      , const SHF_STRINGS          =       0x20
      , const SHF_INFO_LINK        =       0x40
      , const SHF_LINK_ORDER       =       0x80
      , const SHF_OS_NONCONFORMING =      0x100
      , const SHF_GROUP            =      0x200
      , const SHF_TLS              =      0x400
      , const SHF_COMPRESSED       =      0x800
      , const SHF_MASKOS           = 0x0ff00000
      , const SHF_MASKPROC         = 0xf0000000
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bits.fmt(f)
    }
}

bitflags! {
    pub flags GroupFlags: u32 {
        const GRP_COMDAT	=        0x1
      , const GRP_MASKOS	= 0x0ff00000
      , const GRP_MASKPROC	= 0xf0000000
    }
}

macro_rules! get {
    ($s: expr, $name: ident) => {
        match *$s {
            Header::ThirtyTwo(x) => x.$name
          , Header::SixtyFour(x) => x.$name
        }
    }
}

macro_rules! impl_getters {
    ( pub $name: ident : $ty: ident, $( $rest: tt )* ) => {
        #[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
        impl_getters!{ $( $rest )* }
    };
    ( $name: ident : $ty: ident,  $( $rest: tt )* ) => {
        #[inline] fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
        impl_getters!{ $( $rest )* }
    };
    ( $name: ident : $ty: ident ) => {
        #[inline] fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
    };
    ( pub $name: ident : $ty: ident ) => {
        #[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
    };
}

impl<'a> Header<'a> {
    impl_getters! { address: u64
                  , pub offset: u64
                  , pub length: u64
                  , pub link: u32
                  , pub info: u32
                  , pub address_align: u64
                  , pub entry_length: u64
                  }

    /// Returns the start address of this section
    #[inline] pub fn addr(&self) -> PAddr { PAddr::from(self.address()) }

    /// Returns the end address of this section
    #[inline] pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.address() + self.length())
    }

    /// Returns the type of this section
    #[inline] pub fn flags(&self) -> Flags { get!(self, flags) }

    /// Returns the type of this section
    #[inline] pub fn get_type(&self) -> ElfResult<Type> {
         get!(self, ty).as_type()
     }

    /// Returns true if this section is writable.
    #[inline] pub fn is_writable(&self) -> bool {
        get!(self, flags).contains(SHF_WRITE)
    }

    /// Returns true if this section occupies memory during program execution.
    #[inline] pub fn is_allocated(&self) -> bool {
        get!(self, flags).contains(SHF_ALLOC)
    }

    /// Returns true if this section contains executable instructions.
    #[inline] pub fn is_executable(&self) -> bool {
        get!(self, flags).contains(SHF_EXECINSTR)
    }

    /// Returns true if this section can be merged.
    #[inline] pub fn is_mergeable(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE)
    }

    /// Returns true if this section contains data that is of a uniform size.
    #[inline] pub fn is_uniform(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE) &&
        !get!(self, flags).contains(SHF_STRINGS)
    }
}

pub enum Contents<'a> {
    Empty
  , Undefined(&'a [u8])
  , Group { flags: &'a u32
          , indicies: &'a[u32] }
}

/// Underlying representation of a section header type field
///
/// Unfortunately, we cannot have enums with open ranges yet, so we have
/// to convert between the ELF file underlying representation and our
/// type-safe representation.
#[derive(Debug, Copy, Clone)]
struct TypeRepr(u32);

impl TypeRepr {
    #[inline] fn as_type(&self) -> ElfResult<Type> {
        match self.0 {
            0 => Ok(Type::Null)
          , 1 => Ok(Type::ProgramBits)
          , 2 => Ok(Type::SymbolTable)
          , 3 => Ok(Type::StringTable)
          , 4 => Ok(Type::Rela)
          , 5 => Ok(Type::HashTable)
          , 6 => Ok(Type::Dynamic)
          , 7 => Ok(Type::Notes)
          , 8 => Ok(Type::NoBits)
          , 9 => Ok(Type::Rel)
          , 10 => Ok(Type::Shlib)
          , 11 => Ok(Type::DynSymTable)
          , 14 => Ok(Type::InitArray)
          , 15 => Ok(Type::FiniArray)
          , 16 => Ok(Type::PreInitArray)
          , x @ SHT_LOOS ... SHT_HIOS => Ok(Type::OsSpecific(x))
          , x @ SHT_LOPROC ... SHT_HIPROC => Ok(Type::ProcessorSpecific(x))
          , x @ SHT_LOUSER ... SHT_HIUSER => Ok(Type::User(x))
          , _ => Err("Invalid section type!")
        }
    }
}

/// Enum representing an ELF file section type.
///
/// Refer to Figure 1-10: "Section Types, `sh_type`" in Section 1 of the
/// [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable
  , InitArray
  , FiniArray
  , PreInitArray
  , Group
  , SymbolTableShIndex
  , OsSpecific(u32)
  , ProcessorSpecific(u32)
  , User(u32)
}

/// Iterator over ELF64 sections
#[derive(Clone,Debug)]
pub struct Sections<'a, W: 'a> { curr: &'a HeaderRepr<W>
                               , remaining: u32
                               , size: u32
                               }

impl<'a, W: 'a> Sections<'a, W> {

    pub fn new(curr: &'a HeaderRepr<W>, remaining: u32, size: u32)
               -> Sections<'a, W>
    {
        Sections { curr: curr, remaining: remaining, size: size }

    }

}

impl<'a, W> Iterator for Sections<'a, W>
where HeaderRepr<W>: AsHeader {
    type Item = Header<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            let current = self.curr.as_header();
            self.curr = unsafe {
                &*(((self.curr as *const HeaderRepr<W>) as u32 + self.size)
                    as *const HeaderRepr<W>)
            };
            self.remaining -= 1;
            if current.get_type().unwrap() == Type::Null {
                self.next()
            } else {
                Some(current)
            }
        }
    }
}
<commit_msg>chore(elf): add documentation to some ELF section header bits<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use memory::PAddr;
use core::fmt;
use super::ElfResult;

// Distinguished section indices.
pub const SHN_UNDEF: u16        = 0;
pub const SHN_LORESERVE: u16    = 0xff00;
pub const SHN_LOPROC: u16       = 0xff00;
pub const SHN_HIPROC: u16       = 0xff1f;
pub const SHN_LOOS: u16         = 0xff20;
pub const SHN_HIOS: u16         = 0xff3f;
pub const SHN_ABS: u16          = 0xfff1;
pub const SHN_COMMON: u16       = 0xfff2;
pub const SHN_XINDEX: u16       = 0xffff;
pub const SHN_HIRESERVE: u16    = 0xffff;

pub const SHT_LOOS: u32   = 0x60000000;
pub const SHT_HIOS: u32   = 0x6fffffff;
pub const SHT_LOPROC: u32 = 0x70000000;
pub const SHT_HIPROC: u32 = 0x7fffffff;
pub const SHT_LOUSER: u32 = 0x80000000;
pub const SHT_HIUSER: u32 = 0xffffffff;

/// Represents an ELF section header
///
/// Refer to [Figure 4-8], "Section Header", from Chapter 4 of the ELF standard
/// for more information.
///
/// [Figure 4-8]: (http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_header)
#[derive(Clone, Copy, Debug)]
pub enum Header<'a> {
    ThirtyTwo(&'a HeaderRepr<u32>)
  , SixtyFour(&'a HeaderRepr<u64>)
}

/// Raw representation of an ELF section header in an ELF binary.
///
/// Refer to [Figure 4-8], "Section Header", from Chapter 4 of the ELF standard
/// for more information.
///
/// [Figure 4-8]: (http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_header)
//  TODO: add docs for all fields!
//          - eliza, 03/05/2017
#[derive(Debug)]
#[repr(C)]
pub struct HeaderRepr<Word> {
    /// This member specifies the name of the section.
    ///
    /// Its value is an index into the section header string table section,
    /// giving the location of a null-terminated string.
    //  TODO: this should be a Word, not a 32-bit word.
    //          - eliza, 03/05/2017
    name_offset: u32
  , /// This member categorizes the section's contents and semantics.
    ty: TypeRepr
  , flags: Flags
  , address: Word
  , offset: Word
  , length: Word
  , link: u32
  , info: u32
  , address_align: Word
  , entry_length: Word
}

pub trait AsHeader {
    fn as_header(&self) -> Header;
}

impl AsHeader for HeaderRepr<u32> {
    #[inline] fn as_header(&self) -> Header {
        Header::ThirtyTwo(self)
    }
}

impl AsHeader for HeaderRepr<u64> {
    #[inline] fn as_header(&self) -> Header {
        Header::SixtyFour(self)
    }
}

bitflags! {
    pub flags Flags: usize {
        // Flags (SectionHeader::flags)
        const SHF_WRITE            =        0x1
      , const SHF_ALLOC            =        0x2
      , const SHF_EXECINSTR        =        0x4
      , const SHF_MERGE            =       0x10
      , const SHF_STRINGS          =       0x20
      , const SHF_INFO_LINK        =       0x40
      , const SHF_LINK_ORDER       =       0x80
      , const SHF_OS_NONCONFORMING =      0x100
      , const SHF_GROUP            =      0x200
      , const SHF_TLS              =      0x400
      , const SHF_COMPRESSED       =      0x800
      , const SHF_MASKOS           = 0x0ff00000
      , const SHF_MASKPROC         = 0xf0000000
    }
}

impl fmt::LowerHex for Flags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.bits.fmt(f)
    }
}

bitflags! {
    pub flags GroupFlags: u32 {
        const GRP_COMDAT	=        0x1
      , const GRP_MASKOS	= 0x0ff00000
      , const GRP_MASKPROC	= 0xf0000000
    }
}

macro_rules! get {
    ($s: expr, $name: ident) => {
        match *$s {
            Header::ThirtyTwo(x) => x.$name
          , Header::SixtyFour(x) => x.$name
        }
    }
}

macro_rules! impl_getters {
    ( pub $name: ident : $ty: ident, $( $rest: tt )* ) => {
        #[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
        impl_getters!{ $( $rest )* }
    };
    ( $name: ident : $ty: ident,  $( $rest: tt )* ) => {
        #[inline] fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
        impl_getters!{ $( $rest )* }
    };
    ( $name: ident : $ty: ident ) => {
        #[inline] fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
    };
    ( pub $name: ident : $ty: ident ) => {
        #[inline] pub fn $name(&self) -> $ty {
            match *self {
                Header::ThirtyTwo(x) => x.$name as $ty
              , Header::SixtyFour(x) => x.$name as $ty
            }
        }
    };
}

impl<'a> Header<'a> {
    impl_getters! { address: u64
                  , pub offset: u64
                  , pub length: u64
                  , pub link: u32
                  , pub info: u32
                  , pub address_align: u64
                  , pub entry_length: u64
                  }

    /// Returns the start address of this section
    #[inline] pub fn addr(&self) -> PAddr { PAddr::from(self.address()) }

    /// Returns the end address of this section
    #[inline] pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.address() + self.length())
    }

    /// Returns the type of this section
    #[inline] pub fn flags(&self) -> Flags { get!(self, flags) }

    /// Returns the type of this section
    #[inline] pub fn get_type(&self) -> ElfResult<Type> {
         get!(self, ty).as_type()
     }

    /// Returns true if this section is writable.
    #[inline] pub fn is_writable(&self) -> bool {
        get!(self, flags).contains(SHF_WRITE)
    }

    /// Returns true if this section occupies memory during program execution.
    #[inline] pub fn is_allocated(&self) -> bool {
        get!(self, flags).contains(SHF_ALLOC)
    }

    /// Returns true if this section contains executable instructions.
    #[inline] pub fn is_executable(&self) -> bool {
        get!(self, flags).contains(SHF_EXECINSTR)
    }

    /// Returns true if this section can be merged.
    #[inline] pub fn is_mergeable(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE)
    }

    /// Returns true if this section contains data that is of a uniform size.
    #[inline] pub fn is_uniform(&self) -> bool {
        get!(self, flags).contains(SHF_MERGE) &&
        !get!(self, flags).contains(SHF_STRINGS)
    }
}

pub enum Contents<'a> {
    Empty
  , Undefined(&'a [u8])
  , Group { flags: &'a u32
          , indicies: &'a[u32] }
}

/// Underlying representation of a section header type field
///
/// Unfortunately, we cannot have enums with open ranges yet, so we have
/// to convert between the ELF file underlying representation and our
/// type-safe representation.
///
/// Refer to [Figure 4-9]: "Section Types, `sh_type`" in Section 4 of the
/// ELF standard for more information.
///
/// [Figure 4-9]:  http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type
#[derive(Debug, Copy, Clone)]
struct TypeRepr(u32);

impl TypeRepr {
    #[inline] fn as_type(&self) -> ElfResult<Type> {
        match self.0 {
            0 => Ok(Type::Null)
          , 1 => Ok(Type::ProgramBits)
          , 2 => Ok(Type::SymbolTable)
          , 3 => Ok(Type::StringTable)
          , 4 => Ok(Type::Rela)
          , 5 => Ok(Type::HashTable)
          , 6 => Ok(Type::Dynamic)
          , 7 => Ok(Type::Notes)
          , 8 => Ok(Type::NoBits)
          , 9 => Ok(Type::Rel)
          , 10 => Ok(Type::Shlib)
          , 11 => Ok(Type::DynSymTable)
          , 14 => Ok(Type::InitArray)
          , 15 => Ok(Type::FiniArray)
          , 16 => Ok(Type::PreInitArray)
          , x @ SHT_LOOS ... SHT_HIOS => Ok(Type::OsSpecific(x))
          , x @ SHT_LOPROC ... SHT_HIPROC => Ok(Type::ProcessorSpecific(x))
          , x @ SHT_LOUSER ... SHT_HIUSER => Ok(Type::User(x))
          , _ => Err("Invalid section type!")
        }
    }
}

/// Enum representing an ELF file section type.
///
/// Refer to [Figure 4-9]: "Section Types, `sh_type`" in Section 4 of the
/// ELF standard for more information.
///
/// [Figure 4-9]:  http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable
  , InitArray
  , FiniArray
  , PreInitArray
  , Group
  , SymbolTableShIndex
  , OsSpecific(u32)
  , ProcessorSpecific(u32)
  , User(u32)
}

/// Iterator over ELF64 sections
#[derive(Clone,Debug)]
pub struct Sections<'a, W: 'a> { curr: &'a HeaderRepr<W>
                               , remaining: u32
                               , size: u32
                               }

impl<'a, W: 'a> Sections<'a, W> {

    pub fn new(curr: &'a HeaderRepr<W>, remaining: u32, size: u32)
               -> Sections<'a, W>
    {
        Sections { curr: curr, remaining: remaining, size: size }

    }

}

impl<'a, W> Iterator for Sections<'a, W>
where HeaderRepr<W>: AsHeader {
    type Item = Header<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            let current = self.curr.as_header();
            self.curr = unsafe {
                // TODO: we should be able to use ptr::offset() here?
                //          - eliza, 03/05/2017
                &*(((self.curr as *const HeaderRepr<W>) as u32 + self.size)
                    as *const HeaderRepr<W>)
            };
            self.remaining -= 1;
            if current.get_type().unwrap() == Type::Null {
                self.next()
            } else {
                Some(current)
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Mul;
use std::io;
use std::net;
use std::string::FromUtf8Error;
use uuid;
use super::*;
use FromCursor;

// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L813

// Decodes Cassandra `ascii` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_custom(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `ascii` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_ascii(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `varchar` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_varchar(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `bigint` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_bigint(bytes: &[u8]) -> Result<i64, io::Error> {
    try_from_bytes(bytes).map(|i| i as i64)
}

// Decodes Cassandra `blob` data (bytes) into Rust's `Result<Vec<u8>, io::Error>`
pub fn decode_blob(bytes: Vec<u8>) -> Result<Vec<u8>, io::Error> {
    // in fact we just pass it through.
    Ok(bytes)
}

// Decodes Cassandra `boolean` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_boolean(bytes: &[u8]) -> Result<bool, io::Error> {
    let false_byte: u8 = 0;
    if bytes.is_empty() {
        Err(io::Error::new(io::ErrorKind::UnexpectedEof, "no bytes were found"))
    } else {
        Ok(bytes[0] != false_byte)
    }
}

// Decodes Cassandra `int` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_int(bytes: &[u8]) -> Result<i32, io::Error> {
    try_from_bytes(bytes).map(|i| i as i32)
}

// Decodes Cassandra `date` data (bytes) into Rust's `Result<i32, io::Error>` in following way
//    0: -5877641-06-23
// 2^31: 1970-1-1
// 2^32: 5881580-07-11
pub fn decode_date(bytes: &[u8]) -> Result<i32, io::Error> {
    try_from_bytes(bytes).map(|i| i as i32)
}

// TODO: make sure this method meets the specification.
// Decodes Cassandra `decimal` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_decimal(bytes: &[u8]) -> Result<f32, io::Error> {
    let ref separator = b'E';
    let lr: Vec<Vec<u8>> = bytes.split(|ch| ch == separator).map(|p| p.to_vec()).collect();
    let unscaled = try_i_from_bytes(lr[0].as_slice());
    if unscaled.is_err() {
        return Err(unscaled.unwrap_err());
    }
    let scaled = try_i_from_bytes(lr[1].as_slice());
    if scaled.is_err() {
        return Err(scaled.unwrap_err());
    }

    let unscaled_unwrapped: f32 = unscaled.unwrap() as f32;
    let scaled_unwrapped: i32 = scaled.unwrap() as i32;
    let dec: f32 = 10.0;
    Ok(unscaled_unwrapped.mul(dec.powi(scaled_unwrapped)))
}

// Decodes Cassandra `double` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_double(bytes: &[u8]) -> Result<f64, io::Error> {
    try_f64_from_bytes(bytes)
}

// Decodes Cassandra `float` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_float(bytes: &[u8]) -> Result<f32, io::Error> {
    try_f32_from_bytes(bytes)
}

// Decodes Cassandra `inet` data (bytes) into Rust's `Result<net::IpAddr, io::Error>`
pub fn decode_inet(bytes: &[u8]) -> Result<net::IpAddr, io::Error> {
    match bytes.len() {
        // v4
        4 => Ok(net::IpAddr::V4(net::Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))),
        // v6
        16 => {
            let a = from_u16_bytes(&bytes[0..2]);
            let b = from_u16_bytes(&bytes[2..4]);
            let c = from_u16_bytes(&bytes[4..6]);
            let d = from_u16_bytes(&bytes[6..8]);
            let e = from_u16_bytes(&bytes[8..10]);
            let f = from_u16_bytes(&bytes[10..12]);
            let g = from_u16_bytes(&bytes[12..14]);
            let h = from_u16_bytes(&bytes[14..16]);
            Ok(net::IpAddr::V6(net::Ipv6Addr::new(a, b, c, d, e, f, g, h)))
        }
        _ => unreachable!(),
    }
}

// Decodes Cassandra `timestamp` data (bytes) into Rust's `Result<i64, io::Error>`
// `i32` represets a millisecond-precision
//  offset from the unix epoch (00:00:00, January 1st, 1970).  Negative values
//  represent a negative offset from the epoch.
pub fn decode_timestamp(bytes: &[u8]) -> Result<i64, io::Error> {
    try_from_bytes(bytes).map(|i| i as i64)
}

// Decodes Cassandra `list` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
pub fn decode_list(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

// Decodes Cassandra `set` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
pub fn decode_set(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

// Decodes Cassandra `map` data (bytes) into Rust's `Result<Vec<(CBytes, CBytes)>, io::Error>`
pub fn decode_map(bytes: &[u8]) -> Result<Vec<(CBytes, CBytes)>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l)
        .map(|_| (CBytes::from_cursor(&mut cursor), CBytes::from_cursor(&mut cursor)))
        .collect();
    Ok(list)
}

// Decodes Cassandra `smallint` data (bytes) into Rust's `Result<i16, io::Error>`
pub fn decode_smallint(bytes: &[u8]) -> Result<i16, io::Error> {
    try_from_bytes(bytes).map(|i| i as i16)
}

// Decodes Cassandra `tinyint` data (bytes) into Rust's `Result<i8, io::Error>`
pub fn decode_tinyint(bytes: &[u8]) -> Result<i8, io::Error> {
    Ok(bytes[0] as i8)
}

// Decodes Cassandra `text` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_text(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `time` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_time(bytes: &[u8]) -> Result<i64, io::Error> {
    try_i_from_bytes(bytes)
}

// Decodes Cassandra `timeuuid` data (bytes) into Rust's `Result<uuid::Uuid, uuid::ParseError>`
pub fn decode_timeuuid(bytes: &[u8]) -> Result<uuid::Uuid, uuid::ParseError> {
    uuid::Uuid::from_bytes(bytes)
}

// Decodes Cassandra `varint` data (bytes) into Rust's `Result<i64, io::Error>`
pub fn decode_varint(bytes: &[u8]) -> Result<i64, io::Error> {
    try_i_from_bytes(bytes)
}

// Decodes Cassandra `Udt` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
// each `CBytes` is encoded type of field of user defined type
pub fn decode_udt(bytes: &[u8], l: usize) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

/// Decodes any Cassandra data type into the corresponding Rust type,
/// given the column type as `ColTypeOption` and the value as `CBytes`
/// plus the matching Rust type.
macro_rules! as_rust {
    ($data_type_option:ident, $data_value:ident, Vec<u8>) => (
        match $data_type_option.id {
            ColType::Blob => {
                decode_blob($data_value.as_plain()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, String) => (
        match $data_type_option.id {
            ColType::Custom => {
                decode_custom($data_value.as_slice()).unwrap()
            }
            ColType::Ascii => {
                decode_ascii($data_value.as_slice()).unwrap()
            }
            ColType::Varchar => {
                decode_varchar($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, bool) => (
        match $data_type_option.id {
            ColType::Boolean => {
                decode_boolean($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i64) => (
        match $data_type_option.id {
            ColType::Bigint => {
                decode_bigint($data_value.as_slice()).unwrap()
            }
            ColType::Timestamp => {
                decode_timestamp($data_value.as_slice()).unwrap()
            }
            ColType::Time => {
                decode_time($data_value.as_slice()).unwrap()
            }
            ColType::Varint => {
                decode_varint($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i32) => (
        match $data_type_option.id {
            ColType::Int => {
                decode_int($data_value.as_slice()).unwrap()
            }
            ColType::Date => {
                decode_date($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i16) => (
        match $data_type_option.id {
            ColType::Smallint => {
                decode_smallint($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i8) => (
        match $data_type_option.id {
            ColType::Tinyint => {
                decode_tinyint($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, f64) => (
        match $data_type_option.id {
            ColType::Double => {
                decode_double($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, f32) => (
        match $data_type_option.id {
            ColType::Decimal => {
                decode_decimal($data_value.as_slice()).unwrap()
            }
            ColType::Float => {
                decode_float($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, IpAddr) => (
        match $data_type_option.id {
            ColType::Inet => {
                decode_inet($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, Uuid) => (
        match $data_type_option.id {
            ColType::Uuid => {
                decode_timeuuid($data_value.as_slice()).unwrap()
            }
            ColType::Timeuuid => {
                decode_timeuuid($data_value.as_slice()).unwrap()
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, List) => (
        match $data_type_option.id {
            ColType::List => {
                List::new(decode_list($data_value.as_slice()).unwrap(),
                    $data_type_option.as_ref().clone())
            }
            ColType::Set => {
                List::new(decode_list($data_value.as_slice()).unwrap(),
                    $data_type_option.as_ref().clone())
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, Map) => (
        match $data_type_option.id {
            ColType::Map => {
                Map::new(decode_map($data_value.as_slice()).unwrap(),
                    $data_type_option.as_ref().clone())
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, UDT) => (
        match *$data_type_option {
            ColTypeOption {
                id: ColType::Udt,
                value: Some(ColTypeOptionValue::UdtType(ref list_type_option))
            } => {
                UDT::new(decode_udt($data_value.as_slice(),
                    list_type_option.descriptions.len()).unwrap(), list_type_option)
            }
            _ => unreachable!()
        }
    );
}
<commit_msg>Return errors in as_rust! instead of using unwrap<commit_after>use std::ops::Mul;
use std::io;
use std::net;
use std::string::FromUtf8Error;
use uuid;
use super::*;
use FromCursor;

// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L813

// Decodes Cassandra `ascii` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_custom(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `ascii` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_ascii(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `varchar` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_varchar(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `bigint` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_bigint(bytes: &[u8]) -> Result<i64, io::Error> {
    try_from_bytes(bytes).map(|i| i as i64)
}

// Decodes Cassandra `blob` data (bytes) into Rust's `Result<Vec<u8>, io::Error>`
pub fn decode_blob(bytes: Vec<u8>) -> Result<Vec<u8>, io::Error> {
    // in fact we just pass it through.
    Ok(bytes)
}

// Decodes Cassandra `boolean` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_boolean(bytes: &[u8]) -> Result<bool, io::Error> {
    let false_byte: u8 = 0;
    if bytes.is_empty() {
        Err(io::Error::new(io::ErrorKind::UnexpectedEof, "no bytes were found"))
    } else {
        Ok(bytes[0] != false_byte)
    }
}

// Decodes Cassandra `int` data (bytes) into Rust's `Result<i32, io::Error>`
pub fn decode_int(bytes: &[u8]) -> Result<i32, io::Error> {
    try_from_bytes(bytes).map(|i| i as i32)
}

// Decodes Cassandra `date` data (bytes) into Rust's `Result<i32, io::Error>` in following way
//    0: -5877641-06-23
// 2^31: 1970-1-1
// 2^32: 5881580-07-11
pub fn decode_date(bytes: &[u8]) -> Result<i32, io::Error> {
    try_from_bytes(bytes).map(|i| i as i32)
}

// TODO: make sure this method meets the specification.
// Decodes Cassandra `decimal` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_decimal(bytes: &[u8]) -> Result<f32, io::Error> {
    let ref separator = b'E';
    let lr: Vec<Vec<u8>> = bytes.split(|ch| ch == separator).map(|p| p.to_vec()).collect();
    let unscaled = try_i_from_bytes(lr[0].as_slice());
    if unscaled.is_err() {
        return Err(unscaled.unwrap_err());
    }
    let scaled = try_i_from_bytes(lr[1].as_slice());
    if scaled.is_err() {
        return Err(scaled.unwrap_err());
    }

    let unscaled_unwrapped: f32 = unscaled.unwrap() as f32;
    let scaled_unwrapped: i32 = scaled.unwrap() as i32;
    let dec: f32 = 10.0;
    Ok(unscaled_unwrapped.mul(dec.powi(scaled_unwrapped)))
}

// Decodes Cassandra `double` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_double(bytes: &[u8]) -> Result<f64, io::Error> {
    try_f64_from_bytes(bytes)
}

// Decodes Cassandra `float` data (bytes) into Rust's `Result<f32, io::Error>`
pub fn decode_float(bytes: &[u8]) -> Result<f32, io::Error> {
    try_f32_from_bytes(bytes)
}

// Decodes Cassandra `inet` data (bytes) into Rust's `Result<net::IpAddr, io::Error>`
pub fn decode_inet(bytes: &[u8]) -> Result<net::IpAddr, io::Error> {
    match bytes.len() {
        // v4
        4 => Ok(net::IpAddr::V4(net::Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))),
        // v6
        16 => {
            let a = from_u16_bytes(&bytes[0..2]);
            let b = from_u16_bytes(&bytes[2..4]);
            let c = from_u16_bytes(&bytes[4..6]);
            let d = from_u16_bytes(&bytes[6..8]);
            let e = from_u16_bytes(&bytes[8..10]);
            let f = from_u16_bytes(&bytes[10..12]);
            let g = from_u16_bytes(&bytes[12..14]);
            let h = from_u16_bytes(&bytes[14..16]);
            Ok(net::IpAddr::V6(net::Ipv6Addr::new(a, b, c, d, e, f, g, h)))
        }
        _ => unreachable!(),
    }
}

// Decodes Cassandra `timestamp` data (bytes) into Rust's `Result<i64, io::Error>`
// `i32` represets a millisecond-precision
//  offset from the unix epoch (00:00:00, January 1st, 1970).  Negative values
//  represent a negative offset from the epoch.
pub fn decode_timestamp(bytes: &[u8]) -> Result<i64, io::Error> {
    try_from_bytes(bytes).map(|i| i as i64)
}

// Decodes Cassandra `list` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
pub fn decode_list(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

// Decodes Cassandra `set` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
pub fn decode_set(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

// Decodes Cassandra `map` data (bytes) into Rust's `Result<Vec<(CBytes, CBytes)>, io::Error>`
pub fn decode_map(bytes: &[u8]) -> Result<Vec<(CBytes, CBytes)>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let l = CInt::from_cursor(&mut cursor);
    let list = (0..l)
        .map(|_| (CBytes::from_cursor(&mut cursor), CBytes::from_cursor(&mut cursor)))
        .collect();
    Ok(list)
}

// Decodes Cassandra `smallint` data (bytes) into Rust's `Result<i16, io::Error>`
pub fn decode_smallint(bytes: &[u8]) -> Result<i16, io::Error> {
    try_from_bytes(bytes).map(|i| i as i16)
}

// Decodes Cassandra `tinyint` data (bytes) into Rust's `Result<i8, io::Error>`
pub fn decode_tinyint(bytes: &[u8]) -> Result<i8, io::Error> {
    Ok(bytes[0] as i8)
}

// Decodes Cassandra `text` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_text(bytes: &[u8]) -> Result<String, FromUtf8Error> {
    Ok(String::from_utf8_lossy(bytes).into_owned())
}

// Decodes Cassandra `time` data (bytes) into Rust's `Result<String, FromUtf8Error>`.
pub fn decode_time(bytes: &[u8]) -> Result<i64, io::Error> {
    try_i_from_bytes(bytes)
}

// Decodes Cassandra `timeuuid` data (bytes) into Rust's `Result<uuid::Uuid, uuid::ParseError>`
pub fn decode_timeuuid(bytes: &[u8]) -> Result<uuid::Uuid, uuid::ParseError> {
    uuid::Uuid::from_bytes(bytes)
}

// Decodes Cassandra `varint` data (bytes) into Rust's `Result<i64, io::Error>`
pub fn decode_varint(bytes: &[u8]) -> Result<i64, io::Error> {
    try_i_from_bytes(bytes)
}

// Decodes Cassandra `Udt` data (bytes) into Rust's `Result<Vec<CBytes>, io::Error>`
// each `CBytes` is encoded type of field of user defined type
pub fn decode_udt(bytes: &[u8], l: usize) -> Result<Vec<CBytes>, io::Error> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
    let list = (0..l).map(|_| CBytes::from_cursor(&mut cursor)).collect();
    Ok(list)
}

/// Decodes any Cassandra data type into the corresponding Rust type,
/// given the column type as `ColTypeOption` and the value as `CBytes`
/// plus the matching Rust type.
macro_rules! as_rust {
    ($data_type_option:ident, $data_value:ident, Vec<u8>) => (
        match $data_type_option.id {
            ColType::Blob => {
                decode_blob($data_value.as_plain())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, String) => (
        match $data_type_option.id {
            ColType::Custom => {
                decode_custom($data_value.as_slice())?
            }
            ColType::Ascii => {
                decode_ascii($data_value.as_slice())?
            }
            ColType::Varchar => {
                decode_varchar($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, bool) => (
        match $data_type_option.id {
            ColType::Boolean => {
                decode_boolean($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i64) => (
        match $data_type_option.id {
            ColType::Bigint => {
                decode_bigint($data_value.as_slice())?
            }
            ColType::Timestamp => {
                decode_timestamp($data_value.as_slice())?
            }
            ColType::Time => {
                decode_time($data_value.as_slice())?
            }
            ColType::Varint => {
                decode_varint($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i32) => (
        match $data_type_option.id {
            ColType::Int => {
                decode_int($data_value.as_slice())?
            }
            ColType::Date => {
                decode_date($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i16) => (
        match $data_type_option.id {
            ColType::Smallint => {
                decode_smallint($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, i8) => (
        match $data_type_option.id {
            ColType::Tinyint => {
                decode_tinyint($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, f64) => (
        match $data_type_option.id {
            ColType::Double => {
                decode_double($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, f32) => (
        match $data_type_option.id {
            ColType::Decimal => {
                decode_decimal($data_value.as_slice())?
            }
            ColType::Float => {
                decode_float($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, IpAddr) => (
        match $data_type_option.id {
            ColType::Inet => {
                decode_inet($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, Uuid) => (
        match $data_type_option.id {
            ColType::Uuid => {
                decode_timeuuid($data_value.as_slice())?
            }
            ColType::Timeuuid => {
                decode_timeuuid($data_value.as_slice())?
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, List) => (
        match $data_type_option.id {
            ColType::List => {
                List::new(decode_list($data_value.as_slice())?,
                    $data_type_option.as_ref().clone())
            }
            ColType::Set => {
                List::new(decode_list($data_value.as_slice())?,
                    $data_type_option.as_ref().clone())
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, Map) => (
        match $data_type_option.id {
            ColType::Map => {
                Map::new(decode_map($data_value.as_slice())?,
                    $data_type_option.as_ref().clone())
            }
            _ => unreachable!()
        }
    );
    ($data_type_option:ident, $data_value:ident, UDT) => (
        match *$data_type_option {
            ColTypeOption {
                id: ColType::Udt,
                value: Some(ColTypeOptionValue::UdtType(ref list_type_option))
            } => {
                UDT::new(decode_udt($data_value.as_slice(), list_type_option.descriptions.len())?,
                    list_type_option)
            }
            _ => unreachable!()
        }
    );
}
<|endoftext|>


<commit_before>//! IPC module will hold all massive (that is why IPC) internal messages
//! which occur due to data collection, its start and its end.
use super::{
    audio_info::{AudioInfo, AudioInfoKey},
    IFInternalCollectionOutputData,
};

// todo: move to mod
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct IFCollectionOutputData {
    pub nr_searched_files: u32,
    pub nr_found_songs: u32,
    pub nr_internal_duplicates: u32,
    pub size_of_data_in_kb: usize,
}

impl IFCollectionOutputData {
    pub fn from(internal: &IFInternalCollectionOutputData) -> Self {
        Self {
            nr_searched_files: internal.nr_searched_files,
            nr_found_songs: internal.nr_found_songs,
            nr_internal_duplicates: internal.nr_internal_duplicates,
            size_of_data_in_kb: 0,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub enum IPC {
    DoneSearching(IFCollectionOutputData),
    PublishSingleAudioDataRecord(AudioInfoKey, AudioInfo),
}
<commit_msg>[refactor] data will stay in the file<commit_after>//! IPC module will hold all massive (that is why IPC) internal messages
//! which occur due to data collection, its start and its end.
use super::{
    audio_info::{AudioInfo, AudioInfoKey},
    IFInternalCollectionOutputData,
};

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct IFCollectionOutputData {
    pub nr_searched_files: u32,
    pub nr_found_songs: u32,
    pub nr_internal_duplicates: u32,
    pub size_of_data_in_kb: usize,
}

impl IFCollectionOutputData {
    pub fn from(internal: &IFInternalCollectionOutputData) -> Self {
        Self {
            nr_searched_files: internal.nr_searched_files,
            nr_found_songs: internal.nr_found_songs,
            nr_internal_duplicates: internal.nr_internal_duplicates,
            size_of_data_in_kb: 0,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub enum IPC {
    DoneSearching(IFCollectionOutputData),
    PublishSingleAudioDataRecord(AudioInfoKey, AudioInfo),
}
<|endoftext|>


<commit_before>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Opcode info from game packets
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcast packet type opcodes.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::thread::Builder;
use std::sync::{Arc, Mutex};

extern crate time;
use time::{SteadyTime,Duration};

mod error_macros;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::{HeartbeatPacket,GAMEEXITED,VALID_GAME_VERSIONS,HALO_RETAIL};

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = unwrap_result_or_bail!(UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)), {
        println!("Failed creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
        return;
    });

    let client_socket = unwrap_result_or_bail!(TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)), {
        println!("Failed listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
        return;
    });

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    let _ = Builder::new().name("destruction_thread".to_string()).spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = SteadyTime::now();
            servers.retain(|x| x.last_alive + Duration::seconds(DROP_TIME) > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Option<Vec<String>> = None;
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    let _ = Builder::new().name("blacklist_thread".to_string()).spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).ok();
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    let _ = Builder::new().name("halomd_thread".to_string()).spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = unwrap_option_or_bail!(stream.ok(), { continue });
                let ip = unwrap_option_or_bail!(client.peer_addr().ok(), { continue }).ip_string();
                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                // May want to consider some lightweight thread library in the future, or some non-blocking polling mechanism
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = unwrap_option_or_bail!(halo_socket.recv_from(&mut buffer).ok(), { continue });

        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if (*blacklist_ref).as_ref().map(|blacklist| blacklist.contains(&client_ip)).unwrap_or(false) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {

            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = SteadyTime::now();
                    match servers.iter_mut().position(|x| *x == (&client_ip, packet.localport)) {
                        None => {
                            if packet.gamename == HALO_RETAIL && VALID_GAME_VERSIONS.contains(&&*packet.gamever) {
                                (*servers).push(HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime });
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if *i == (&client_ip, source.port()) {
                    i.last_alive = SteadyTime::now();
                    break;
                }
            }
        }
    }
}
<commit_msg>Spacing<commit_after>// Syntax: master_server [ip address (0.0.0.0 by default)]
// This was created for HaloMD.

// If the server does not respond in at least this many seconds, it will be dropped from the list.
const DROP_TIME : i64 = 60;

// Blacklist for blocking IPs. Separate with newlines. Any line that starts with a # is ignored.
// Blacklisting IPs ignores heartbeat and keepalive packets from an IP address.
// That means that servers that are banned will not be immediately removed, but will time out, instead.
const BLACKLIST_FILE : &'static str = "blacklist.txt";

// Read the blacklist every x amount of seconds.
const BLACKLIST_UPDATE_TIME : u32 = 60;

// Note: The master server must have TCP 29920 open and UDP 27900 open.
const BROADCAST_PORT_UDP : u16 = 27900;
const SERVER_LIST_PORT_TCP : u16 = 29920;

// Opcode info from game packets
const OPCODE_INDEX : usize = 0;
const OPCODE_AND_HANDSHAKE_LENGTH : usize = 5;

// Broadcast packet type opcodes.
const KEEPALIVE : u8 = 8;
const HEARTBEAT : u8 = 3;

use std::net::{UdpSocket,TcpListener,SocketAddr};
use std::net::SocketAddr::{V4,V6};
use std::io::{Write,BufReader,BufRead};
use std::env;
use std::fs::File;
use std::thread;
use std::thread::Builder;
use std::sync::{Arc, Mutex};

extern crate time;
use time::{SteadyTime,Duration};

mod error_macros;

mod halo_server;
use halo_server::HaloServer;

mod heartbeat_packet;
use heartbeat_packet::{HeartbeatPacket,GAMEEXITED,VALID_GAME_VERSIONS,HALO_RETAIL};

trait IPString {
    fn ip_string(&self) -> String;
}

impl IPString for SocketAddr {
    fn ip_string(&self) -> String {
        match *self {
            V4(ipv4) => ipv4.ip().to_string(),
            V6(ipv6) => "[".to_string() + &ipv6.ip().to_string() + "]"
        }
    }
}

fn main() {
    let count = env::args().count();
    let ip = if count == 2 {
        let j : Vec<_> = env::args().collect();
        j[1].to_string()
    }
    else if count == 1 {
        "0.0.0.0".to_string()
    }
    else {
        println!("Only one argument is allowed: the IP to bind to.");
        return;
    };

    // We need to bind on two different ports. If it failed to bind (invalid IP, port is taken), then we must make sure this is known.
    let halo_socket = unwrap_result_or_bail!(UdpSocket::bind((&ip as &str,BROADCAST_PORT_UDP)), {
        println!("Failed creating a UDP socket at {}:{}.",ip,BROADCAST_PORT_UDP);
        return;
    });

    let client_socket = unwrap_result_or_bail!(TcpListener::bind((&ip as &str,SERVER_LIST_PORT_TCP)), {
        println!("Failed listening to TCP at {}:{}.",ip,SERVER_LIST_PORT_TCP);
        return;
    });

    // Mutex for thread safety.
    let servers_halo: Vec<HaloServer> = Vec::new();
    let servers_mut_udp = Arc::new(Mutex::new(servers_halo));
    let servers_mut_tcp = servers_mut_udp.clone();
    let servers_mut_destruction = servers_mut_udp.clone();

    // Destruction thread. This will remove servers that have not broadcasted their presence in a while.
    let _ = Builder::new().name("destruction_thread".to_string()).spawn(move || {
        loop {
            thread::sleep_ms(10 * 1000);
            let mut servers = servers_mut_destruction.lock().unwrap();
            let timenow = SteadyTime::now();
            servers.retain(|x| x.last_alive + Duration::seconds(DROP_TIME) > timenow);
        }
    });

    // Blacklist mutex. Concurrency needs to be safe, my friend.
    let blacklist: Option<Vec<String>> = None;
    let blacklist_update = Arc::new(Mutex::new(blacklist));
    let blacklist_udp = blacklist_update.clone();

    // Blacklist read thread.
    let _ = Builder::new().name("blacklist_thread".to_string()).spawn(move || {
        let valid_line = |x: &str| -> bool { x.trim().len() > 0 && !x.starts_with("#") };
        loop {
            // Placed in a block so blacklist is unlocked before sleeping to prevent threads from being locked for too long.
            {
                let mut blacklist_ref = blacklist_update.lock().unwrap();
                *blacklist_ref =
                    File::open(BLACKLIST_FILE).
                    map(|file|
                        BufReader::new(&file).lines().
                        filter_map(|line| line.ok().and_then(|x| if valid_line(&x) { Some(x) } else { None })).
                        collect()
                    ).ok();
            }
            thread::sleep_ms(BLACKLIST_UPDATE_TIME * 1000);
        }
    });

    // TCP server thread. This is for the HaloMD application.
    let _ = Builder::new().name("halomd_thread".to_string()).spawn(move || {
        loop {
            for stream in client_socket.incoming() {
                let mut client = unwrap_option_or_bail!(stream.ok(), { continue });
                let ip = unwrap_option_or_bail!(client.peer_addr().ok(), { continue }).ip_string();
                let mut ips = String::new();

                // Make servers_ref go out of scope to unlock it for other threads, since we don't need it.
                {
                    let servers_ref = servers_mut_tcp.lock().unwrap();
                    let servers = (*servers_ref).iter();

                    for j in servers {
                        ips.push_str(&(j.to_string()));
                        ips.push('\n');
                    }
                }

                // Some number placed after the requester's IP. If you ask me, the source code was abducted by aliens, and this is a tracking number. Regardless, it's needed.
                ips.push_str(&ip);
                ips.push_str(":49149:3425");

                // We may be here a while. Just in case...
                // May want to consider some lightweight thread library in the future, or some non-blocking polling mechanism
                thread::spawn( move || {
                    let _ = client.write_all(ips.as_bytes());
                });
            }
        }
    });

    // UDP server is run on the main thread. Servers broadcast their presence here.

    let mut buffer = [0; 2048];
    loop {
        let (length, source) = unwrap_option_or_bail!(halo_socket.recv_from(&mut buffer).ok(), { continue });

        if length <= OPCODE_INDEX {
            continue;
        }

        if buffer[OPCODE_INDEX] != KEEPALIVE && buffer[OPCODE_INDEX] != HEARTBEAT {
            continue;
        }

        let client_ip = source.ip_string();

        let blacklist_ref = blacklist_udp.lock().unwrap();
        if (*blacklist_ref).as_ref().map(|blacklist| blacklist.contains(&client_ip)).unwrap_or(false) {
            continue;
        }

        // Heartbeat packet. These contain null-terminated C strings and are ordered in key1[0]value1[0]key2[0]value2[0]key3[0]value3[0] where [0] is a byte equal to 0x00.
        if buffer[OPCODE_INDEX] == HEARTBEAT && length > OPCODE_AND_HANDSHAKE_LENGTH {
            let mut servers = servers_mut_udp.lock().unwrap();

            match HeartbeatPacket::from_buffer(&buffer[OPCODE_AND_HANDSHAKE_LENGTH..length]) {
                None => {},
                Some(packet) => {
                    let updatetime = SteadyTime::now();
                    match servers.iter_mut().position(|x| *x == (&client_ip, packet.localport)) {
                        None => {
                            if packet.gamename == HALO_RETAIL && VALID_GAME_VERSIONS.contains(&&*packet.gamever) {
                                (*servers).push(HaloServer { ip:client_ip, port: packet.localport, last_alive: updatetime });
                            }
                        }
                        Some(k) => {
                            servers[k].last_alive = updatetime;
                            if packet.statechanged == GAMEEXITED {
                                servers.remove(k);
                            }
                        }
                    };
                }
            };
        }

        // Keepalive packet. We need to rely on the origin's port for this, unfortunately. This may mean that the source port is incorrect if the port was changed with NAT.
        else if buffer[OPCODE_INDEX] == KEEPALIVE {
            let mut servers_ref = servers_mut_udp.lock().unwrap();
            let servers = (*servers_ref).iter_mut();

            for i in servers {
                if *i == (&client_ip, source.port()) {
                    i.last_alive = SteadyTime::now();
                    break;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::slice;
use { ffi, FtResult, Error };

/// An enumeration type used to describe the format of pixels in a given bitmap. Note that
/// additional formats may be added in the future.
#[derive(Copy, Clone, Debug)]
pub enum PixelMode {
    /// This value is reserved.
    None,

    /// A monochrome bitmap, using 1 bit per pixel. Note that pixels are
    /// stored in most-significant order (MSB), which means that the left-most
    /// pixel in a byte has value 128.
    Mono,

    /// An 8-bit bitmap, generally used to represent anti-aliased glyph images.
    /// Each pixel is stored in one byte. Note that the number of `gray`
    /// levels is stored in the `num_grays` field of the FT_Bitmap structure
    /// (it generally is 256).
    Gray,

    /// A 2-bit per pixel bitmap, used to represent embedded anti-aliased
    /// bitmaps in font files according to the OpenType specification. We
    /// haven't found a single font using this format, however.
    Gray2,

    /// A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps in
    /// font files according to the OpenType specification. We haven't found a
    /// single font using this format, however.
    Gray4,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    /// for display on LCD displays; the bitmap is three times wider than the
    /// original glyph image. See also FT_RENDER_MODE_LCD.
    Lcd,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used for
    /// display on rotated LCD displays; the bitmap is three times taller than
    /// the original glyph image. See also FT_RENDER_MODE_LCD_V.
    LcdV,

    /// An image with four 8-bit channels per pixel, representing a color image
    /// (such as emoticons) with alpha channel. For each pixel, the format is
    /// BGRA, which means, the blue channel comes first in memory. The color
    /// channels are pre-multiplied and in the sRGB colorspace. For example,
    /// full red at half-translucent opacity will be represented as
    /// `00,00,80,80`, not `00,00,FF,80`. See also FT_LOAD_COLOR.
    Bgra
}

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap
}

impl Bitmap {
    pub fn from_raw(raw: *const ffi::FT_Bitmap) -> Self {
        Bitmap {
            raw: raw
        }
    }

    /// A typeless pointer to the bitmap buffer. This value should be aligned
    /// on 32-bit boundaries in most cases.
    pub fn buffer(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                (*self.raw).buffer,
                (self.width() * self.rows()) as usize
            )
        }
    }

    /// The number of pixels in bitmap row.
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    /// The number of bitmap rows.
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }

    /// The pixel mode, i.e., how pixel bits are stored. See `PixelMode` for
    /// possible values.
    pub fn pixel_mode(&self) -> FtResult<PixelMode> {
        let pixel_mode = unsafe { (*self.raw).pixel_mode } as u32;

        Ok(match pixel_mode {
            ffi::FT_PIXEL_MODE_NONE  => PixelMode::None,
            ffi::FT_PIXEL_MODE_MONO  => PixelMode::Mono,
            ffi::FT_PIXEL_MODE_GRAY  => PixelMode::Gray,
            ffi::FT_PIXEL_MODE_GRAY2 => PixelMode::Gray2,
            ffi::FT_PIXEL_MODE_GRAY4 => PixelMode::Gray4,
            ffi::FT_PIXEL_MODE_LCD   => PixelMode::Lcd,
            ffi::FT_PIXEL_MODE_LCD_V => PixelMode::LcdV,
            ffi::FT_PIXEL_MODE_BGRA  => PixelMode::Bgra,
            _ => return Err(Error::UnexpectedPixelMode)
        })
    }

    /// The pitch's absolute value is the number of bytes taken by one bitmap row, including
    /// padding. However, the pitch is positive when the bitmap has a ‘down’ flow, and negative
    /// when it has an ‘up’ flow. In all cases, the pitch is an offset to add to a bitmap pointer
    /// in order to go down one row.
    ///
    /// Note that ‘padding’ means the alignment of a bitmap to a byte border, and FreeType
    /// functions normally align to the smallest possible integer value.
    /// For the B/W rasterizer, ‘pitch’ is always an even number.
    ///
    /// To change the pitch of a bitmap (say, to make it a multiple of 4), use FT_Bitmap_Convert.
    /// Alternatively, you might use callback functions to directly render to the application's
    /// surface; see the file ‘example2.cpp’ in the tutorial for a demonstration.
    pub fn pitch(&self) -> i32 {
        unsafe {
            (*self.raw).pitch
        }
    }
}
<commit_msg>Bitmap: Use abs(pitch) * rows as the bitmap length<commit_after>use std::slice;
use { ffi, FtResult, Error };

/// An enumeration type used to describe the format of pixels in a given bitmap. Note that
/// additional formats may be added in the future.
#[derive(Copy, Clone, Debug)]
pub enum PixelMode {
    /// This value is reserved.
    None,

    /// A monochrome bitmap, using 1 bit per pixel. Note that pixels are
    /// stored in most-significant order (MSB), which means that the left-most
    /// pixel in a byte has value 128.
    Mono,

    /// An 8-bit bitmap, generally used to represent anti-aliased glyph images.
    /// Each pixel is stored in one byte. Note that the number of `gray`
    /// levels is stored in the `num_grays` field of the FT_Bitmap structure
    /// (it generally is 256).
    Gray,

    /// A 2-bit per pixel bitmap, used to represent embedded anti-aliased
    /// bitmaps in font files according to the OpenType specification. We
    /// haven't found a single font using this format, however.
    Gray2,

    /// A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps in
    /// font files according to the OpenType specification. We haven't found a
    /// single font using this format, however.
    Gray4,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    /// for display on LCD displays; the bitmap is three times wider than the
    /// original glyph image. See also FT_RENDER_MODE_LCD.
    Lcd,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used for
    /// display on rotated LCD displays; the bitmap is three times taller than
    /// the original glyph image. See also FT_RENDER_MODE_LCD_V.
    LcdV,

    /// An image with four 8-bit channels per pixel, representing a color image
    /// (such as emoticons) with alpha channel. For each pixel, the format is
    /// BGRA, which means, the blue channel comes first in memory. The color
    /// channels are pre-multiplied and in the sRGB colorspace. For example,
    /// full red at half-translucent opacity will be represented as
    /// `00,00,80,80`, not `00,00,FF,80`. See also FT_LOAD_COLOR.
    Bgra
}

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap
}

impl Bitmap {
    pub fn from_raw(raw: *const ffi::FT_Bitmap) -> Self {
        Bitmap {
            raw: raw
        }
    }

    /// A typeless pointer to the bitmap buffer. This value should be aligned
    /// on 32-bit boundaries in most cases.
    pub fn buffer(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                (*self.raw).buffer,
                (self.pitch().abs() * self.rows()) as usize
            )
        }
    }

    /// The number of pixels in bitmap row.
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    /// The number of bitmap rows.
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }

    /// The pixel mode, i.e., how pixel bits are stored. See `PixelMode` for
    /// possible values.
    pub fn pixel_mode(&self) -> FtResult<PixelMode> {
        let pixel_mode = unsafe { (*self.raw).pixel_mode } as u32;

        Ok(match pixel_mode {
            ffi::FT_PIXEL_MODE_NONE  => PixelMode::None,
            ffi::FT_PIXEL_MODE_MONO  => PixelMode::Mono,
            ffi::FT_PIXEL_MODE_GRAY  => PixelMode::Gray,
            ffi::FT_PIXEL_MODE_GRAY2 => PixelMode::Gray2,
            ffi::FT_PIXEL_MODE_GRAY4 => PixelMode::Gray4,
            ffi::FT_PIXEL_MODE_LCD   => PixelMode::Lcd,
            ffi::FT_PIXEL_MODE_LCD_V => PixelMode::LcdV,
            ffi::FT_PIXEL_MODE_BGRA  => PixelMode::Bgra,
            _ => return Err(Error::UnexpectedPixelMode)
        })
    }

    /// The pitch's absolute value is the number of bytes taken by one bitmap row, including
    /// padding. However, the pitch is positive when the bitmap has a ‘down’ flow, and negative
    /// when it has an ‘up’ flow. In all cases, the pitch is an offset to add to a bitmap pointer
    /// in order to go down one row.
    ///
    /// Note that ‘padding’ means the alignment of a bitmap to a byte border, and FreeType
    /// functions normally align to the smallest possible integer value.
    /// For the B/W rasterizer, ‘pitch’ is always an even number.
    ///
    /// To change the pitch of a bitmap (say, to make it a multiple of 4), use FT_Bitmap_Convert.
    /// Alternatively, you might use callback functions to directly render to the application's
    /// surface; see the file ‘example2.cpp’ in the tutorial for a demonstration.
    pub fn pitch(&self) -> i32 {
        unsafe {
            (*self.raw).pitch
        }
    }
}
<|endoftext|>


<commit_before>// -*- tab-width: 2 -*-

use libc;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
use std::slice;

/// Fixed-length heap-allocated vector.
/// This is basically a `Box<[T]>`, except that that type can't actually be constructed.
/// Furthermore, `[T; N]` can't be constructed if N is not a compile-time constant.
#[derive(Debug)]
pub struct Buffer<T> {
  ptr: *mut T,
  length: usize,
  owned: bool,
}

impl<T: Default> Buffer<T> {
  /// Creates a new buffer initialized to zeros.
  ///
  /// `len` is the number of elements.
  pub fn new(len: usize) -> Self {
    let mut b = unsafe {
      Buffer::new_uninitialized(len)
    };
    // TODO: Use libc::memset for primitives once we have impl specialization and memset is included
    for i in 0..len {
      b[i] = T::default();
    }
    b
  }
}

impl<T> Buffer<T> {
  /// Creates a new uninitialized buffer.
  ///
  /// `len` is the number of elements.
  /// The caller is responsible for initializing the data.
  pub unsafe fn new_uninitialized(len: usize) -> Self {
    let elem_size = mem::size_of::<T>();
    let alloc_size = len * elem_size;
    let align = mem::align_of::<T>();
    // TODO: Use alloc::heap::allocate once it's stable, or at least libc::aligned_alloc once it exists
    let ptr = libc::memalign(align, alloc_size) as *mut T;
    if ptr.is_null() {
      panic!("Failed to allocate. Out of memory?");
    }
    Buffer {
      ptr: ptr,
      length: len,
      owned: true,
    }
  }

  /// Creates a buffer from data owned by the C API.
  ///
  /// `len` is the number of elements.
  /// The underlying data is *not* freed when the buffer is destroyed.
  pub unsafe fn from_ptr(ptr: *mut T, len: usize) -> Self {
    Buffer {
      ptr: ptr,
      length: len,
      owned: false,
    }
  }
}

impl<T> Drop for Buffer<T> {
  fn drop(&mut self) {
    if self.owned {
      // It would be nice to skip the loop entirely if std::intrinsics::needs_drop() returns false,
      // but it's not stable, and the docs say it probably never will be.
      // Note that checking to see if T implements Drop is not sufficient,
      // because T may not implement Drop, but may contain a type that does.
      unsafe {
        for x in self.iter_mut() {
          // TODO: use std::ptr::drop_in_place
          mem::drop(mem::replace(x, mem::uninitialized()));
        }
        libc::free(self.ptr as *mut libc::c_void);
      }
    }
  }
}

impl<T> AsRef<[T]> for Buffer<T> {
  #[inline]
  fn as_ref(&self) -> &[T] {
    unsafe {
      slice::from_raw_parts(self.ptr, self.length)
    }
  }
}

impl<T> AsMut<[T]> for Buffer<T> {
  #[inline]
  fn as_mut(&mut self) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(self.ptr, self.length)
    }
  }
}

impl<T> Deref for Buffer<T> {
  type Target = [T];

  #[inline]
  fn deref(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> DerefMut for Buffer<T> {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
    self.as_mut()
  }
}

impl<T> Borrow<[T]> for Buffer<T> {
  #[inline]
  fn borrow(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> BorrowMut<[T]> for Buffer<T> {
  #[inline]
  fn borrow_mut(&mut self) -> &mut [T] {
    self.as_mut()
  }
}

impl<T: Clone> Clone for Buffer<T> where T: Clone {
  #[inline]
  fn clone(&self) -> Buffer<T> {
    let mut b = unsafe {
      Buffer::new_uninitialized(self.length)
    };
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      b[i] = self[i].clone();
    }
    b
  }

  #[inline]
  fn clone_from(&mut self, other: &Buffer<T>) {
    assert!(self.length == other.length, "self.length = {}, other.length = {}", self.length, other.length);
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      self[i] = other[i].clone();
    }
  }
}

impl<T> Index<usize> for Buffer<T> {
  type Output = T;

  #[inline]
  fn index(&self, index: usize) -> &T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &*self.ptr.offset(index as isize)
    }
  }
}

impl<T> IndexMut<usize> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: usize) -> &mut T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &mut *self.ptr.offset(index as isize)
    }
  }
}

impl<T> Index<Range<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: Range<usize>) -> &[T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> IndexMut<Range<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> Index<RangeTo<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeTo<usize>) -> &[T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr, index.end)
    }
  }
}

impl<T> IndexMut<RangeTo<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, index.end)
    }
  }
}

impl<T> Index<RangeFrom<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeFrom<usize>) -> &[T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> IndexMut<RangeFrom<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> Index<RangeFull> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, _: RangeFull) -> &[T] {
    unsafe {
      slice::from_raw_parts(&*self.ptr, self.length)
    }
  }
}

impl<T> IndexMut<RangeFull> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, self.length)
    }
  }
}

////////////////////////

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn basic() {
    let mut buf = Buffer::new(10);
    assert_eq!(buf.len(), 10);
    buf[0] = 1;
    assert_eq!(buf[0], 1);
  }
}
<commit_msg>Use posix_memalign instead of memalign<commit_after>// -*- tab-width: 2 -*-

use libc;
use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::cmp;
use std::ffi::CStr;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
use std::ptr;
use std::slice;

/// Fixed-length heap-allocated vector.
/// This is basically a `Box<[T]>`, except that that type can't actually be constructed.
/// Furthermore, `[T; N]` can't be constructed if N is not a compile-time constant.
#[derive(Debug)]
pub struct Buffer<T> {
  ptr: *mut T,
  length: usize,
  owned: bool,
}

impl<T: Default> Buffer<T> {
  /// Creates a new buffer initialized to zeros.
  ///
  /// `len` is the number of elements.
  pub fn new(len: usize) -> Self {
    let mut b = unsafe {
      Buffer::new_uninitialized(len)
    };
    // TODO: Use libc::memset for primitives once we have impl specialization and memset is included
    for i in 0..len {
      b[i] = T::default();
    }
    b
  }
}

impl<T> Buffer<T> {
  /// Creates a new uninitialized buffer.
  ///
  /// `len` is the number of elements.
  /// The caller is responsible for initializing the data.
  pub unsafe fn new_uninitialized(len: usize) -> Self {
    let elem_size = mem::size_of::<T>();
    let alloc_size = len * elem_size;
    let align = cmp::max(mem::align_of::<T>(), mem::size_of::<*const libc::c_void>());
    // posix_memalign requires the alignment to be at least sizeof(void*).
    // TODO: Use alloc::heap::allocate once it's stable, or at least libc::aligned_alloc once it exists
    let mut ptr = ptr::null::<libc::c_void>() as *mut libc::c_void;
    let err = libc::posix_memalign(&mut ptr, align, alloc_size);
    if err != 0 {
      let c_msg = libc::strerror(err);
      let msg = CStr::from_ptr(c_msg);
      panic!("Failed to allocate: {}", msg.to_str().unwrap());
    }
    Buffer {
      ptr: ptr as *mut T,
      length: len,
      owned: true,
    }
  }

  /// Creates a buffer from data owned by the C API.
  ///
  /// `len` is the number of elements.
  /// The underlying data is *not* freed when the buffer is destroyed.
  pub unsafe fn from_ptr(ptr: *mut T, len: usize) -> Self {
    Buffer {
      ptr: ptr,
      length: len,
      owned: false,
    }
  }
}

impl<T> Drop for Buffer<T> {
  fn drop(&mut self) {
    if self.owned {
      // It would be nice to skip the loop entirely if std::intrinsics::needs_drop() returns false,
      // but it's not stable, and the docs say it probably never will be.
      // Note that checking to see if T implements Drop is not sufficient,
      // because T may not implement Drop, but may contain a type that does.
      unsafe {
        for x in self.iter_mut() {
          // TODO: use std::ptr::drop_in_place
          mem::drop(mem::replace(x, mem::uninitialized()));
        }
        libc::free(self.ptr as *mut libc::c_void);
      }
    }
  }
}

impl<T> AsRef<[T]> for Buffer<T> {
  #[inline]
  fn as_ref(&self) -> &[T] {
    unsafe {
      slice::from_raw_parts(self.ptr, self.length)
    }
  }
}

impl<T> AsMut<[T]> for Buffer<T> {
  #[inline]
  fn as_mut(&mut self) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(self.ptr, self.length)
    }
  }
}

impl<T> Deref for Buffer<T> {
  type Target = [T];

  #[inline]
  fn deref(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> DerefMut for Buffer<T> {
  #[inline]
  fn deref_mut<'a>(&'a mut self) -> &'a mut [T] {
    self.as_mut()
  }
}

impl<T> Borrow<[T]> for Buffer<T> {
  #[inline]
  fn borrow(&self) -> &[T] {
    self.as_ref()
  }
}

impl<T> BorrowMut<[T]> for Buffer<T> {
  #[inline]
  fn borrow_mut(&mut self) -> &mut [T] {
    self.as_mut()
  }
}

impl<T: Clone> Clone for Buffer<T> where T: Clone {
  #[inline]
  fn clone(&self) -> Buffer<T> {
    let mut b = unsafe {
      Buffer::new_uninitialized(self.length)
    };
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      b[i] = self[i].clone();
    }
    b
  }

  #[inline]
  fn clone_from(&mut self, other: &Buffer<T>) {
    assert!(self.length == other.length, "self.length = {}, other.length = {}", self.length, other.length);
    // TODO: Use std::ptr::copy for primitives once we have impl specialization
    for i in 0..self.length {
      self[i] = other[i].clone();
    }
  }
}

impl<T> Index<usize> for Buffer<T> {
  type Output = T;

  #[inline]
  fn index(&self, index: usize) -> &T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &*self.ptr.offset(index as isize)
    }
  }
}

impl<T> IndexMut<usize> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: usize) -> &mut T {
    assert!(index < self.length, "index = {}, length = {}", index, self.length);
    unsafe {
      &mut *self.ptr.offset(index as isize)
    }
  }
}

impl<T> Index<Range<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: Range<usize>) -> &[T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> IndexMut<Range<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: Range<usize>) -> &mut [T] {
    assert!(index.start <= index.end, "index.start = {}, index.end = {}", index.start, index.end);
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), index.len())
    }
  }
}

impl<T> Index<RangeTo<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeTo<usize>) -> &[T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr, index.end)
    }
  }
}

impl<T> IndexMut<RangeTo<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeTo<usize>) -> &mut [T] {
    assert!(index.end <= self.length, "index.end = {}, length = {}", index.end, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, index.end)
    }
  }
}

impl<T> Index<RangeFrom<usize>> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, index: RangeFrom<usize>) -> &[T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts(&*self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> IndexMut<RangeFrom<usize>> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [T] {
    assert!(index.start <= self.length, "index.start = {}, length = {}", index.start, self.length);
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr.offset(index.start as isize), self.length - index.start)
    }
  }
}

impl<T> Index<RangeFull> for Buffer<T> {
  type Output = [T];

  #[inline]
  fn index(&self, _: RangeFull) -> &[T] {
    unsafe {
      slice::from_raw_parts(&*self.ptr, self.length)
    }
  }
}

impl<T> IndexMut<RangeFull> for Buffer<T> {
  #[inline]
  fn index_mut(&mut self, _: RangeFull) -> &mut [T] {
    unsafe {
      slice::from_raw_parts_mut(&mut *self.ptr, self.length)
    }
  }
}

////////////////////////

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn basic() {
    let mut buf = Buffer::new(10);
    assert_eq!(buf.len(), 10);
    buf[0] = 1;
    assert_eq!(buf[0], 1);
  }
}
<|endoftext|>