<commit_before>//! # libgoblin
//!
//! ![say the right
//! words](https://s-media-cache-ak0.pinimg.com/736x/1b/6a/aa/1b6aaa2bae005e2fed84b1a7c32ecb1b.jpg)
//!
//! `libgoblin` is a cross-platform trifecta of binary parsing and loading fun.  It supports:
//!
//! * An ELF32/64 parser, and raw C structs
//! * A 32/64-bit, zero-copy, endian aware, Mach-o parser, and raw C structs
//! * A PE32/PE32+ (64-bit) parser, and raw C structs
//! * A Unix archive parser and loader
//!
//! Goblin _should_ require at least `rustc` 1.16, but is developed on stable.
//!
//! Goblin primarily supports the following important use cases:
//!
//! 1. Core, std-free `#[repr(C)]` structs, tiny compile time, 32/64 (or both) at your leisure
//!
//! 2. Type punning. Define a function once on a type, but have it work on 32 or 64-bit variants - without really changing anything, and no macros! See `examples/automagic.rs` for a basic example.
//!
//! 3. `std` mode. This throws in read and write impls via `Pread` and `Pwrite`, reading from file, convenience allocations, extra methods, etc. This is for clients who can allocate and want to read binaries off disk.
//!
//! 4. `Endian_fd`. A truly terrible name :laughing: this is for binary analysis like in [panopticon](https://github.com/das-labor/panopticon) which needs to read binaries of foreign endianness, _or_ as a basis for constructing cross platform foreign architecture binutils, e.g. [cargo-sym](https://github.com/m4b/cargo-sym) and [bingrep](https://github.com/m4b/bingrep) are simple examples of this, but the sky is the limit.
//!
//! # Example
//!
//! ```rust
//! use goblin::{error, Object};
//! use std::path::Path;
//! use std::env;
//! use std::fs::File;
//! use std::io::Read;
//!
//! fn run () -> error::Result<()> {
//!     for (i, arg) in env::args().enumerate() {
//!         if i == 1 {
//!             let path = Path::new(arg.as_str());
//!             let mut fd = File::open(path)?;
//!             let mut buffer = Vec::new();
//!             fd.read_to_end(&mut buffer)?;
//!             match goblin::parse(&buffer)? {
//!                 Object::Elf(elf) => {
//!                     println!("elf: {:#?}", &elf);
//!                 },
//!                 Object::PE(pe) => {
//!                     println!("pe: {:#?}", &pe);
//!                 },
//!                 Object::Mach(mach) => {
//!                     println!("mach: {:#?}", &mach);
//!                 },
//!                 Object::Archive(archive) => {
//!                     println!("archive: {:#?}", &archive);
//!                 },
//!                 Object::Unknown(magic) => { println!("unknown magic: {:#x}", magic) }
//!             }
//!         }
//!     }
//!     Ok(())
//! }
//! ```
//!
//! # Feature Usage
//!
//! `libgoblin` is engineered to be tailored towards very different use-case scenarios, for example:
//!
//! * a no-std mode; just simply set default features to false
//! * a endian aware parsing and reading
//! * for binary loaders which don't require this, simply use `elf32` and `elf64` (and `std` of course)
//!
//! For example, if you are writing a 64-bit kernel, or just want a barebones C-like
//! header interface which defines the structures, just select `elf64`, `--cfg
//! feature=\"elf64\"`, which will compile without `std`.
//!
//! Similarly, if you want to use host endianness loading via the various `from_fd` methods, `--cfg
//! feature=\"std\"`, which will not use the `byteorder` extern crate, and read the bytes
//! from disk in the endianness of the host machine.
//!
//! If you want endian aware reading, and you don't use `default`, then you need to opt in as normal
//! via `endian_fd`

#![cfg_attr(not(feature = "std"), no_std)]

extern crate plain;
extern crate scroll;
#[macro_use] extern crate log;

#[cfg(feature = "std")]
extern crate core;

#[cfg(feature = "std")]
#[macro_use] extern crate scroll_derive;

#[cfg(feature = "std")]
pub mod error;

pub mod strtab;

/////////////////////////
// Misc/Helper Modules
/////////////////////////

/// Binary container size information and byte-order context
pub mod container {
    use scroll;
    pub use scroll::Endian as Endian;

    #[derive(Debug, Copy, Clone, PartialEq)]
    /// The size of a binary container
    pub enum Container {
        Little,
        Big,
    }

    impl Container {
        /// Is this a 64-bit container or not?
        pub fn is_big(&self) -> bool {
            *self == Container::Big
        }
    }

    #[cfg(not(target_pointer_width = "64"))]
    /// The default binary container size - either `Big` or `Little`, depending on whether the host machine's pointer size is 64 or not
    pub const CONTAINER: Container =  Container::Little;

    #[cfg(target_pointer_width = "64")]
    /// The default binary container size - either `Big` or `Little`, depending on whether the host machine's pointer size is 64 or not
    pub const CONTAINER: Container =  Container::Big;

    impl Default for Container {
        #[inline]
        fn default() -> Self {
            CONTAINER
        }
    }

    #[derive(Debug, Copy, Clone, PartialEq)]
    /// A binary parsing context, including the container size and underlying byte endianness
    pub struct Ctx {
        pub container: Container,
        pub le: scroll::Endian,
    }

    impl Ctx {
        /// Whether this binary container context is "big" or not
        pub fn is_big(&self) -> bool {
            self.container.is_big()
        }
        /// Whether this binary container context is little endian or not
        pub fn is_little_endian(&self) -> bool {
            self.le.is_little()
        }
        /// Create a new binary container context
        pub fn new (container: Container, le: scroll::Endian) -> Self {
            Ctx { container: container, le: le }
        }
        /// Return a dubious pointer/address byte size for the container
        pub fn size(&self) -> usize {
            match self.container {
                // TODO: require pointer size initialization/setting or default to container size with these values, e.g., avr pointer width will be smaller iirc
                Container::Little => 4,
                Container::Big    => 8,
            }
        }
    }

    impl From<Container> for Ctx {
        fn from(container: Container) -> Self {
            Ctx { container: container, le: scroll::Endian::default() }
        }
    }

    impl From<scroll::Endian> for Ctx {
        fn from(le: scroll::Endian) -> Self {
            Ctx { container: CONTAINER, le: le }
        }
    }

    impl Default for Ctx {
        #[inline]
        fn default() -> Self {
            Ctx { container: Container::default(), le: scroll::Endian::default() }
        }
    }
}

// peek at the underlying bytes
#[cfg(feature = "std")]
pub use peek::*;

#[cfg(all(feature = "std"))]
mod peek {

    #[derive(Debug, Default)]
    /// Information obtained from a peek `Hint`
    pub struct HintData {
        pub is_lsb: bool,
        pub is_64: Option<bool>,
    }

    #[derive(Debug)]
    /// A hint at the underlying binary format for 16 bytes of arbitrary data
    pub enum Hint {
        Elf(HintData),
        Mach(HintData),
        MachFat(usize),
        PE,
        Archive,
        Unknown(u64),
    }

    /// Peeks at `bytes`, and returns a `Hint`
    #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
    pub fn peek_bytes(bytes: &[u8; 16]) -> super::error::Result<Hint> {
        use scroll::{Pread, BE};
        use super::*;
        if &bytes[0..elf::header::SELFMAG] == elf::header::ELFMAG {
            let class = bytes[elf::header::EI_CLASS];
            let is_lsb = bytes[elf::header::EI_DATA] == elf::header::ELFDATA2LSB;
            let is_64 =
                if class == elf::header::ELFCLASS64 {
                    Some (true)
                } else if class == elf::header::ELFCLASS32 {
                    Some (false)
                } else { None };

            Ok(Hint::Elf(HintData { is_lsb: is_lsb, is_64: is_64 }))
        } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
            Ok(Hint::Archive)
        } else if (&bytes[0..2]).pread::<u16>(0)? == pe::header::DOS_MAGIC {
            Ok(Hint::PE)
        } else {
            use mach::{fat, header};
            let magic = mach::peek(bytes, 0)?;
            match magic {
                fat::FAT_MAGIC => {
                    // should probably verify this is always Big Endian...
                    let narchitectures = bytes.pread_with::<u32>(4, BE)? as usize;
                    Ok(Hint::MachFat(narchitectures))
                },
                header::MH_CIGAM_64 | header::MH_CIGAM | header::MH_MAGIC_64 | header::MH_MAGIC => {
                    let is_lsb = magic == header::MH_CIGAM || magic == header::MH_CIGAM_64;
                    let is_64 = magic == header::MH_MAGIC_64 || magic == header::MH_CIGAM_64;
                    Ok(Hint::Mach(HintData { is_lsb: is_lsb, is_64: Some(is_64) }))
                },
                // its something else
                _ => Ok(Hint::Unknown(bytes.pread::<u64>(0)?))
            }
        }
    }

    /// Peeks at the underlying Read object. Requires the underlying bytes to have at least 16 byte length. Resets the seek to `Start` after reading.
    #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
    pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> super::error::Result<Hint> {
        use std::io::SeekFrom;
        let mut bytes = [0u8; 16];
        fd.seek(SeekFrom::Start(0))?;
        fd.read_exact(&mut bytes)?;
        fd.seek(SeekFrom::Start(0))?;
        peek_bytes(&bytes)
    }
}

#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
#[derive(Debug)]
/// A parseable object that goblin understands
pub enum Object<'a> {
    /// An ELF32/ELF64!
    Elf(elf::Elf<'a>),
    /// A PE32/PE32+!
    PE(pe::PE<'a>),
    /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container!
    Mach(mach::Mach<'a>),
    /// A Unix archive
    Archive(archive::Archive<'a>),
    /// None of the above, with the given magic value
    Unknown(u64),
}

#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
/// Parses an `Object` from `bytes`.
pub fn parse(bytes: &[u8]) -> error::Result<Object> {
    use std::io::Cursor;
    match peek(&mut Cursor::new(&bytes))? {
        Hint::Elf(_) => Ok(Object::Elf(elf::Elf::parse(bytes)?)),
        Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)),
        Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)),
        Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)),
        Hint::Unknown(magic) => Ok(Object::Unknown(magic))
    }
}

/////////////////////////
// Binary Modules
/////////////////////////

#[cfg(any(feature = "elf64", feature = "elf32"))]
#[macro_use]
pub mod elf;

#[cfg(feature = "elf32")]
/// The ELF 32-bit struct definitions and associated values, re-exported for easy "type-punning"
pub mod elf32 {
    pub use elf::header::header32 as header;
    pub use elf::program_header::program_header32 as program_header;
    pub use elf::section_header::section_header32 as section_header;
    pub use elf::dyn::dyn32 as dyn;
    pub use elf::sym::sym32 as sym;
    pub use elf::reloc::reloc32 as reloc;

    pub mod gnu_hash {
        elf_gnu_hash_impl!(u32);
    }
}

#[cfg(feature = "elf64")]
/// The ELF 64-bit struct definitions and associated values, re-exported for easy "type-punning"
pub mod elf64 {
    pub use elf::header::header64 as header;
    pub use elf::program_header::program_header64 as program_header;
    pub use elf::section_header::section_header64 as section_header;
    pub use elf::dyn::dyn64 as dyn;
    pub use elf::sym::sym64 as sym;
    pub use elf::reloc::reloc64 as reloc;

    pub mod gnu_hash {
        elf_gnu_hash_impl!(u64);
    }
}

#[cfg(all(feature = "mach32", feature = "mach64", feature = "endian_fd"))]
pub mod mach;

#[cfg(all(feature = "pe32", feature = "pe64", feature = "endian_fd"))]
pub mod pe;

#[cfg(all(feature = "archive", feature = "std"))]
pub mod archive;
<commit_msg>goblin: add parse to Object to be more rustish; add deprecation<commit_after>//! # libgoblin
//!
//! ![say the right
//! words](https://s-media-cache-ak0.pinimg.com/736x/1b/6a/aa/1b6aaa2bae005e2fed84b1a7c32ecb1b.jpg)
//!
//! `libgoblin` is a cross-platform trifecta of binary parsing and loading fun.  It supports:
//!
//! * An ELF32/64 parser, and raw C structs
//! * A 32/64-bit, zero-copy, endian aware, Mach-o parser, and raw C structs
//! * A PE32/PE32+ (64-bit) parser, and raw C structs
//! * A Unix archive parser and loader
//!
//! Goblin _should_ require at least `rustc` 1.16, but is developed on stable.
//!
//! Goblin primarily supports the following important use cases:
//!
//! 1. Core, std-free `#[repr(C)]` structs, tiny compile time, 32/64 (or both) at your leisure
//!
//! 2. Type punning. Define a function once on a type, but have it work on 32 or 64-bit variants - without really changing anything, and no macros! See `examples/automagic.rs` for a basic example.
//!
//! 3. `std` mode. This throws in read and write impls via `Pread` and `Pwrite`, reading from file, convenience allocations, extra methods, etc. This is for clients who can allocate and want to read binaries off disk.
//!
//! 4. `Endian_fd`. A truly terrible name :laughing: this is for binary analysis like in [panopticon](https://github.com/das-labor/panopticon) which needs to read binaries of foreign endianness, _or_ as a basis for constructing cross platform foreign architecture binutils, e.g. [cargo-sym](https://github.com/m4b/cargo-sym) and [bingrep](https://github.com/m4b/bingrep) are simple examples of this, but the sky is the limit.
//!
//! # Example
//!
//! ```rust
//! use goblin::{error, Object};
//! use std::path::Path;
//! use std::env;
//! use std::fs::File;
//! use std::io::Read;
//!
//! fn run () -> error::Result<()> {
//!     for (i, arg) in env::args().enumerate() {
//!         if i == 1 {
//!             let path = Path::new(arg.as_str());
//!             let mut fd = File::open(path)?;
//!             let mut buffer = Vec::new();
//!             fd.read_to_end(&mut buffer)?;
//!             match goblin::parse(&buffer)? {
//!                 Object::Elf(elf) => {
//!                     println!("elf: {:#?}", &elf);
//!                 },
//!                 Object::PE(pe) => {
//!                     println!("pe: {:#?}", &pe);
//!                 },
//!                 Object::Mach(mach) => {
//!                     println!("mach: {:#?}", &mach);
//!                 },
//!                 Object::Archive(archive) => {
//!                     println!("archive: {:#?}", &archive);
//!                 },
//!                 Object::Unknown(magic) => { println!("unknown magic: {:#x}", magic) }
//!             }
//!         }
//!     }
//!     Ok(())
//! }
//! ```
//!
//! # Feature Usage
//!
//! `libgoblin` is engineered to be tailored towards very different use-case scenarios, for example:
//!
//! * a no-std mode; just simply set default features to false
//! * a endian aware parsing and reading
//! * for binary loaders which don't require this, simply use `elf32` and `elf64` (and `std` of course)
//!
//! For example, if you are writing a 64-bit kernel, or just want a barebones C-like
//! header interface which defines the structures, just select `elf64`, `--cfg
//! feature=\"elf64\"`, which will compile without `std`.
//!
//! Similarly, if you want to use host endianness loading via the various `from_fd` methods, `--cfg
//! feature=\"std\"`, which will not use the `byteorder` extern crate, and read the bytes
//! from disk in the endianness of the host machine.
//!
//! If you want endian aware reading, and you don't use `default`, then you need to opt in as normal
//! via `endian_fd`

#![cfg_attr(not(feature = "std"), no_std)]

extern crate plain;
extern crate scroll;
#[macro_use] extern crate log;

#[cfg(feature = "std")]
extern crate core;

#[cfg(feature = "std")]
#[macro_use] extern crate scroll_derive;

#[cfg(feature = "std")]
pub mod error;

pub mod strtab;

/////////////////////////
// Misc/Helper Modules
/////////////////////////

/// Binary container size information and byte-order context
pub mod container {
    use scroll;
    pub use scroll::Endian as Endian;

    #[derive(Debug, Copy, Clone, PartialEq)]
    /// The size of a binary container
    pub enum Container {
        Little,
        Big,
    }

    impl Container {
        /// Is this a 64-bit container or not?
        pub fn is_big(&self) -> bool {
            *self == Container::Big
        }
    }

    #[cfg(not(target_pointer_width = "64"))]
    /// The default binary container size - either `Big` or `Little`, depending on whether the host machine's pointer size is 64 or not
    pub const CONTAINER: Container =  Container::Little;

    #[cfg(target_pointer_width = "64")]
    /// The default binary container size - either `Big` or `Little`, depending on whether the host machine's pointer size is 64 or not
    pub const CONTAINER: Container =  Container::Big;

    impl Default for Container {
        #[inline]
        fn default() -> Self {
            CONTAINER
        }
    }

    #[derive(Debug, Copy, Clone, PartialEq)]
    /// A binary parsing context, including the container size and underlying byte endianness
    pub struct Ctx {
        pub container: Container,
        pub le: scroll::Endian,
    }

    impl Ctx {
        /// Whether this binary container context is "big" or not
        pub fn is_big(&self) -> bool {
            self.container.is_big()
        }
        /// Whether this binary container context is little endian or not
        pub fn is_little_endian(&self) -> bool {
            self.le.is_little()
        }
        /// Create a new binary container context
        pub fn new (container: Container, le: scroll::Endian) -> Self {
            Ctx { container: container, le: le }
        }
        /// Return a dubious pointer/address byte size for the container
        pub fn size(&self) -> usize {
            match self.container {
                // TODO: require pointer size initialization/setting or default to container size with these values, e.g., avr pointer width will be smaller iirc
                Container::Little => 4,
                Container::Big    => 8,
            }
        }
    }

    impl From<Container> for Ctx {
        fn from(container: Container) -> Self {
            Ctx { container: container, le: scroll::Endian::default() }
        }
    }

    impl From<scroll::Endian> for Ctx {
        fn from(le: scroll::Endian) -> Self {
            Ctx { container: CONTAINER, le: le }
        }
    }

    impl Default for Ctx {
        #[inline]
        fn default() -> Self {
            Ctx { container: Container::default(), le: scroll::Endian::default() }
        }
    }
}

// peek at the underlying bytes
#[cfg(feature = "std")]
pub use peek::*;

#[cfg(all(feature = "std"))]
mod peek {

    #[derive(Debug, Default)]
    /// Information obtained from a peek `Hint`
    pub struct HintData {
        pub is_lsb: bool,
        pub is_64: Option<bool>,
    }

    #[derive(Debug)]
    /// A hint at the underlying binary format for 16 bytes of arbitrary data
    pub enum Hint {
        Elf(HintData),
        Mach(HintData),
        MachFat(usize),
        PE,
        Archive,
        Unknown(u64),
    }

    /// Peeks at `bytes`, and returns a `Hint`
    #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
    pub fn peek_bytes(bytes: &[u8; 16]) -> super::error::Result<Hint> {
        use scroll::{Pread, BE};
        use super::*;
        if &bytes[0..elf::header::SELFMAG] == elf::header::ELFMAG {
            let class = bytes[elf::header::EI_CLASS];
            let is_lsb = bytes[elf::header::EI_DATA] == elf::header::ELFDATA2LSB;
            let is_64 =
                if class == elf::header::ELFCLASS64 {
                    Some (true)
                } else if class == elf::header::ELFCLASS32 {
                    Some (false)
                } else { None };

            Ok(Hint::Elf(HintData { is_lsb: is_lsb, is_64: is_64 }))
        } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
            Ok(Hint::Archive)
        } else if (&bytes[0..2]).pread::<u16>(0)? == pe::header::DOS_MAGIC {
            Ok(Hint::PE)
        } else {
            use mach::{fat, header};
            let magic = mach::peek(bytes, 0)?;
            match magic {
                fat::FAT_MAGIC => {
                    // should probably verify this is always Big Endian...
                    let narchitectures = bytes.pread_with::<u32>(4, BE)? as usize;
                    Ok(Hint::MachFat(narchitectures))
                },
                header::MH_CIGAM_64 | header::MH_CIGAM | header::MH_MAGIC_64 | header::MH_MAGIC => {
                    let is_lsb = magic == header::MH_CIGAM || magic == header::MH_CIGAM_64;
                    let is_64 = magic == header::MH_MAGIC_64 || magic == header::MH_CIGAM_64;
                    Ok(Hint::Mach(HintData { is_lsb: is_lsb, is_64: Some(is_64) }))
                },
                // its something else
                _ => Ok(Hint::Unknown(bytes.pread::<u64>(0)?))
            }
        }
    }

    /// Peeks at the underlying Read object. Requires the underlying bytes to have at least 16 byte length. Resets the seek to `Start` after reading.
    #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
    pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> super::error::Result<Hint> {
        use std::io::SeekFrom;
        let mut bytes = [0u8; 16];
        fd.seek(SeekFrom::Start(0))?;
        fd.read_exact(&mut bytes)?;
        fd.seek(SeekFrom::Start(0))?;
        peek_bytes(&bytes)
    }
}

#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
#[derive(Debug)]
/// A parseable object that goblin understands
pub enum Object<'a> {
    /// An ELF32/ELF64!
    Elf(elf::Elf<'a>),
    /// A PE32/PE32+!
    PE(pe::PE<'a>),
    /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container!
    Mach(mach::Mach<'a>),
    /// A Unix archive
    Archive(archive::Archive<'a>),
    /// None of the above, with the given magic value
    Unknown(u64),
}

#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
impl<'a> Object<'a> {
    /// Tries to parse an `Object` from `bytes`
    pub fn parse(bytes: &[u8]) -> error::Result<Object> {
        use std::io::Cursor;
        match peek(&mut Cursor::new(&bytes))? {
            Hint::Elf(_) => Ok(Object::Elf(elf::Elf::parse(bytes)?)),
            Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)),
            Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)),
            Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)),
            Hint::Unknown(magic) => Ok(Object::Unknown(magic))
        }
    }
}

#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
/// Parses an `Object` from `bytes`.
#[deprecated(since = "0.0.11", note = "use `goblin::Object::parse` instead; this will be removed in 0.0.12")]
pub fn parse(bytes: &[u8]) -> error::Result<Object> {
    Object::parse(bytes)
}

/////////////////////////
// Binary Modules
/////////////////////////

#[cfg(any(feature = "elf64", feature = "elf32"))]
#[macro_use]
pub mod elf;

#[cfg(feature = "elf32")]
/// The ELF 32-bit struct definitions and associated values, re-exported for easy "type-punning"
pub mod elf32 {
    pub use elf::header::header32 as header;
    pub use elf::program_header::program_header32 as program_header;
    pub use elf::section_header::section_header32 as section_header;
    pub use elf::dyn::dyn32 as dyn;
    pub use elf::sym::sym32 as sym;
    pub use elf::reloc::reloc32 as reloc;

    pub mod gnu_hash {
        elf_gnu_hash_impl!(u32);
    }
}

#[cfg(feature = "elf64")]
/// The ELF 64-bit struct definitions and associated values, re-exported for easy "type-punning"
pub mod elf64 {
    pub use elf::header::header64 as header;
    pub use elf::program_header::program_header64 as program_header;
    pub use elf::section_header::section_header64 as section_header;
    pub use elf::dyn::dyn64 as dyn;
    pub use elf::sym::sym64 as sym;
    pub use elf::reloc::reloc64 as reloc;

    pub mod gnu_hash {
        elf_gnu_hash_impl!(u64);
    }
}

#[cfg(all(feature = "mach32", feature = "mach64", feature = "endian_fd"))]
pub mod mach;

#[cfg(all(feature = "pe32", feature = "pe64", feature = "endian_fd"))]
pub mod pe;

#[cfg(all(feature = "archive", feature = "std"))]
pub mod archive;
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate gfx_core;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
    /// Flips image horizontally.
    Horizontal,
    /// Flips image both vertically and horizontally.
    Both,
}

/// Represents a texture.
#[derive(Clone, Debug, PartialEq)]
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// Sampler for texture.
    pub sampler: gfx::handle::Sampler<R>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = match flip {
            Flip::Vertical => image::imageops::flip_vertical(&img),
            Flip::Horizontal => image::imageops::flip_horizontal(&img),
            Flip::Both => {
                let img = image::imageops::flip_vertical(&img);
                image::imageops::flip_horizontal(&img)
            }
            Flip::None => img,
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        // Modified `Factory::create_texture_immutable_u8` for dynamic texture.
        fn create_texture<T, F, R>(
            factory: &mut F,
            kind: gfx::texture::Kind,
            data: &[&[u8]]
        ) -> Result<(
            gfx::handle::Texture<R, T::Surface>,
            gfx::handle::ShaderResourceView<R, T::View>
        ), CombinedError>
            where F: gfx::Factory<R>,
                  R: gfx::Resources,
                  T: gfx::format::TextureFormat
        {
            use gfx::{format, texture};
            use gfx::memory::{Usage, Bind};
            use gfx_core::memory::Typed;
            use gfx_core::texture::Mipmap;

            let surface = <T::Surface as format::SurfaceTyped>::get_surface_type();
            let num_slices = kind.get_num_slices().unwrap_or(1) as usize;
            let num_faces = if kind.is_cube() {6} else {1};
            let desc = texture::Info {
                kind: kind,
                levels: (data.len() / (num_slices * num_faces)) as texture::Level,
                format: surface,
                bind: Bind::SHADER_RESOURCE,
                usage: Usage::Dynamic,
            };
            let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
            let raw = try!(factory.create_texture_raw(desc, Some(cty), Some((data, Mipmap::Provided))));
            let levels = (0, raw.get_info().levels - 1);
            let tex = Typed::new(raw);
            let view = try!(factory.view_texture_as_shader_resource::<T>(
                &tex, levels, format::Swizzle::new()
            ));
            Ok((tex, view))
        }

        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::texture::Kind::D2(width, height,
            gfx::texture::AaMode::Single);

        // FIXME Use get_min too. gfx has only one filter setting for both.
        let filter_method = match settings.get_mag() {
            texture::Filter::Nearest => gfx::texture::FilterMethod::Scale,
            texture::Filter::Linear => gfx::texture::FilterMethod::Bilinear,
        };
        let sampler_info = gfx::texture::SamplerInfo::new(
            filter_method,
            gfx::texture::WrapMode::Clamp
        );

        let (surface, view) = try!(create_texture::<Srgba8, F, R>(
            factory, tex_kind, &[memory])
        );
        let sampler = factory.create_sampler(sampler_info);
        Ok(Texture { surface: surface, sampler: sampler, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::texture::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::memory::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<commit_msg>Derive `Hash` and `Debug` for `Flip`<commit_after>#![deny(missing_docs)]

//! A Gfx texture representation that works nicely with Piston libraries.

extern crate gfx;
extern crate gfx_core;
extern crate texture;
extern crate image;

pub use texture::*;

use std::path::Path;
use image::{
    DynamicImage,
    RgbaImage,
};
use gfx::CombinedError;
use gfx::format::{Srgba8, R8_G8_B8_A8};

/// Flip settings.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Flip {
    /// Does not flip.
    None,
    /// Flips image vertically.
    Vertical,
    /// Flips image horizontally.
    Horizontal,
    /// Flips image both vertically and horizontally.
    Both,
}

/// Represents a texture.
#[derive(Clone, Debug, PartialEq)]
pub struct Texture<R> where R: gfx::Resources {
    /// Pixel storage for texture.
    pub surface: gfx::handle::Texture<R, R8_G8_B8_A8>,
    /// Sampler for texture.
    pub sampler: gfx::handle::Sampler<R>,
    /// View used by shader.
    pub view: gfx::handle::ShaderResourceView<R, [f32; 4]>
}

impl<R: gfx::Resources> Texture<R> {
    /// Returns empty texture.
    pub fn empty<F>(factory: &mut F) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        CreateTexture::create(factory, Format::Rgba8, &[0u8; 4], [1, 1],
                              &TextureSettings::new())
    }

    /// Creates a texture from path.
    pub fn from_path<F, P>(
        factory: &mut F,
        path: P,
        flip: Flip,
        settings: &TextureSettings,
    ) -> Result<Self, String>
        where F: gfx::Factory<R>,
              P: AsRef<Path>
    {
        let img = try!(image::open(path).map_err(|e| e.to_string()));

        let img = match img {
            DynamicImage::ImageRgba8(img) => img,
            img => img.to_rgba()
        };

        let img = match flip {
            Flip::Vertical => image::imageops::flip_vertical(&img),
            Flip::Horizontal => image::imageops::flip_horizontal(&img),
            Flip::Both => {
                let img = image::imageops::flip_vertical(&img);
                image::imageops::flip_horizontal(&img)
            }
            Flip::None => img,
        };

        Texture::from_image(factory, &img, settings).map_err(
            |e| format!("{:?}", e))
    }

    /// Creates a texture from image.
    pub fn from_image<F>(
        factory: &mut F,
        img: &RgbaImage,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        let (width, height) = img.dimensions();
        CreateTexture::create(factory, Format::Rgba8,
                              img, [width, height], settings)
    }

    /// Creates texture from memory alpha.
    pub fn from_memory_alpha<F>(
        factory: &mut F,
        buffer: &[u8],
        width: u32,
        height: u32,
        settings: &TextureSettings
    ) -> Result<Self, CombinedError>
        where F: gfx::Factory<R>
    {
        if width == 0 || height == 0 {
            return Texture::empty(factory);
        }

        let size = [width, height];
        let buffer = texture::ops::alpha_to_rgba8(buffer, size);
        CreateTexture::create(factory, Format::Rgba8, &buffer, size, settings)
    }

    /// Updates the texture with an image.
    pub fn update<C>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        img: &RgbaImage
    ) -> Result<(), gfx::UpdateError<[u16; 3]>>
        where C: gfx::CommandBuffer<R>
    {
        let (width, height) = img.dimensions();
        let offset = [0, 0];
        let size = [width, height];
        UpdateTexture::update(self, encoder, Format::Rgba8, img, offset, size)
    }
}

impl<F, R> CreateTexture<F> for Texture<R>
    where F: gfx::Factory<R>,
          R: gfx::Resources
{
    type Error = CombinedError;

    fn create<S: Into<[u32; 2]>>(
        factory: &mut F,
        _format: Format,
        memory: &[u8],
        size: S,
        settings: &TextureSettings
    ) -> Result<Self, Self::Error> {
        // Modified `Factory::create_texture_immutable_u8` for dynamic texture.
        fn create_texture<T, F, R>(
            factory: &mut F,
            kind: gfx::texture::Kind,
            data: &[&[u8]]
        ) -> Result<(
            gfx::handle::Texture<R, T::Surface>,
            gfx::handle::ShaderResourceView<R, T::View>
        ), CombinedError>
            where F: gfx::Factory<R>,
                  R: gfx::Resources,
                  T: gfx::format::TextureFormat
        {
            use gfx::{format, texture};
            use gfx::memory::{Usage, Bind};
            use gfx_core::memory::Typed;
            use gfx_core::texture::Mipmap;

            let surface = <T::Surface as format::SurfaceTyped>::get_surface_type();
            let num_slices = kind.get_num_slices().unwrap_or(1) as usize;
            let num_faces = if kind.is_cube() {6} else {1};
            let desc = texture::Info {
                kind: kind,
                levels: (data.len() / (num_slices * num_faces)) as texture::Level,
                format: surface,
                bind: Bind::SHADER_RESOURCE,
                usage: Usage::Dynamic,
            };
            let cty = <T::Channel as format::ChannelTyped>::get_channel_type();
            let raw = try!(factory.create_texture_raw(desc, Some(cty), Some((data, Mipmap::Provided))));
            let levels = (0, raw.get_info().levels - 1);
            let tex = Typed::new(raw);
            let view = try!(factory.view_texture_as_shader_resource::<T>(
                &tex, levels, format::Swizzle::new()
            ));
            Ok((tex, view))
        }

        let size = size.into();
        let (width, height) = (size[0] as u16, size[1] as u16);
        let tex_kind = gfx::texture::Kind::D2(width, height,
            gfx::texture::AaMode::Single);

        // FIXME Use get_min too. gfx has only one filter setting for both.
        let filter_method = match settings.get_mag() {
            texture::Filter::Nearest => gfx::texture::FilterMethod::Scale,
            texture::Filter::Linear => gfx::texture::FilterMethod::Bilinear,
        };
        let sampler_info = gfx::texture::SamplerInfo::new(
            filter_method,
            gfx::texture::WrapMode::Clamp
        );

        let (surface, view) = try!(create_texture::<Srgba8, F, R>(
            factory, tex_kind, &[memory])
        );
        let sampler = factory.create_sampler(sampler_info);
        Ok(Texture { surface: surface, sampler: sampler, view: view })
    }
}

impl<R, C> UpdateTexture<gfx::Encoder<R, C>> for Texture<R>
    where R: gfx::Resources,
          C: gfx::CommandBuffer<R>
{
    type Error = gfx::UpdateError<[u16; 3]>;

    fn update<O, S>(
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        format: Format,
        memory: &[u8],
        offset: O,
        size: S,
    ) -> Result<(), Self::Error>
        where O: Into<[u32; 2]>,
              S: Into<[u32; 2]>,
    {
        let offset = offset.into();
        let size = size.into();
        let tex = &self.surface;
        let face = None;
        let img_info = gfx::texture::ImageInfoCommon {
            xoffset: offset[0] as u16,
            yoffset: offset[1] as u16,
            zoffset: 0,
            width: size[0] as u16,
            height: size[1] as u16,
            depth: 0,
            format: (),
            mipmap: 0,
        };
        let data = gfx::memory::cast_slice(memory);

        match format {
            Format::Rgba8 => {
                use gfx::format::Rgba8;
                encoder.update_texture::<_, Rgba8>(tex, face, img_info, data).map_err(Into::into)
            },
        }
    }
}

impl<R> ImageSize for Texture<R> where R: gfx::Resources {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let (w, h, _, _) = self.surface.get_info().kind.get_dimensions();
        (w as u32, h as u32)
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};

pub struct Builder {
    name: String,
    ino: u32,
    mode: u32,
    uid: u32,
    gid: u32,
    nlink: u32,
    mtime: u32,
    dev_major: u32,
    dev_minor: u32,
    rdev_major: u32,
    rdev_minor: u32,
}

pub struct Writer<W: Write> {
    inner: W,
    written: u32,
    file_size: u32,
    header_size: usize,
    header: Vec<u8>,
}

fn pad(len: usize) -> Option<Vec<u8>> {
    // pad out to a multiple of 4 bytes
    let overhang = len % 4;
    if overhang != 0 {
        let repeat = 4 - overhang;
        Some(vec![0u8; repeat])
    } else {
        None
    }
}

impl Builder {
    pub fn new(name: &str) -> Builder {
        Builder {
            name: name.to_string(),
            ino: 0,
            mode: 0,
            uid: 0,
            gid: 0,
            nlink: 1,
            mtime: 0,
            dev_major: 0,
            dev_minor: 0,
            rdev_major: 0,
            rdev_minor: 0,
        }
    }

    pub fn ino(mut self, ino: u32) -> Builder {
        self.ino = ino;
        self
    }

    pub fn mode(mut self, mode: u32) -> Builder {
        self.mode = mode;
        self
    }

    pub fn uid(mut self, uid: u32) -> Builder {
        self.uid = uid;
        self
    }

    pub fn gid(mut self, gid: u32) -> Builder {
        self.gid = gid;
        self
    }

    pub fn nlink(mut self, nlink: u32) -> Builder {
        self.nlink = nlink;
        self
    }

    pub fn mtime(mut self, mtime: u32) -> Builder {
        self.mtime = mtime;
        self
    }

    pub fn dev_major(mut self, dev_major: u32) -> Builder {
        self.dev_major = dev_major;
        self
    }

    pub fn dev_minor(mut self, dev_minor: u32) -> Builder {
        self.dev_minor = dev_minor;
        self
    }

    pub fn rdev_major(mut self, rdev_major: u32) -> Builder {
        self.rdev_major = rdev_major;
        self
    }

    pub fn rdev_minor(mut self, rdev_minor: u32) -> Builder {
        self.rdev_minor = rdev_minor;
        self
    }

    pub fn write<W: Write>(self, w: W, file_size: u32) -> Writer<W> {
        let header = self.into_header(file_size);

        Writer {
            inner: w,
            written: 0,
            file_size: file_size,
            header_size: header.len(),
            header: header,
        }
    }

    fn into_header(self, file_size: u32) -> Vec<u8> {
        let mut header = Vec::with_capacity(110);

        // char    c_magic[6];
        header.extend("070701".to_string().as_bytes());
        // char    c_ino[8];
        header.extend(format!("{:08x}", self.ino).as_bytes());
        // char    c_mode[8];
        header.extend(format!("{:08x}", self.mode).as_bytes());
        // char    c_uid[8];
        header.extend(format!("{:08x}", self.uid).as_bytes());
        // char    c_gid[8];
        header.extend(format!("{:08x}", self.gid).as_bytes());
        // char    c_nlink[8];
        header.extend(format!("{:08x}", self.nlink).as_bytes());
        // char    c_mtime[8];
        header.extend(format!("{:08x}", self.mtime).as_bytes());
        // char    c_filesize[8];
        header.extend(format!("{:08x}", file_size).as_bytes());
        // char    c_devmajor[8];
        header.extend(format!("{:08x}", self.dev_major).as_bytes());
        // char    c_devminor[8];
        header.extend(format!("{:08x}", self.dev_minor).as_bytes());
        // char    c_rdevmajor[8];
        header.extend(format!("{:08x}", self.rdev_major).as_bytes());
        // char    c_rdevminor[8];
        header.extend(format!("{:08x}", self.rdev_minor).as_bytes());
        // char    c_namesize[8];
        let name_len = self.name.len();
        header.extend(format!("{:08x}", name_len).as_bytes());
        // char    c_check[8];
        header.extend(format!("{:08x}", 0).as_bytes());

        // append the name to the end of the header
        header.extend(self.name.as_bytes());

        // pad out to a multiple of 4 bytes
        if let Some(pad) = pad(name_len) {
            header.extend(pad);
        }

        header
    }
}

impl<W: Write> Writer<W> {
    pub fn finish(mut self) -> io::Result<W> {
        try!(self.do_finish());
        Ok(self.inner)
    }

    fn try_write_header(&mut self) -> io::Result<()> {
        if self.header.len() != 0 {
            try!(self.inner.write_all(&self.header));
            self.header.truncate(0);
        }
        Ok(())
    }

    fn do_finish(&mut self) -> io::Result<()> {
        try!(self.try_write_header());

        if self.written == self.file_size {
            if let Some(pad) = pad(self.header_size + self.file_size as usize) {
                try!(self.inner.write(&pad));
                try!(self.inner.flush());
            }
        }

        Ok(())
    }
}

impl<W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.written + buf.len() as u32 <= self.file_size {
            try!(self.try_write_header());

            let n = try!(self.inner.write(buf));
            self.written += n as u32;
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                               "trying to write more than the specified file size"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::Write;

    #[test]
    fn test_single_file() {
         let data = "Hello, World".to_string();

         let fp = File::create("/tmp/test_single.cpio").unwrap();

         let b = Builder::new("/tmp/hello_world");
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let _ = writer.finish().unwrap();
    }

    #[test]
    fn test_multi_file() {
         let data = "Hello, World".to_string();

         let fp = File::create("/tmp/test_multi.cpio").unwrap();

         let b = Builder::new("/tmp/hello_world")
                    .ino(1);
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let fp = writer.finish().unwrap();

         let b = Builder::new("/tmp/hello_world2")
                    .ino(2);
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let _ = writer.finish().unwrap();
    }
}
<commit_msg>fix the padding of filenames<commit_after>use std::io::{self, Write};

const HEADER_LEN: usize = 110;

pub struct Builder {
    name: String,
    ino: u32,
    mode: u32,
    uid: u32,
    gid: u32,
    nlink: u32,
    mtime: u32,
    dev_major: u32,
    dev_minor: u32,
    rdev_major: u32,
    rdev_minor: u32,
}

pub struct Writer<W: Write> {
    inner: W,
    written: u32,
    file_size: u32,
    header_size: usize,
    header: Vec<u8>,
}

fn pad(len: usize) -> Option<Vec<u8>> {
    // pad out to a multiple of 4 bytes
    let overhang = len % 4;
    if overhang != 0 {
        let repeat = 4 - overhang;
        Some(vec![0u8; repeat])
    } else {
        None
    }
}

impl Builder {
    pub fn new(name: &str) -> Builder {
        Builder {
            name: name.to_string(),
            ino: 0,
            mode: 0,
            uid: 0,
            gid: 0,
            nlink: 1,
            mtime: 0,
            dev_major: 0,
            dev_minor: 0,
            rdev_major: 0,
            rdev_minor: 0,
        }
    }

    pub fn ino(mut self, ino: u32) -> Builder {
        self.ino = ino;
        self
    }

    pub fn mode(mut self, mode: u32) -> Builder {
        self.mode = mode;
        self
    }

    pub fn uid(mut self, uid: u32) -> Builder {
        self.uid = uid;
        self
    }

    pub fn gid(mut self, gid: u32) -> Builder {
        self.gid = gid;
        self
    }

    pub fn nlink(mut self, nlink: u32) -> Builder {
        self.nlink = nlink;
        self
    }

    pub fn mtime(mut self, mtime: u32) -> Builder {
        self.mtime = mtime;
        self
    }

    pub fn dev_major(mut self, dev_major: u32) -> Builder {
        self.dev_major = dev_major;
        self
    }

    pub fn dev_minor(mut self, dev_minor: u32) -> Builder {
        self.dev_minor = dev_minor;
        self
    }

    pub fn rdev_major(mut self, rdev_major: u32) -> Builder {
        self.rdev_major = rdev_major;
        self
    }

    pub fn rdev_minor(mut self, rdev_minor: u32) -> Builder {
        self.rdev_minor = rdev_minor;
        self
    }

    pub fn write<W: Write>(self, w: W, file_size: u32) -> Writer<W> {
        let header = self.into_header(file_size);

        Writer {
            inner: w,
            written: 0,
            file_size: file_size,
            header_size: header.len(),
            header: header,
        }
    }

    fn into_header(self, file_size: u32) -> Vec<u8> {
        let mut header = Vec::with_capacity(HEADER_LEN);

        // char    c_magic[6];
        header.extend("070701".to_string().as_bytes());
        // char    c_ino[8];
        header.extend(format!("{:08x}", self.ino).as_bytes());
        // char    c_mode[8];
        header.extend(format!("{:08x}", self.mode).as_bytes());
        // char    c_uid[8];
        header.extend(format!("{:08x}", self.uid).as_bytes());
        // char    c_gid[8];
        header.extend(format!("{:08x}", self.gid).as_bytes());
        // char    c_nlink[8];
        header.extend(format!("{:08x}", self.nlink).as_bytes());
        // char    c_mtime[8];
        header.extend(format!("{:08x}", self.mtime).as_bytes());
        // char    c_filesize[8];
        header.extend(format!("{:08x}", file_size).as_bytes());
        // char    c_devmajor[8];
        header.extend(format!("{:08x}", self.dev_major).as_bytes());
        // char    c_devminor[8];
        header.extend(format!("{:08x}", self.dev_minor).as_bytes());
        // char    c_rdevmajor[8];
        header.extend(format!("{:08x}", self.rdev_major).as_bytes());
        // char    c_rdevminor[8];
        header.extend(format!("{:08x}", self.rdev_minor).as_bytes());
        // char    c_namesize[8];
        let name_len = self.name.len() + 1;
        header.extend(format!("{:08x}", name_len).as_bytes());
        // char    c_check[8];
        header.extend(format!("{:08x}", 0).as_bytes());

        // append the name to the end of the header
        header.extend(self.name.as_bytes());
        header.push(0u8);

        // pad out to a multiple of 4 bytes
        if let Some(pad) = pad(HEADER_LEN + name_len) {
            header.extend(pad);
        }

        header
    }
}

impl<W: Write> Writer<W> {
    pub fn finish(mut self) -> io::Result<W> {
        try!(self.do_finish());
        Ok(self.inner)
    }

    fn try_write_header(&mut self) -> io::Result<()> {
        if self.header.len() != 0 {
            try!(self.inner.write_all(&self.header));
            self.header.truncate(0);
        }
        Ok(())
    }

    fn do_finish(&mut self) -> io::Result<()> {
        try!(self.try_write_header());

        if self.written == self.file_size {
            if let Some(pad) = pad(self.header_size + self.file_size as usize) {
                try!(self.inner.write(&pad));
                try!(self.inner.flush());
            }
        }

        Ok(())
    }
}

impl<W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.written + buf.len() as u32 <= self.file_size {
            try!(self.try_write_header());

            let n = try!(self.inner.write(buf));
            self.written += n as u32;
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                               "trying to write more than the specified file size"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::Write;

    #[test]
    fn test_single_file() {
         let data = "Hello, World".to_string();

         let fp = File::create("/tmp/test_single.cpio").unwrap();

         let b = Builder::new("/tmp/hello_world");
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let _ = writer.finish().unwrap();
    }

    #[test]
    fn test_multi_file() {
         let data = "Hello, World".to_string();

         let fp = File::create("/tmp/test_multi.cpio").unwrap();

         let b = Builder::new("/tmp/hello_world")
                    .ino(1);
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let fp = writer.finish().unwrap();

         let b = Builder::new("/tmp/hello_world2")
                    .ino(2);
         let mut writer = b.write(fp, data.len() as u32);
         writer.write_all(data.as_bytes()).unwrap();
         writer.flush().unwrap();
         let _ = writer.finish().unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(step_by)]

extern crate libc;
pub extern crate nix;

use nix::sys::ptrace;
pub use nix::sys::ptrace::ptrace::*;
use nix::sys::signal;
use std::ptr;
use std::default::Default;
use std::vec::Vec;
use std::mem;

pub type Address = usize;
pub type Word = usize;
pub type IWord = isize;

#[derive(Clone, Copy, Default, Debug)]
pub struct Registers {
    pub r15: Word,
    pub r14: Word,
    pub r13: Word,
    pub r12: Word,
    pub rbp: Word,
    pub rbx: Word,
    pub r11: Word,
    pub r10: Word,
    pub r9: Word,
    pub r8: Word,
    pub rax: Word,
    pub rcx: Word,
    pub rdx: Word,
    pub rsi: Word,
    pub rdi: Word,
    pub orig_rax: Word,
    pub rip: Word,
    pub cs: Word,
    pub eflags: Word,
    pub rsp: Word,
    pub ss: Word,
    pub fs_base: Word,
    pub gs_base: Word,
    pub ds: Word,
    pub es: Word,
    pub fs: Word,
    pub gs: Word
}

fn ptrace_raw(request: PtraceRequest, pid: libc::pid_t, addr: *mut libc::c_void, data: *mut libc::c_void) -> Result<libc::c_long, i32> {
    match ptrace::ptrace(request, pid, addr, data) {
        Ok(v) => Ok(v),
        Err(e) => match e {
            nix::Error::Sys(errno) => Err(errno as i32),
            nix::Error::InvalidPath => panic!("nix InvalidPath caught"),
        },
    }
}
pub fn setoptions(pid: libc::pid_t, options: PtraceOptions) -> Result<(), i32> {
    match ptrace::ptrace_setoptions(pid, options) {
        Ok(v) => Ok(v),
        Err(e) => match e {
            nix::Error::Sys(errno) => Err(errno as i32),
            nix::Error::InvalidPath => panic!("nix InvalidPath caught"),
        },
    }
}

pub fn getregs(pid: libc::pid_t) -> Result<Registers, i32> {
    let mut buf: Registers = Default::default();
    let buf_mut: *mut Registers = &mut buf;

    match ptrace_raw(PTRACE_GETREGS, pid, ptr::null_mut(), buf_mut as *mut libc::c_void) {
        Ok(_) => Ok(buf),
        Err(e) => Err(e)
    }
}

pub fn setregs(pid: libc::pid_t, regs: &Registers) -> Result<libc::c_long, i32> {
    let buf: *mut libc::c_void = unsafe { mem::transmute(regs) };
    ptrace_raw(PTRACE_SETREGS, pid, ptr::null_mut(), buf)
}

pub fn seize(pid: libc::pid_t) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_SEIZE, pid, ptr::null_mut(), ptr::null_mut())
}

pub fn attach(pid: libc::pid_t) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_ATTACH, pid, ptr::null_mut(), ptr::null_mut())
}

pub fn release(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_DETACH, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn cont(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_CONT, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn cont_syscall(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_SYSCALL, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn traceme() -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_TRACEME, 0, ptr::null_mut(), ptr::null_mut())
}

#[derive(Clone, Copy, Debug)]
pub struct Syscall {
    pub args: [Word; 6],
    pub call: Word,
    pub pid: libc::pid_t,
    pub return_val: IWord
}

impl Syscall {
    pub fn from_pid(pid: libc::pid_t) -> Result<Syscall, i32> {
        match getregs(pid) {
            Ok(regs) =>
                Ok(Syscall {
                    pid: pid,
                    call: regs.orig_rax,
                    args: [regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9],
                    return_val: regs.rax as IWord
                }),
            Err(e) => Err(e)
        }
    }

    pub fn write(&self) -> Result<libc::c_long, i32> {
        match getregs(self.pid) {
            Ok(mut regs) => {
                regs.rdi = self.args[0];
                regs.rsi = self.args[1];
                regs.rdx = self.args[2];
                regs.rcx = self.args[3];
                regs.r8 = self.args[4];
                regs.r9 = self.args[5];
                regs.orig_rax = self.call;
                regs.rax = self.return_val as Word;
                setregs(self.pid, &regs)
            },
            Err(e) => Err(e)
        }
    }
}

#[derive(Clone, Copy)]
pub struct Reader {
    pub pid: libc::pid_t
}

#[derive(Clone, Copy)]
pub struct Writer {
    pub pid: libc::pid_t
}

impl Writer {
    pub fn new(pid: libc::pid_t) -> Self {
        Writer {
            pid: pid
        }
    }

    pub fn poke_data(&self, address: Address, data: Word) -> Result<Word, i32> {
        match ptrace_raw(PTRACE_POKEDATA, self.pid, address as *mut libc::c_void,
                             data as *mut libc::c_void) {
            Err(e) => Err(e),
            Ok(r) => Ok(r as Word)
        }
    }

    pub fn write_object<T: Sized>(&self, address: Address, data: &T) -> Result<(), usize> {
        let mut buf = Vec::with_capacity(mem::size_of::<T>());
        unsafe {
            let tptr: *const T = data;
            let p: *const u8 = mem::transmute(tptr);
            for i in 0..buf.capacity() {
                buf.push(*p.offset(i as isize));
            }
        }

        Ok(())
    }

    pub fn write_data(&self, address: Address, buf: &Vec<u8>) -> Result<(), i32> {
        // The end of our range
        let max_addr = address + buf.len() as Address;
        // The last word we can completely overwrite
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        for write_addr in (address..align_end).step_by(mem::size_of::<Word>() as Address) {
            let mut d: Word = 0;
            let buf_idx = (write_addr - address) as usize;
            for word_idx in 0..mem::size_of::<Word>() {
                d = set_byte(d, word_idx, buf[buf_idx + word_idx]);
            }
            match self.poke_data(write_addr, d) {
                Ok(_) => {},
                Err(e) => return Err(e)
            }
        }
        // Handle a partial word overwrite
        if max_addr > align_end {
            let buf_start = buf.len() - (max_addr - align_end) as usize;
            let r = Reader::new(self.pid);
            let mut d = match r.peek_data(align_end) {
                Ok(v) => v,
                Err(e) => return Err(e)
            };
            for word_idx in 0..mem::size_of::<Word>() - 2 {
                let buf_idx = buf_start + word_idx;
                d = set_byte(d, word_idx, buf[buf_idx]);
            }
            match self.poke_data(align_end, d) {
                Ok(_) => {},
                Err(e) => return Err(e)
            }
        }
        Ok(())
    }
}

impl Reader {
    pub fn new(pid: libc::pid_t) -> Reader {
        Reader {
            pid: pid
        }
    }

    pub fn peek_data(&self, address: Address) -> Result<Word, i32> {
        match ptrace_raw(PTRACE_PEEKDATA, self.pid, address as *mut libc::c_void, ptr::null_mut()) {
            Ok(v) => Ok(v as Word),
            Err(e) => Err(e),
        }
    }

    pub fn read_string(&self, address: Address) -> Result<Vec<u8>, i32> {
        let mut end_of_str = false;
        let mut buf: Vec<u8> = Vec::with_capacity(1024);
        let max_addr = address + buf.capacity() as Address;
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        'finish: for read_addr in (address..align_end).step_by(mem::size_of::<Word>() as Address) {
            let d;
            match self.peek_data(read_addr) {
                Ok(v) => d = v,
                Err(e) => return Err(e)
            }
            for word_idx in 0..mem::size_of::<Word>() {
                let chr = get_byte(d, word_idx);
                if chr == 0 {
                    end_of_str = true;
                    break 'finish;
                }
                buf.push(chr);
            }
        }
        if !end_of_str {
            let d;
            match self.peek_data(align_end) {
                Ok(v) => d = v,
                Err(e) => return Err(e)
            }
            for word_idx in 0..mem::size_of::<Word>() {
                let chr = get_byte(d, word_idx);
                if chr == 0 {
                    break;
                }
                buf.push(chr);
            }
        }
        return Ok(buf);
    }
}

fn get_byte(d: Word, byte_idx: usize) -> u8 {
    assert!(byte_idx < mem::size_of::<Word>());
    ((d >> (byte_idx * 8)) & 0xff) as u8
}

fn set_byte(d: Word, byte_idx: usize, value: u8) -> Word {
    assert!(byte_idx < mem::size_of::<Word>());
    let shift = mem::size_of::<u8>() * 8 * byte_idx;
    let mask = 0xff << shift;
    (d & !mask) | (((value as Word) << shift) & mask)
}

#[test]
pub fn test_set_byte() {
    assert_eq!(set_byte(0, 0, 0), 0);
    assert_eq!(set_byte(0xffffffffffff, 0, 0xff), 0xffffffffffff);
    assert_eq!(set_byte(0xffffffffffff, 0, 0),    0xffffffffff00);
    assert_eq!(set_byte(0xffffffffffff, 0, 0xaa), 0xffffffffffaa);
    assert_eq!(set_byte(0xffffffffffff, 1, 0x00), 0xffffffff00ff);
    assert_eq!(set_byte(0xffffffffffff, 4, 0xaa), 0xffaaffffffff);
}

#[test]
pub fn test_get_byte() {
    assert_eq!(get_byte(0, 0), 0);
    assert_eq!(get_byte(0xffffffffffff, 0), 0xff);
    assert_eq!(get_byte(0xffffffffffaa, 0), 0xaa);
    assert_eq!(get_byte(0x0123456789ab, 1), 0x89);
    assert_eq!(get_byte(0x0123456789ab, 4), 0x23);
}
<commit_msg>Add missing (in nix) non-event ptrace options<commit_after>#![feature(step_by)]

extern crate libc;
pub extern crate nix;

use nix::sys::ptrace;
pub use nix::sys::ptrace::ptrace::*;
use nix::sys::signal;
use std::ptr;
use std::default::Default;
use std::vec::Vec;
use std::mem;

pub type Address = usize;
pub type Word = usize;
pub type IWord = isize;

pub const PTRACE_O_EXITKILL: PtraceOptions        = 1 << 20;
pub const PTRACE_O_SUSPEND_SECCOMP: PtraceOptions = 1 << 21;

#[derive(Clone, Copy, Default, Debug)]
pub struct Registers {
    pub r15: Word,
    pub r14: Word,
    pub r13: Word,
    pub r12: Word,
    pub rbp: Word,
    pub rbx: Word,
    pub r11: Word,
    pub r10: Word,
    pub r9: Word,
    pub r8: Word,
    pub rax: Word,
    pub rcx: Word,
    pub rdx: Word,
    pub rsi: Word,
    pub rdi: Word,
    pub orig_rax: Word,
    pub rip: Word,
    pub cs: Word,
    pub eflags: Word,
    pub rsp: Word,
    pub ss: Word,
    pub fs_base: Word,
    pub gs_base: Word,
    pub ds: Word,
    pub es: Word,
    pub fs: Word,
    pub gs: Word
}

fn ptrace_raw(request: PtraceRequest, pid: libc::pid_t, addr: *mut libc::c_void, data: *mut libc::c_void) -> Result<libc::c_long, i32> {
    match ptrace::ptrace(request, pid, addr, data) {
        Ok(v) => Ok(v),
        Err(e) => match e {
            nix::Error::Sys(errno) => Err(errno as i32),
            nix::Error::InvalidPath => panic!("nix InvalidPath caught"),
        },
    }
}
pub fn setoptions(pid: libc::pid_t, options: PtraceOptions) -> Result<(), i32> {
    match ptrace::ptrace_setoptions(pid, options) {
        Ok(v) => Ok(v),
        Err(e) => match e {
            nix::Error::Sys(errno) => Err(errno as i32),
            nix::Error::InvalidPath => panic!("nix InvalidPath caught"),
        },
    }
}

pub fn getregs(pid: libc::pid_t) -> Result<Registers, i32> {
    let mut buf: Registers = Default::default();
    let buf_mut: *mut Registers = &mut buf;

    match ptrace_raw(PTRACE_GETREGS, pid, ptr::null_mut(), buf_mut as *mut libc::c_void) {
        Ok(_) => Ok(buf),
        Err(e) => Err(e)
    }
}

pub fn setregs(pid: libc::pid_t, regs: &Registers) -> Result<libc::c_long, i32> {
    let buf: *mut libc::c_void = unsafe { mem::transmute(regs) };
    ptrace_raw(PTRACE_SETREGS, pid, ptr::null_mut(), buf)
}

pub fn seize(pid: libc::pid_t) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_SEIZE, pid, ptr::null_mut(), ptr::null_mut())
}

pub fn attach(pid: libc::pid_t) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_ATTACH, pid, ptr::null_mut(), ptr::null_mut())
}

pub fn release(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_DETACH, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn cont(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_CONT, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn cont_syscall(pid: libc::pid_t, signal: Option<signal::Signal>) -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_SYSCALL, pid, ptr::null_mut(), signal.map_or(0, |s| s as u32) as *mut libc::c_void)
}

pub fn traceme() -> Result<libc::c_long, i32> {
    ptrace_raw(PTRACE_TRACEME, 0, ptr::null_mut(), ptr::null_mut())
}

#[derive(Clone, Copy, Debug)]
pub struct Syscall {
    pub args: [Word; 6],
    pub call: Word,
    pub pid: libc::pid_t,
    pub return_val: IWord
}

impl Syscall {
    pub fn from_pid(pid: libc::pid_t) -> Result<Syscall, i32> {
        match getregs(pid) {
            Ok(regs) =>
                Ok(Syscall {
                    pid: pid,
                    call: regs.orig_rax,
                    args: [regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9],
                    return_val: regs.rax as IWord
                }),
            Err(e) => Err(e)
        }
    }

    pub fn write(&self) -> Result<libc::c_long, i32> {
        match getregs(self.pid) {
            Ok(mut regs) => {
                regs.rdi = self.args[0];
                regs.rsi = self.args[1];
                regs.rdx = self.args[2];
                regs.rcx = self.args[3];
                regs.r8 = self.args[4];
                regs.r9 = self.args[5];
                regs.orig_rax = self.call;
                regs.rax = self.return_val as Word;
                setregs(self.pid, &regs)
            },
            Err(e) => Err(e)
        }
    }
}

#[derive(Clone, Copy)]
pub struct Reader {
    pub pid: libc::pid_t
}

#[derive(Clone, Copy)]
pub struct Writer {
    pub pid: libc::pid_t
}

impl Writer {
    pub fn new(pid: libc::pid_t) -> Self {
        Writer {
            pid: pid
        }
    }

    pub fn poke_data(&self, address: Address, data: Word) -> Result<Word, i32> {
        match ptrace_raw(PTRACE_POKEDATA, self.pid, address as *mut libc::c_void,
                             data as *mut libc::c_void) {
            Err(e) => Err(e),
            Ok(r) => Ok(r as Word)
        }
    }

    pub fn write_object<T: Sized>(&self, address: Address, data: &T) -> Result<(), usize> {
        let mut buf = Vec::with_capacity(mem::size_of::<T>());
        unsafe {
            let tptr: *const T = data;
            let p: *const u8 = mem::transmute(tptr);
            for i in 0..buf.capacity() {
                buf.push(*p.offset(i as isize));
            }
        }

        Ok(())
    }

    pub fn write_data(&self, address: Address, buf: &Vec<u8>) -> Result<(), i32> {
        // The end of our range
        let max_addr = address + buf.len() as Address;
        // The last word we can completely overwrite
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        for write_addr in (address..align_end).step_by(mem::size_of::<Word>() as Address) {
            let mut d: Word = 0;
            let buf_idx = (write_addr - address) as usize;
            for word_idx in 0..mem::size_of::<Word>() {
                d = set_byte(d, word_idx, buf[buf_idx + word_idx]);
            }
            match self.poke_data(write_addr, d) {
                Ok(_) => {},
                Err(e) => return Err(e)
            }
        }
        // Handle a partial word overwrite
        if max_addr > align_end {
            let buf_start = buf.len() - (max_addr - align_end) as usize;
            let r = Reader::new(self.pid);
            let mut d = match r.peek_data(align_end) {
                Ok(v) => v,
                Err(e) => return Err(e)
            };
            for word_idx in 0..mem::size_of::<Word>() - 2 {
                let buf_idx = buf_start + word_idx;
                d = set_byte(d, word_idx, buf[buf_idx]);
            }
            match self.poke_data(align_end, d) {
                Ok(_) => {},
                Err(e) => return Err(e)
            }
        }
        Ok(())
    }
}

impl Reader {
    pub fn new(pid: libc::pid_t) -> Reader {
        Reader {
            pid: pid
        }
    }

    pub fn peek_data(&self, address: Address) -> Result<Word, i32> {
        match ptrace_raw(PTRACE_PEEKDATA, self.pid, address as *mut libc::c_void, ptr::null_mut()) {
            Ok(v) => Ok(v as Word),
            Err(e) => Err(e),
        }
    }

    pub fn read_string(&self, address: Address) -> Result<Vec<u8>, i32> {
        let mut end_of_str = false;
        let mut buf: Vec<u8> = Vec::with_capacity(1024);
        let max_addr = address + buf.capacity() as Address;
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        'finish: for read_addr in (address..align_end).step_by(mem::size_of::<Word>() as Address) {
            let d;
            match self.peek_data(read_addr) {
                Ok(v) => d = v,
                Err(e) => return Err(e)
            }
            for word_idx in 0..mem::size_of::<Word>() {
                let chr = get_byte(d, word_idx);
                if chr == 0 {
                    end_of_str = true;
                    break 'finish;
                }
                buf.push(chr);
            }
        }
        if !end_of_str {
            let d;
            match self.peek_data(align_end) {
                Ok(v) => d = v,
                Err(e) => return Err(e)
            }
            for word_idx in 0..mem::size_of::<Word>() {
                let chr = get_byte(d, word_idx);
                if chr == 0 {
                    break;
                }
                buf.push(chr);
            }
        }
        return Ok(buf);
    }
}

fn get_byte(d: Word, byte_idx: usize) -> u8 {
    assert!(byte_idx < mem::size_of::<Word>());
    ((d >> (byte_idx * 8)) & 0xff) as u8
}

fn set_byte(d: Word, byte_idx: usize, value: u8) -> Word {
    assert!(byte_idx < mem::size_of::<Word>());
    let shift = mem::size_of::<u8>() * 8 * byte_idx;
    let mask = 0xff << shift;
    (d & !mask) | (((value as Word) << shift) & mask)
}

#[test]
pub fn test_set_byte() {
    assert_eq!(set_byte(0, 0, 0), 0);
    assert_eq!(set_byte(0xffffffffffff, 0, 0xff), 0xffffffffffff);
    assert_eq!(set_byte(0xffffffffffff, 0, 0),    0xffffffffff00);
    assert_eq!(set_byte(0xffffffffffff, 0, 0xaa), 0xffffffffffaa);
    assert_eq!(set_byte(0xffffffffffff, 1, 0x00), 0xffffffff00ff);
    assert_eq!(set_byte(0xffffffffffff, 4, 0xaa), 0xffaaffffffff);
}

#[test]
pub fn test_get_byte() {
    assert_eq!(get_byte(0, 0), 0);
    assert_eq!(get_byte(0xffffffffffff, 0), 0xff);
    assert_eq!(get_byte(0xffffffffffaa, 0), 0xaa);
    assert_eq!(get_byte(0x0123456789ab, 1), 0x89);
    assert_eq!(get_byte(0x0123456789ab, 4), 0x23);
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures)]

use std::fmt;

pub use api::IntoLogger;
pub use api::Logger;
pub use config::Logger as LoggerConfig;
pub use config::Output as LoggerOutput;

mod config;
mod api;
mod loggers;

pub enum Level {
    Debug,
    Info,
    Warning,
    Error,
    Critical,
}

impl Copy for Level {}

impl Level {
    pub fn as_int(&self) -> u8 {
        match self {
            &Level::Debug => 0u8,
            &Level::Info => 1u8,
            &Level::Warning => 2u8,
            &Level::Error => 3u8,
            &Level::Critical => 4u8,
        }
    }
}

impl fmt::Show for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        return write!(f, "{}", match self {
            &Level::Debug => "DEBUG",
            &Level::Info => "INFO",
            &Level::Warning => "WARNING",
            &Level::Error => "ERROR",
            &Level::Critical => "CRITICAL",
        });
    }
}
<commit_msg>Replace Error and Critical levels with the Severe warning level<commit_after>#![feature(unboxed_closures)]

use std::fmt;

pub use api::IntoLogger;
pub use api::Logger;
pub use config::Logger as LoggerConfig;
pub use config::Output as LoggerOutput;

mod config;
mod api;
mod loggers;

pub enum Level {
    Debug,
    Info,
    Warning,
    Severe,
}

impl Copy for Level {}

impl Level {
    pub fn as_int(&self) -> u8 {
        match self {
            &Level::Debug => 0u8,
            &Level::Info => 1u8,
            &Level::Warning => 2u8,
            &Level::Severe => 3u8,
        }
    }
}

impl fmt::Show for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        return write!(f, "{}", match self {
            &Level::Debug => "DEBUG",
            &Level::Info => "INFO",
            &Level::Warning => "WARNING",
            &Level::Severe => "SEVERE",
        });
    }
}
<|endoftext|>


<commit_before>
use std::f32;
use std::vec;
use std::collections::HashMap;
use std::collections::hash_set::HashSet;

extern crate ocl;
use ocl::{ProQue, Buffer};

static KERNEL_SOURCE: &'static str = include_str!("kernel_source.cl");

type Dimension = (usize, usize);
type NodeId = usize;

//		ActivationFunction::Sigmoid => 1.0f32/(1.0 + (-value).exp()),

struct Node<F> {
	id : NodeId,
	shape : Dimension,
	inputs : Vec<NodeId>,
	operation : F,
	buffer : Vec<f32>,
}

impl<F> Node<F> {
	fn get_value(&self, x : usize, y : usize) -> f32 {
		self.buffer[x + y*self.shape.1]
	}

	fn set_value(&mut self, x : usize, y : usize, value : f32) {
		self.buffer[x + y*self.shape.1] = value;
	}

	fn get_rows(&self) -> usize {
		self.shape.0
	}

	fn get_columns(&self) -> usize {
		self.shape.1
	}

	fn get_width(&self) -> usize {
		self.shape.1
	}

	fn get_height(&self) -> usize {
		self.shape.0
	}
}

struct Graph<F> {
//	proque : ProQue,
	nodes : Vec<Node<F>>,
}

impl<F> Graph<F> where F: Fn(f32, f32)->f32 {
	fn new() -> Graph<F> {
		Graph {
//			proque : ProQue::builder().src(KERNEL_SOURCE).dims([3]).build().unwrap(),
			nodes : vec![],
		}
	}

	// Graph methods
	fn get_output(&mut self, node_id : NodeId, input_map : &HashMap<NodeId, Vec<f32>>) -> Vec<f32> {
		//(node.operation)(&self, input_map)
		vec![]
/*
		match self.nodes[node_id].operation {
			Operation::Input => input_map.get(&node_id).unwrap().clone(),
			Operation::MatrixMultiply(n1, n2) => {
				// Verify shapes
				let a_width = self.nodes[n1].shape.1; // Columns (j)
				let a_height = self.nodes[n1].shape.0; // Rows (i)
				let b_width = self.nodes[n2].shape.1; // Columns (k)
				let b_height = self.nodes[n2].shape.0; // Rows (j)
				let c_width = b_width;
				let c_height = a_height;
				assert_eq!(a_width, b_height);
				assert_eq!(a_height*b_width, self.nodes[node_id].buffer.len());

				// Set up the buffer for this node.
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);

				// Multiply
				for i in 0..a_height { // Column [Iterating over row]
					for k in 0..b_width { // Row/Width [Iterating over column]
						let mut accumulator = 0.0;
						for j in 0..a_width { // Column
							accumulator += a[j + i*a_width]*b[k + j*b_width];
						}
						self.nodes[node_id].buffer[k + i*c_width] = accumulator;
					}
				}

				self.nodes[node_id].buffer.clone()
			},
			Operation::MatrixBinaryOp(n1, n2, f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);

				let vec_len = self.nodes[node_id].buffer.len();

				for i in 0..vec_len {
					self.nodes[node_id].buffer[i] = f(a[i], b[i]);
				}

				self.nodes[node_id].buffer.clone()
			},
			Operation::MatrixUnaryOp(n1, f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let vec_len = self.nodes[node_id].buffer.len();

				for i in 0..vec_len {
					self.nodes[node_id].buffer[i] = f(a[i], i as f32);
				}

				self.nodes[node_id].buffer.clone()
			}
		}
*/
	}

	// Node creation
	fn new_input(&mut self, shape : Dimension) -> NodeId {
		let mut n = Node {
			id : 0,
			inputs: vec![],
			shape : shape,
			operation : |a, b| { 0.0 },
			buffer : vec![0.0; shape.0*shape.1], //self.proque.create_buffer::<f32>().unwrap()
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}

	fn new_matmul(&mut self, node_a_id : NodeId, node_b_id : NodeId) -> NodeId {
		let mut n = Node {
			id : 0,
			inputs: vec![],
			shape : (self.nodes[node_a_id].shape.0, self.nodes[node_b_id].shape.1),
			operation : |a, b| { 0.0 },
			buffer : vec![0.0; self.nodes[node_a_id].shape.0*self.nodes[node_b_id].shape.1],
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}
}

#[cfg(test)]
mod tests {
	use super::{Graph, Dimension, Node, NodeId};
	use std::collections::HashMap;

	#[test]
	fn test_identity() {
		// Build graph
		let mut input = HashMap::new();
		let mut g = Graph::new();
		let m : NodeId = g.new_input((3, 3));
		let n : NodeId = g.new_input((1, 3));
		let o = g.new_matmul(n, m);
		let j : NodeId = g.new_input((3, 5));
		let k = g.new_matmul(m, j);

		// Shape check
		assert_eq!(g.nodes[m].shape, (3, 3));
		assert_eq!(g.nodes[n].shape, (1, 3));
		assert_eq!(g.nodes[o].shape, (1, 3));

		// Configure data
		input.insert(m, vec![
			1.0, 0.0, 0.0,
			0.0, 1.0, 0.0,
			0.0, 0.0, 1.0
		]);
		input.insert(n, vec![
			0.0, 1.0, 2.0
		]);
		input.insert(j, vec![
			1.0, 2.0, 3.0,
			4.0, 5.0, 6.0,
			7.0, 8.0, 9.0,
			10.0, 11.0, 12.0,
			13.0, 14.0, 15.0
		]);

		// Verify outputs
		let res = g.get_output(o, &input);
		assert_eq!(res[0], 0.0);
		assert_eq!(res[1], 1.0);
		assert_eq!(res[2], 2.0);
		let res2 = g.get_output(k, &input);
		for i in 0..15 {
			assert_eq!(res2[i], (i as f32+1.0));
		}
	}

    #[test]
    fn integration_full_test() {
		let g = Graph::new();
    }
}
<commit_msg>Fix problem with borrowing.  Add ability to insert element-wise operations.<commit_after>
use std::f32;
use std::vec;
use std::collections::HashMap;
use std::collections::hash_set::HashSet;

extern crate ocl;
use ocl::{ProQue, Buffer};

static KERNEL_SOURCE: &'static str = include_str!("kernel_source.cl");

type Dimension = (usize, usize);
type NodeId = usize;

//		ActivationFunction::Sigmoid => 1.0f32/(1.0 + (-value).exp()),

enum Operation {
	Input,
	MatrixMultiply(NodeId, NodeId),
	BinaryElement(NodeId, NodeId, Box<Fn(f32,f32)->f32>),
	UnaryElement(NodeId, Box<Fn(f32)->f32>),
}

struct Node {
	id : NodeId,
	shape : Dimension,
	operation : Operation,
}

struct Graph {
//	proque : ProQue,
	nodes : Vec<Node>,
}

impl Graph {
	fn new() -> Graph {
		Graph {
//			proque : ProQue::builder().src(KERNEL_SOURCE).dims([3]).build().unwrap(),
			nodes : vec![],
		}
	}

	// Graph methods
	fn get_output(&self, node_id : NodeId, input_map : &HashMap<NodeId, Vec<f32>>) -> Vec<f32> {
		//(node.operation)(&self, input_map)
		match self.nodes[node_id].operation {
			Operation::Input => { input_map.get(&node_id).unwrap().clone() },
			Operation::MatrixMultiply(n1, n2) => {
				// Verify shapes
				let a_width = self.nodes[n1].shape.1; // Columns (j)
				let a_height = self.nodes[n1].shape.0; // Rows (i)
				let b_width = self.nodes[n2].shape.1; // Columns (k)
				let b_height = self.nodes[n2].shape.0; // Rows (j)
				let c_width = b_width;
				let c_height = a_height;
				assert_eq!(a_width, b_height);

				let mut result = vec![0.0; a_height*b_width];

				// Set up the buffer for this node.
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);

				// Multiply
				for i in 0..a_height { // Column [Iterating over row]
					for k in 0..b_width { // Row/Width [Iterating over column]
						let mut accumulator = 0.0;
						for j in 0..a_width { // Column
							accumulator += a[j + i*a_width]*b[k + j*b_width];
						}
						result[k + i*c_width] = accumulator;
					}
				}

				result
			},
			Operation::BinaryElement(n1, n2, ref f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let b : Vec<f32> = self.get_output(n2, &input_map);
				let mut result = vec![0.0; a.len()];
				let vec_len = result.len();

				for i in 0..vec_len {
					result[i] = f(a[i], b[i]);
				}

				result
			},
			Operation::UnaryElement(n1, ref f) => {
				let a : Vec<f32> = self.get_output(n1, &input_map);
				let vec_len = a.len();
				let mut result = vec![0.0; vec_len];

				for i in 0..vec_len {
					result[i] = f(a[i]);
				}
				result
			}
		}
	}

	// Node creation
	fn new_input(&mut self, shape : Dimension) -> NodeId {
		let mut n = Node {
			id : 0,
			shape : shape,
			operation : Operation::Input,
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}

	fn new_matmul(&mut self, node_a_id : NodeId, node_b_id : NodeId) -> NodeId {
		let mut n = Node {
			id : 0,
			shape : (self.nodes[node_a_id].shape.0, self.nodes[node_b_id].shape.1),
			//operation : Operation::BinaryElement(node_a_id, node_b_id, Box::new(|a, b| { 0.0 })),
			operation : Operation::MatrixMultiply(node_a_id, node_b_id),
		};
		self.nodes.push(n);
		let id = self.nodes.len()-1;
		n.id = id;
		id
	}
}

#[cfg(test)]
mod tests {
	use super::{Graph, Dimension, Node, NodeId};
	use std::collections::HashMap;

	#[test]
	fn test_identity() {
		// Build graph
		let mut input = HashMap::new();
		let mut g = Graph::new();
		let m : NodeId = g.new_input((3, 3));
		let n : NodeId = g.new_input((1, 3));
		let o = g.new_matmul(n, m);
		let j : NodeId = g.new_input((3, 5));
		let k = g.new_matmul(m, j);

		// Shape check
		assert_eq!(g.nodes[m].shape, (3, 3));
		assert_eq!(g.nodes[n].shape, (1, 3));
		assert_eq!(g.nodes[o].shape, (1, 3));

		// Configure data
		input.insert(m, vec![
			1.0, 0.0, 0.0,
			0.0, 1.0, 0.0,
			0.0, 0.0, 1.0
		]);
		input.insert(n, vec![
			0.0, 1.0, 2.0
		]);
		input.insert(j, vec![
			1.0, 2.0, 3.0,
			4.0, 5.0, 6.0,
			7.0, 8.0, 9.0,
			10.0, 11.0, 12.0,
			13.0, 14.0, 15.0
		]);

		// Verify outputs
		let res = g.get_output(o, &input);
		assert_eq!(res[0], 0.0);
		assert_eq!(res[1], 1.0);
		assert_eq!(res[2], 2.0);
		let res2 = g.get_output(k, &input);
		for i in 0..15 {
			assert_eq!(res2[i], (i as f32+1.0));
		}
	}

    #[test]
    fn integration_full_test() {
		let g = Graph::new();
    }
}
<|endoftext|>


<commit_before>pub mod classifier;
pub mod model;

mod ngrams;
mod tests;
<commit_msg>Silence unused code warnings in tests<commit_after>pub mod classifier;
pub mod model;

mod ngrams;

#[cfg(test)] mod tests;
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::ops::{
    Deref,
    DerefMut,
};
use std::slice;
use std::convert::From;

/// Make sure the non-nullable pointer optimization does not occur!
enum Flag<T> {
    Alive(T),
    Dropped,
    _Unused,
}

#[derive(Debug)]
struct Dud(i32);

impl Drop for Dud {
    fn drop(&mut self) {
        let Dud(ref i) = *self;
        println!("Drop Dud({})", *i);
    }
}

/// Trait for fixed size arrays.
pub unsafe trait Array {
    type Item;
    unsafe fn new() -> Self;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity() -> usize;
}

macro_rules! fix_array_impl {
    ($len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            unsafe fn new() -> [T; $len] { mem::uninitialized() }
            #[inline]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    () => ();
    ($len:expr, $($more:expr,)*) => (
        fix_array_impl!($len);
        fix_array_impl_recursive!($($more,)*);
    );
}

fix_array_impl_recursive!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 48, 64, 96, 128,);

/// A vector with a fixed capacity.
///
/// The **ArrayVec** is backed by a fixed size array and keeps track of
/// the number of initialized elements.
///
/// The ArrayVec is a congiguous value that you can store directly on the stack
/// if needed.
pub struct ArrayVec<A: Array> {
    len: u8,
    xs: Flag<A>,
}

impl<A: Array> Drop for ArrayVec<A> {
    fn drop(&mut self) {
        // clear all elements, then inhibit drop of inner array
        while let Some(_) = self.pop() { }
        unsafe {
            ptr::write(&mut self.xs, Flag::Dropped);
        }
    }
}

impl<A: Array> ArrayVec<A> {
    pub fn new() -> ArrayVec<A> {
        unsafe {
            ArrayVec { xs: Flag::Alive(Array::new()), len: 0 }
        }
    }

    pub fn from(array: A) -> ArrayVec<A> {
        ArrayVec { xs: Flag::Alive(array), len: A::capacity() as u8 }
    }

    #[inline]
    pub fn capacity(&self) -> usize { A::capacity() }

    #[inline]
    fn array(&self) -> &A {
        match self.xs {
            Flag::Alive(ref xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    fn array_mut(&mut self) -> &mut A {
        // FIXME: Optimize this, we know it's always Some.
        match self.xs {
            Flag::Alive(ref mut xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    pub fn len(&self) -> usize { self.len as usize }

    pub fn push(&mut self, elt: A::Item) -> Option<A::Item> {
        if self.len() < A::capacity() {
            unsafe {
                let len = self.len();
                ptr::write(self.get_unchecked_mut(len), elt);
            }
            self.len += 1;
            None
        } else {
            Some(elt)
        }
    }

    pub fn pop(&mut self) -> Option<A::Item> {
        if self.len == 0 {
            return None
        }
        unsafe {
            self.len -= 1;
            let len = self.len();
            Some(ptr::read(self.get_unchecked_mut(len)))
        }
    }
}

impl<A: Array> Deref for ArrayVec<A> {
    type Target = [A::Item];
    #[inline]
    fn deref(&self) -> &[A::Item] {
        unsafe {
            slice::from_raw_parts(self.array().as_ptr(), self.len())
        }
    }
}

impl<A: Array> DerefMut for ArrayVec<A> {
    #[inline]
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let len = self.len();
        unsafe {
            slice::from_raw_parts_mut(self.array_mut().as_mut_ptr(), len)
        }
    }
}

impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
    type Item = &'a A::Item;
    type IntoIter = slice::Iter<'a, A::Item>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<A: Array> IntoIterator for ArrayVec<A> {
    type Item = A::Item;
    type IntoIter = IntoIter<A>;
    fn into_iter(self) -> IntoIter<A> {
        IntoIter { index: 0, v: self, }
    }
}

/// By-value iterator for ArrayVec.
pub struct IntoIter<A: Array> {
    index: u8,
    v: ArrayVec<A>,
}

impl<A: Array> Iterator for IntoIter<A> {
    type Item = A::Item;

    fn next(&mut self) -> Option<A::Item> {
        if self.index == self.v.len {
            None
        } else {
            unsafe {
                let ptr = self.v.get_unchecked_mut(self.index as usize);
                let elt = ptr::read(ptr);
                self.index += 1;
                Some(elt)
            }
        }
    }
}

impl<A: Array> Drop for IntoIter<A> {
    fn drop(&mut self) {
        // exhaust iterator and clear the vector
        while let Some(_) = self.next() { }
        self.v.len = 0;
    }
}

#[test]
fn test1() {
    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1,2,4,5]);
    vec.push(vec![3]);
    vec.push(vec![97,98,92]);

    for elt in vec {
        println!("{:?}", elt);
    }
}

fn main() {
    let mut v = ArrayVec::from([1, 2, 3]);
    v.push(4);
    v.push(5);
    println!("{:?}", v.pop());
    println!("{:?}", v.pop());
    println!("{:?}", &*v);
    v.pop();
    v.pop();
    v.push(8);
    println!("{:?}", &*v);

    let mut u: ArrayVec<[_; 3]> = ArrayVec::new();

    u.push(vec![1,2,4,5]);
    u.push(vec![3]);
    u.push(vec![97,98,92]);

    {
        let slc: &[_] = &u;
        println!("{:?}", slc);
    }
    println!("{:?}", u.pop());
    println!("{:?}", u.pop());
    println!("{:?}", u.len());
    println!("{:?}", u[0]);

    let mut v: ArrayVec<[Dud; 2]> = ArrayVec::new();
    v.push(Dud(1));
    v.push(Dud(2));
    v.pop();
    v.pop();
    v.pop();
    v.push(Dud(3));
    v.pop();
    v.push(Dud(4));
    v.push(Dud(5));
    v.push(Dud(6));
    //v.pop();

    println!("v: {:?}", &*v);

    for elt in &v { // slice iter
        println!("Slice Iter: {:?}", elt);
    }

    for elt in v {
        println!("Iter: {:?}", elt);
        //break;
    }

    for elt in ArrayVec::from(["a".to_string(), "b".to_string()]).into_iter() {
        println!("Iter: {:?}", elt);
    }
}
<commit_msg>More sizes<commit_after>use std::mem;
use std::ptr;
use std::ops::{
    Deref,
    DerefMut,
};
use std::slice;
use std::convert::From;

/// Make sure the non-nullable pointer optimization does not occur!
enum Flag<T> {
    Alive(T),
    Dropped,
    _Unused,
}

#[derive(Debug)]
struct Dud(i32);

impl Drop for Dud {
    fn drop(&mut self) {
        let Dud(ref i) = *self;
        println!("Drop Dud({})", *i);
    }
}

/// Trait for fixed size arrays.
pub unsafe trait Array {
    type Item;
    unsafe fn new() -> Self;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity() -> usize;
}

macro_rules! fix_array_impl {
    ($len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            unsafe fn new() -> [T; $len] { mem::uninitialized() }
            #[inline]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    () => ();
    ($len:expr, $($more:expr,)*) => (
        fix_array_impl!($len);
        fix_array_impl_recursive!($($more,)*);
    );
}

fix_array_impl_recursive!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,);

/// A vector with a fixed capacity.
///
/// The **ArrayVec** is backed by a fixed size array and keeps track of
/// the number of initialized elements.
///
/// The ArrayVec is a congiguous value that you can store directly on the stack
/// if needed.
pub struct ArrayVec<A: Array> {
    len: u8,
    xs: Flag<A>,
}

impl<A: Array> Drop for ArrayVec<A> {
    fn drop(&mut self) {
        // clear all elements, then inhibit drop of inner array
        while let Some(_) = self.pop() { }
        unsafe {
            ptr::write(&mut self.xs, Flag::Dropped);
        }
    }
}

impl<A: Array> ArrayVec<A> {
    pub fn new() -> ArrayVec<A> {
        unsafe {
            ArrayVec { xs: Flag::Alive(Array::new()), len: 0 }
        }
    }

    pub fn from(array: A) -> ArrayVec<A> {
        ArrayVec { xs: Flag::Alive(array), len: A::capacity() as u8 }
    }

    #[inline]
    pub fn capacity(&self) -> usize { A::capacity() }

    #[inline]
    fn array(&self) -> &A {
        match self.xs {
            Flag::Alive(ref xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    fn array_mut(&mut self) -> &mut A {
        // FIXME: Optimize this, we know it's always Some.
        match self.xs {
            Flag::Alive(ref mut xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    pub fn len(&self) -> usize { self.len as usize }

    pub fn push(&mut self, elt: A::Item) -> Option<A::Item> {
        if self.len() < A::capacity() {
            unsafe {
                let len = self.len();
                ptr::write(self.get_unchecked_mut(len), elt);
            }
            self.len += 1;
            None
        } else {
            Some(elt)
        }
    }

    pub fn pop(&mut self) -> Option<A::Item> {
        if self.len == 0 {
            return None
        }
        unsafe {
            self.len -= 1;
            let len = self.len();
            Some(ptr::read(self.get_unchecked_mut(len)))
        }
    }
}

impl<A: Array> Deref for ArrayVec<A> {
    type Target = [A::Item];
    #[inline]
    fn deref(&self) -> &[A::Item] {
        unsafe {
            slice::from_raw_parts(self.array().as_ptr(), self.len())
        }
    }
}

impl<A: Array> DerefMut for ArrayVec<A> {
    #[inline]
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let len = self.len();
        unsafe {
            slice::from_raw_parts_mut(self.array_mut().as_mut_ptr(), len)
        }
    }
}

impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
    type Item = &'a A::Item;
    type IntoIter = slice::Iter<'a, A::Item>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

impl<A: Array> IntoIterator for ArrayVec<A> {
    type Item = A::Item;
    type IntoIter = IntoIter<A>;
    fn into_iter(self) -> IntoIter<A> {
        IntoIter { index: 0, v: self, }
    }
}

/// By-value iterator for ArrayVec.
pub struct IntoIter<A: Array> {
    index: u8,
    v: ArrayVec<A>,
}

impl<A: Array> Iterator for IntoIter<A> {
    type Item = A::Item;

    fn next(&mut self) -> Option<A::Item> {
        if self.index == self.v.len {
            None
        } else {
            unsafe {
                let ptr = self.v.get_unchecked_mut(self.index as usize);
                let elt = ptr::read(ptr);
                self.index += 1;
                Some(elt)
            }
        }
    }
}

impl<A: Array> Drop for IntoIter<A> {
    fn drop(&mut self) {
        // exhaust iterator and clear the vector
        while let Some(_) = self.next() { }
        self.v.len = 0;
    }
}

#[test]
fn test1() {
    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1,2,4,5]);
    vec.push(vec![3]);
    vec.push(vec![97,98,92]);

    for elt in vec {
        println!("{:?}", elt);
    }
}

fn main() {
    let mut v = ArrayVec::from([1, 2, 3]);
    v.push(4);
    v.push(5);
    println!("{:?}", v.pop());
    println!("{:?}", v.pop());
    println!("{:?}", &*v);
    v.pop();
    v.pop();
    v.push(8);
    println!("{:?}", &*v);

    let mut u: ArrayVec<[_; 3]> = ArrayVec::new();

    u.push(vec![1,2,4,5]);
    u.push(vec![3]);
    u.push(vec![97,98,92]);

    {
        let slc: &[_] = &u;
        println!("{:?}", slc);
    }
    println!("{:?}", u.pop());
    println!("{:?}", u.pop());
    println!("{:?}", u.len());
    println!("{:?}", u[0]);

    let mut v: ArrayVec<[Dud; 2]> = ArrayVec::new();
    v.push(Dud(1));
    v.push(Dud(2));
    v.pop();
    v.pop();
    v.pop();
    v.push(Dud(3));
    v.pop();
    v.push(Dud(4));
    v.push(Dud(5));
    v.push(Dud(6));
    //v.pop();

    println!("v: {:?}", &*v);

    for elt in &v { // slice iter
        println!("Slice Iter: {:?}", elt);
    }

    for elt in v {
        println!("Iter: {:?}", elt);
        //break;
    }

    for elt in ArrayVec::from(["a".to_string(), "b".to_string()]).into_iter() {
        println!("Iter: {:?}", elt);
    }
}
<|endoftext|>