<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 requires at least `rustc` 1.36.0, uses the 2018 rust edition, and 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;
//!
//! fn run () -> error::Result<()> {
//!     for (i, arg) in env::args().enumerate() {
//!         if i == 1 {
//!             let path = Path::new(arg.as_str());
//!             let buffer = fs::read(path)?;
//!             match Object::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)]

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

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

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

#[allow(unused)]
macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "std")]
        $i
    )*)
}

#[allow(unused)]
macro_rules! if_alloc {
    ($($i:item)*) => ($(
        #[cfg(feature = "alloc")]
        $i
    )*)
}

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

pub mod strtab;

/// Binary container size information and byte-order context
pub mod container {
    pub use scroll::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, 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,
                le: scroll::Endian::default(),
            }
        }
    }

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

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

macro_rules! if_everything {
    ($($i:item)*) => ($(
        #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
        $i
    )*)
}

if_everything! {

    #[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`
    pub fn peek_bytes(bytes: &[u8; 16]) -> error::Result<Hint> {
        use scroll::{Pread, LE, BE};
        use crate::mach::{fat, header};
        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_64 }))
        } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
            Ok(Hint::Archive)
        } else if (&bytes[0..2]).pread_with::<u16>(0, LE)? == pe::header::DOS_MAGIC {
            Ok(Hint::PE)
        } else {
            let (magic, maybe_ctx) = mach::parse_magic_and_ctx(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 => {
                    if let Some(ctx) = maybe_ctx {
                        Ok(Hint::Mach(HintData { is_lsb: ctx.le.is_little(), is_64: Some(ctx.container.is_big()) }))
                    } else {
                        Err(error::Error::Malformed(format!("Correct mach magic {:#x} does not have a matching parsing context!", magic)))
                    }
                },
                // 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(feature = "std")]
    pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> 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)
    }

    /// Takes a reference to the first 16 bytes of the total bytes slice and convert it to an array for `peek_bytes` to use.
    fn take_hint_bytes(bytes: &[u8]) -> Option<&[u8; 16]> {
        use core::convert::TryInto;
        bytes.get(0..16)
            .and_then(|hint_bytes_slice| {
                hint_bytes_slice.try_into().ok()
            })
    }

    #[derive(Debug)]
    #[allow(clippy::large_enum_variant)]
    /// 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),
    }

    impl<'a> Object<'a> {
        /// Tries to parse an `Object` from `bytes`
        pub fn parse(bytes: &[u8]) -> error::Result<Object> {
            if let Some(hint_bytes) = take_hint_bytes(bytes) {
                match peek_bytes(hint_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))
                }
            } else {
                Err(error::Error::Malformed(format!("Object is too small.")))
            }
        }
    }
} // end if_endian_fd

/////////////////////////
// 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 crate::elf::dynamic::dyn32 as dynamic;
    pub use crate::elf::header::header32 as header;
    pub use crate::elf::note::Nhdr32 as Note;
    pub use crate::elf::program_header::program_header32 as program_header;
    pub use crate::elf::reloc::reloc32 as reloc;
    pub use crate::elf::section_header::section_header32 as section_header;
    pub use crate::elf::sym::sym32 as sym;

    pub mod gnu_hash {
        pub use crate::elf::gnu_hash::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 crate::elf::dynamic::dyn64 as dynamic;
    pub use crate::elf::header::header64 as header;
    pub use crate::elf::note::Nhdr64 as Note;
    pub use crate::elf::program_header::program_header64 as program_header;
    pub use crate::elf::reloc::reloc64 as reloc;
    pub use crate::elf::section_header::section_header64 as section_header;
    pub use crate::elf::sym::sym64 as sym;

    pub mod gnu_hash {
        pub use crate::elf::gnu_hash::hash;
        elf_gnu_hash_impl!(u64);
    }
}

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

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

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

#[cfg(test)]
mod tests {
    use super::*;
    if_everything! {
        #[test]
        fn take_hint_bytes_long_enough() {
            let bytes_array = [1; 32];
            let bytes = &bytes_array[..];
            assert!(take_hint_bytes(bytes).is_some())
        }

        #[test]
        fn take_hint_bytes_not_long_enough() {
            let bytes_array = [1; 8];
            let bytes = &bytes_array[..];
            assert!(take_hint_bytes(bytes).is_none())
        }
    }
}
<commit_msg>lib.parse: add return document for take_hint_bytes<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 requires at least `rustc` 1.36.0, uses the 2018 rust edition, and 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;
//!
//! fn run () -> error::Result<()> {
//!     for (i, arg) in env::args().enumerate() {
//!         if i == 1 {
//!             let path = Path::new(arg.as_str());
//!             let buffer = fs::read(path)?;
//!             match Object::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)]

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

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

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

#[allow(unused)]
macro_rules! if_std {
    ($($i:item)*) => ($(
        #[cfg(feature = "std")]
        $i
    )*)
}

#[allow(unused)]
macro_rules! if_alloc {
    ($($i:item)*) => ($(
        #[cfg(feature = "alloc")]
        $i
    )*)
}

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

pub mod strtab;

/// Binary container size information and byte-order context
pub mod container {
    pub use scroll::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, 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,
                le: scroll::Endian::default(),
            }
        }
    }

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

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

macro_rules! if_everything {
    ($($i:item)*) => ($(
        #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
        $i
    )*)
}

if_everything! {

    #[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`
    pub fn peek_bytes(bytes: &[u8; 16]) -> error::Result<Hint> {
        use scroll::{Pread, LE, BE};
        use crate::mach::{fat, header};
        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_64 }))
        } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC {
            Ok(Hint::Archive)
        } else if (&bytes[0..2]).pread_with::<u16>(0, LE)? == pe::header::DOS_MAGIC {
            Ok(Hint::PE)
        } else {
            let (magic, maybe_ctx) = mach::parse_magic_and_ctx(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 => {
                    if let Some(ctx) = maybe_ctx {
                        Ok(Hint::Mach(HintData { is_lsb: ctx.le.is_little(), is_64: Some(ctx.container.is_big()) }))
                    } else {
                        Err(error::Error::Malformed(format!("Correct mach magic {:#x} does not have a matching parsing context!", magic)))
                    }
                },
                // 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(feature = "std")]
    pub fn peek<R: ::std::io::Read + ::std::io::Seek>(fd: &mut R) -> 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)
    }

    /// Takes a reference to the first 16 bytes of the total bytes slice and convert it to an array for `peek_bytes` to use.
    /// Returns None if bytes's length is less than 16.
    fn take_hint_bytes(bytes: &[u8]) -> Option<&[u8; 16]> {
        use core::convert::TryInto;
        bytes.get(0..16)
            .and_then(|hint_bytes_slice| {
                hint_bytes_slice.try_into().ok()
            })
    }

    #[derive(Debug)]
    #[allow(clippy::large_enum_variant)]
    /// 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),
    }

    impl<'a> Object<'a> {
        /// Tries to parse an `Object` from `bytes`
        pub fn parse(bytes: &[u8]) -> error::Result<Object> {
            if let Some(hint_bytes) = take_hint_bytes(bytes) {
                match peek_bytes(hint_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))
                }
            } else {
                Err(error::Error::Malformed(format!("Object is too small.")))
            }
        }
    }
} // end if_endian_fd

/////////////////////////
// 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 crate::elf::dynamic::dyn32 as dynamic;
    pub use crate::elf::header::header32 as header;
    pub use crate::elf::note::Nhdr32 as Note;
    pub use crate::elf::program_header::program_header32 as program_header;
    pub use crate::elf::reloc::reloc32 as reloc;
    pub use crate::elf::section_header::section_header32 as section_header;
    pub use crate::elf::sym::sym32 as sym;

    pub mod gnu_hash {
        pub use crate::elf::gnu_hash::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 crate::elf::dynamic::dyn64 as dynamic;
    pub use crate::elf::header::header64 as header;
    pub use crate::elf::note::Nhdr64 as Note;
    pub use crate::elf::program_header::program_header64 as program_header;
    pub use crate::elf::reloc::reloc64 as reloc;
    pub use crate::elf::section_header::section_header64 as section_header;
    pub use crate::elf::sym::sym64 as sym;

    pub mod gnu_hash {
        pub use crate::elf::gnu_hash::hash;
        elf_gnu_hash_impl!(u64);
    }
}

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

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

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

#[cfg(test)]
mod tests {
    use super::*;
    if_everything! {
        #[test]
        fn take_hint_bytes_long_enough() {
            let bytes_array = [1; 32];
            let bytes = &bytes_array[..];
            assert!(take_hint_bytes(bytes).is_some())
        }

        #[test]
        fn take_hint_bytes_not_long_enough() {
            let bytes_array = [1; 8];
            let bytes = &bytes_array[..];
            assert!(take_hint_bytes(bytes).is_none())
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

#[cfg(target_os="windows")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "curses")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({:?})", obj),
            Object::Window(ref obj) => write!(f, "Window({:?})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({:?})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({:?})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({:?})", obj),
            Object::Float(ref obj) => write!(f, "Float({:?})", obj),
            Object::String(ref obj) => write!(f, "String({:?})", obj),
            Object::Array(ref arr) => {
                write!(f, "Array(").ok();
                let obj = arr.unwrap_value();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as isize)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{:?}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {:?})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as usize);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array(Array::wrap_value((*(obj as *mut ffi::C_Object_Array)).data))),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: &Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as usize);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    let s = ffi::C_String {
        data: message.as_slice().as_ptr() as *const i8,
        size: message.len() as u64
    };
    let mut arr_raw = ffi::C_Array {
        items: ::std::ptr::null_mut(),
        size: 0,
        capacity: 0,
    };
    unsafe { ffi::vim_msgpack_parse(s, &mut arr_raw) };
    Array::wrap_value(arr_raw)
}

pub struct Array {
    value: ffi::C_Array,
    is_owned: bool,
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            },
            is_owned: true,
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as isize)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array,
            is_owned: false,
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        if self.is_owned {
            unsafe { ffi::api_free_array(self.value) };
        }
    }
}

impl fmt::Debug for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{:?}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "test", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{:?}", arr.get(i));
    }
}
<commit_msg>Update link attributes<commit_after>#![crate_name = "neovim"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![allow(raw_pointer_derive)]

extern crate libc;

use std::ffi::CString;
use std::fmt;
use std::string::String;
use std::vec::Vec;

#[cfg(target_os="macos")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "termkey", kind = "static")]
    #[link(name = "unibilium", kind = "static")]
    #[link(name = "iconv")]
    extern{}
}

#[cfg(target_os="linux")]
mod platform {
    #[link(name = "nvim")]
    #[link(name = "uv")]
    #[link(name = "msgpack")]
    #[link(name = "termkey", kind = "static")]
    #[link(name = "unibilium", kind = "static")]
    extern{}
}

mod ffi;

pub enum Object {
    Buffer(ffi::C_Buffer),
    Window(ffi::C_Window),
    Tabpage(ffi::C_Tabpage),
    Boolean(ffi::C_Boolean),
    Integer(ffi::C_Integer),
    Float(ffi::C_Float),
    String(String),
    Array(Array),
    Dictionary(ffi::C_Dictionary),
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Object::Buffer(ref obj) => write!(f, "Buffer({:?})", obj),
            Object::Window(ref obj) => write!(f, "Window({:?})", obj),
            Object::Tabpage(ref obj) => write!(f, "Tabpage({:?})", obj),
            Object::Boolean(ref obj) => write!(f, "Boolean({:?})", obj),
            Object::Integer(ref obj) => write!(f, "Integer({:?})", obj),
            Object::Float(ref obj) => write!(f, "Float({:?})", obj),
            Object::String(ref obj) => write!(f, "String({:?})", obj),
            Object::Array(ref arr) => {
                write!(f, "Array(").ok();
                let obj = arr.unwrap_value();
                for i in range(0, obj.size) {
                    let inner_obj_opt = unsafe { c_object_to_object(obj.items.offset(i as isize)) };
                    if let Some(inner_obj) = inner_obj_opt {
                        write!(f, "{:?}", inner_obj).ok();
                        if i + 1 < obj.size {
                            write!(f, ", ").ok();
                        }
                    } else {
                        write!(f, "Nil ").ok();
                    }
                }
                write!(f, ")")
            },
            Object::Dictionary(ref obj) => write!(f, "Dictionary(Length: {:?})", obj.size),
        }
    }
}

unsafe fn c_object_to_object(obj: *mut ffi::C_Object) -> Option<Object> {
    match (*obj).object_type {
        ffi::ObjectType::BufferType =>
            Some(Object::Buffer((*(obj as *mut ffi::C_Object_Buffer)).data)),
        ffi::ObjectType::WindowType =>
            Some(Object::Window((*(obj as *mut ffi::C_Object_Window)).data)),
        ffi::ObjectType::TabpageType =>
            Some(Object::Tabpage((*(obj as *mut ffi::C_Object_Tabpage)).data)),
        ffi::ObjectType::NilType =>
            None,
        ffi::ObjectType::BooleanType =>
            Some(Object::Boolean((*(obj as *mut ffi::C_Object_Boolean)).data)),
        ffi::ObjectType::IntegerType =>
            Some(Object::Integer((*(obj as *mut ffi::C_Object_Integer)).data)),
        ffi::ObjectType::FloatType =>
            Some(Object::Float((*(obj as *mut ffi::C_Object_Float)).data)),
        ffi::ObjectType::StringType => {
            let vim_str: ffi::C_String = (*(obj as *mut ffi::C_Object_String)).data;
            let v = Vec::from_raw_buf(vim_str.data as *const u8, vim_str.size as usize);
            Some(Object::String(String::from_utf8_unchecked(v)))
        },
        ffi::ObjectType::ArrayType =>
            Some(Object::Array(Array::wrap_value((*(obj as *mut ffi::C_Object_Array)).data))),
        ffi::ObjectType::DictionaryType =>
            Some(Object::Dictionary((*(obj as *mut ffi::C_Object_Dictionary)).data)),
    }
}

pub fn main_setup(args: &Vec<String>) -> i32 {
    let v: Vec<CString> = args.iter().map(|s| CString::from_slice(s.as_bytes())).collect();
    let vp: Vec<*const ffi::c_char> = v.iter().map(|s| s.as_ptr()).collect();
    let p_vp: *const *const ffi::c_char = vp.as_ptr();

    unsafe { ffi::nvim_main_setup(vp.len() as i32, p_vp) }
}

pub fn main_loop() -> i32 {
    unsafe { ffi::nvim_main_loop() }
}

pub fn channel_from_fds(read_fd: i32, write_fd: i32) -> u64 {
    unsafe { ffi::channel_from_fds(read_fd, write_fd) }
}

pub fn serialize_message(id: u64, method: &'static str, args: &Array) -> String {
    unsafe {
        let buf = ffi::vim_msgpack_new();
        let vim_str = ffi::C_String {data: method.as_ptr() as *const i8, size: method.len() as u64};
        ffi::vim_serialize_request(id, vim_str, args.unwrap_value(), buf);
        let v = Vec::from_raw_buf((*buf).data as *const u8, (*buf).size as usize);
        ffi::vim_msgpack_free(buf);
        String::from_utf8_unchecked(v)
    }
}

pub fn deserialize_message(message: &String) -> Array {
    let s = ffi::C_String {
        data: message.as_slice().as_ptr() as *const i8,
        size: message.len() as u64
    };
    let mut arr_raw = ffi::C_Array {
        items: ::std::ptr::null_mut(),
        size: 0,
        capacity: 0,
    };
    unsafe { ffi::vim_msgpack_parse(s, &mut arr_raw) };
    Array::wrap_value(arr_raw)
}

pub struct Array {
    value: ffi::C_Array,
    is_owned: bool,
}

impl Array {
    pub fn new() -> Array {
        Array {
            value: ffi::C_Array {
                items: ::std::ptr::null_mut(),
                size: 0,
                capacity: 0,
            },
            is_owned: true,
        }
    }

    pub fn add_buffer(&mut self, val: ffi::C_Buffer) {
        unsafe { ffi::vim_array_add_buffer(val, &mut self.value) }
    }

    pub fn add_window(&mut self, val: ffi::C_Window) {
        unsafe { ffi::vim_array_add_window(val, &mut self.value) }
    }

    pub fn add_tabpage(&mut self, val: ffi::C_Tabpage) {
        unsafe { ffi::vim_array_add_tabpage(val, &mut self.value) }
    }

    pub fn add_nil(&mut self) {
        unsafe { ffi::vim_array_add_nil(&mut self.value) }
    }

    pub fn add_boolean(&mut self, val: ffi::C_Boolean) {
        unsafe { ffi::vim_array_add_boolean(val, &mut self.value) }
    }

    pub fn add_integer(&mut self, val: ffi::C_Integer) {
        unsafe { ffi::vim_array_add_integer(val, &mut self.value) }
    }

    pub fn add_float(&mut self, val: ffi::C_Float) {
        unsafe { ffi::vim_array_add_float(val, &mut self.value) }
    }

    pub fn add_string(&mut self, val: &str) {
        unsafe {
            // we need to copy the string into memory not managed by Rust,
            // so api_free_array can clear it
            let ptr = ffi::malloc(val.len() as u64);
            ::std::ptr::copy_memory(ptr, val.as_ptr() as *const ffi::c_void, val.len());
            let vim_str = ffi::C_String {data: ptr as *const i8, size: val.len() as u64};
            ffi::vim_array_add_string(vim_str, &mut self.value)
        }
    }

    pub fn add_array(&mut self, val: &Array) {
        unsafe { ffi::vim_array_add_array(val.unwrap_value(), &mut self.value) }
    }

    pub fn add_dictionary(&mut self, val: ffi::C_Dictionary) {
        unsafe { ffi::vim_array_add_dictionary(val, &mut self.value) }
    }

    pub fn get(&self, index: u64) -> Option<Object> {
        if index >= self.len() {
            return None;
        }
        unsafe { c_object_to_object(self.value.items.offset(index as isize)) }
    }

    pub fn len(&self) -> u64 {
        self.value.size
    }

    #[doc(hidden)]
    pub fn unwrap_value(&self) -> ffi::C_Array {
        self.value
    }

    #[doc(hidden)]
    pub fn wrap_value(c_array: ffi::C_Array) -> Array {
        Array {
            value: c_array,
            is_owned: false,
        }
    }
}

impl Drop for Array {
    fn drop(&mut self) {
        if self.is_owned {
            unsafe { ffi::api_free_array(self.value) };
        }
    }
}

impl fmt::Debug for Array {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Array(").ok();
        for i in range(0, self.len()) {
            if let Some(obj) = self.get(i) {
                write!(f, "{:?}", obj).ok();
            } else {
                write!(f, "Nil").ok();
            }
            if i + 1 < self.len() {
                write!(f, ", ").ok();
            }
        }
        write!(f, ")")
    }
}

#[test]
fn test_request() {
    let mut args = Array::new();
    args.add_integer(80);
    args.add_integer(24);
    args.add_string("hello");

    let msg = serialize_message(1, "test", &args);
    let arr = deserialize_message(&msg);
    println!("LENGTH: {}", arr.len());
    for i in range(0, arr.len()) {
        println!("{:?}", arr.get(i));
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the the scalar type of their component (f32, i32, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! All euclid types are marked #[repr(C)] in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also repr(C)).
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedMatrix4D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

extern crate heapsize;

#[macro_use]
extern crate log;
extern crate rustc_serialize;
extern crate serde;

#[cfg(test)]
extern crate rand;
#[cfg(feature = "unstable")]
extern crate test;
extern crate num_traits;

pub use length::Length;
pub use scale_factor::ScaleFactor;
pub use matrix2d::{Matrix2D, TypedMatrix2D};
pub use matrix4d::{Matrix4D, TypedMatrix4D};
pub use point::{
    Point2D, TypedPoint2D,
    Point3D, TypedPoint3D,
    Point4D, TypedPoint4D,
};
pub use rect::{Rect, TypedRect};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
pub use size::{Size2D, TypedSize2D};

pub mod approxeq;
pub mod length;
#[macro_use]
mod macros;
pub mod matrix2d;
pub mod matrix4d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
mod trig;

/// The default unit.
#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
pub struct UnknownUnit;

/// Unit for angles in radians.
pub struct Rad;

/// Unit for angles in degrees.
pub struct Deg;

/// A value in radians.
pub type Radians<T> = Length<T, Rad>;

/// A value in Degrees.
pub type Degrees<T> = Length<T, Deg>;
<commit_msg>Silence a warning<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(feature = "unstable", feature(asm, repr_simd, test))]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the the scalar type of their component (f32, i32, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all Typed* structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```Point2D<T>``` is equivalent to ```TypedPoint2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! All euclid types are marked #[repr(C)] in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also repr(C)).
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = TypedPoint2D<f32, ScreenSpace>;
//! pub type ScreenSize = TypedSize2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = TypedMatrix4D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! Components are accessed in their scalar form by default for convenience, and most
//! types additionally implement strongly typed accessors which return typed ```Length``` wrappers.
//! For example:
//!
//! ```rust
//! # use euclid::*;
//! # pub struct WorldSpace;
//! # pub type WorldPoint = TypedPoint3D<f32, WorldSpace>;
//! let p = WorldPoint::new(0.0, 1.0, 1.0);
//! // p.x is an f32.
//! println!("p.x = {:?} ", p.x);
//! // p.x is a Length<f32, WorldSpace>.
//! println!("p.x_typed() = {:?} ", p.x_typed());
//! // Length::get returns the scalar value (f32).
//! assert_eq!(p.x, p.x_typed().get());
//! ```

extern crate heapsize;

#[cfg_attr(test, macro_use)]
extern crate log;
extern crate rustc_serialize;
extern crate serde;

#[cfg(test)]
extern crate rand;
#[cfg(feature = "unstable")]
extern crate test;
extern crate num_traits;

pub use length::Length;
pub use scale_factor::ScaleFactor;
pub use matrix2d::{Matrix2D, TypedMatrix2D};
pub use matrix4d::{Matrix4D, TypedMatrix4D};
pub use point::{
    Point2D, TypedPoint2D,
    Point3D, TypedPoint3D,
    Point4D, TypedPoint4D,
};
pub use rect::{Rect, TypedRect};
pub use side_offsets::{SideOffsets2D, TypedSideOffsets2D};
#[cfg(feature = "unstable")] pub use side_offsets::SideOffsets2DSimdI32;
pub use size::{Size2D, TypedSize2D};

pub mod approxeq;
pub mod length;
#[macro_use]
mod macros;
pub mod matrix2d;
pub mod matrix4d;
pub mod num;
pub mod point;
pub mod rect;
pub mod scale_factor;
pub mod side_offsets;
pub mod size;
mod trig;

/// The default unit.
#[derive(Clone, Copy, RustcDecodable, RustcEncodable)]
pub struct UnknownUnit;

/// Unit for angles in radians.
pub struct Rad;

/// Unit for angles in degrees.
pub struct Deg;

/// A value in radians.
pub type Radians<T> = Length<T, Rad>;

/// A value in Degrees.
pub type Degrees<T> = Length<T, Deg>;
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![feature(core)]

use std::slice::bytes::copy_memory;
use std::num::Wrapping;
use std::ops::{Deref, DerefMut};

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: usize = 4096;
pub const DISPLAY_WIDTH: usize = 64;
pub const DISPLAY_HEIGHT: usize = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

#[derive(Clone, Copy)]
struct KeypressWait {
    wait: bool,
    vx: usize
}

macro_rules! array_wrap (
    ($name:ident, $typ:ty) => (
        #[derive(Copy)]
        struct $name($typ);
        impl Clone for $name {
            fn clone(&self) -> $name { *self }
        }
        impl Deref for $name {
            type Target = $typ;
            fn deref(&self) -> &$typ { &self.0 }
        }
        impl DerefMut for $name {
            fn deref_mut(&mut self) -> &mut $typ { &mut self.0 }
        }
    )
);

array_wrap!(DisplayArray, [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT]);
array_wrap!(MemArray, [u8; MEM_SIZE]);

/// CHIP-8 virtual machine
#[derive(Clone, Copy)]
pub struct VirtualMachine {
    ram: MemArray,
    v: [Wrapping<u8>; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: DisplayArray,
    display_updated: bool,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl VirtualMachine {

    /// Constructs a new `VirtualMachine`.
    pub fn new() -> VirtualMachine {
        let mut ch8 = VirtualMachine {
            ram: MemArray([0; MEM_SIZE]),
            v: [Wrapping(0); 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: DisplayArray([0; DISPLAY_WIDTH * DISPLAY_HEIGHT]),
            display_updated: false,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(&FONTSET, &mut ch8.ram[0usize..5 * 0x10]);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(rom, &mut self.ram[START_ADDR as usize .. len]);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        self.display_updated = false;
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as usize),
            0x3 => ops::skip_next_vx_eq(self, x as usize, kk),
            0x4 => ops::skip_next_vx_ne(self, x as usize, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as usize, kk),
            0x7 => ops::add_vx_byte(self, x as usize, kk),
            0x8 => {
                let (x, y) = (x as usize, y as usize);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as usize, kk),
            0xD => ops::display_sprite(self, x as usize, y as usize, n as usize),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as usize),
                0x9E => ops::skip_next_key_vx_pressed(self, x as usize),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as usize),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as usize),
                    0x15 => ops::set_delay_timer(self, x as usize),
                    0x18 => ops::set_sound_timer(self, x as usize),
                    0x1E => ops::add_vx_to_i(self, x as usize),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as usize),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as usize),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as usize),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as usize),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as usize];
        let b2 = self.ram[(self.pc + 1) as usize];
        self.pc += 2;
        (b1 as u16) << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx].0 = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }

    pub fn display_updated(&self) -> bool { self.display_updated }
    pub fn display(&self) -> &[u8] { &*self.display }
}
<commit_msg>Update documentation<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![feature(core)]
#![warn(missing_docs)]

use std::slice::bytes::copy_memory;
use std::num::Wrapping;
use std::ops::{Deref, DerefMut};

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: usize = 4096;
/// The width of the Chip8's display in pixels.
pub const DISPLAY_WIDTH: usize = 64;
/// The height of the Chip8's display in pixels.
pub const DISPLAY_HEIGHT: usize = 32;

static FONTSET: [u8; 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

#[derive(Clone, Copy)]
struct KeypressWait {
    wait: bool,
    vx: usize
}

macro_rules! array_wrap (
    ($name:ident, $typ:ty) => (
        #[derive(Copy)]
        struct $name($typ);
        impl Clone for $name {
            fn clone(&self) -> $name { *self }
        }
        impl Deref for $name {
            type Target = $typ;
            fn deref(&self) -> &$typ { &self.0 }
        }
        impl DerefMut for $name {
            fn deref_mut(&mut self) -> &mut $typ { &mut self.0 }
        }
    )
);

array_wrap!(DisplayArray, [u8; DISPLAY_WIDTH * DISPLAY_HEIGHT]);
array_wrap!(MemArray, [u8; MEM_SIZE]);

/// A CHIP-8 virtual machine.
#[derive(Clone, Copy)]
pub struct VirtualMachine {
    ram: MemArray,
    v: [Wrapping<u8>; 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16; 16],
    display: DisplayArray,
    display_updated: bool,
    keys: [bool; 16],
    keypress_wait: KeypressWait
}

impl VirtualMachine {

    /// Constructs a new VirtualMachine.
    pub fn new() -> VirtualMachine {
        let mut ch8 = VirtualMachine {
            ram: MemArray([0; MEM_SIZE]),
            v: [Wrapping(0); 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0; 16],
            display: DisplayArray([0; DISPLAY_WIDTH * DISPLAY_HEIGHT]),
            display_updated: false,
            keys: [false; 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(&FONTSET, &mut ch8.ram[0usize..5 * 0x10]);
        ch8
    }

    /// Loads a ROM into the VirtualMachine.
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(rom, &mut self.ram[START_ADDR as usize .. len]);
    }

    /// Does an emulation cycle.
    pub fn do_cycle(&mut self) {
        self.display_updated = false;
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as usize),
            0x3 => ops::skip_next_vx_eq(self, x as usize, kk),
            0x4 => ops::skip_next_vx_ne(self, x as usize, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as usize, kk),
            0x7 => ops::add_vx_byte(self, x as usize, kk),
            0x8 => {
                let (x, y) = (x as usize, y as usize);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as usize, y as usize),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as usize, kk),
            0xD => ops::display_sprite(self, x as usize, y as usize, n as usize),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as usize),
                0x9E => ops::skip_next_key_vx_pressed(self, x as usize),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as usize),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as usize),
                    0x15 => ops::set_delay_timer(self, x as usize),
                    0x18 => ops::set_sound_timer(self, x as usize),
                    0x1E => ops::add_vx_to_i(self, x as usize),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as usize),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as usize),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as usize),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as usize),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as usize];
        let b2 = self.ram[(self.pc + 1) as usize];
        self.pc += 2;
        (b1 as u16) << 8 | b2 as u16
    }

    /// Presses a key on the hexadecimal keypad.
    ///
    /// `key` should be in the range `0..15`.
    pub fn press_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx].0 = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Releases a key on the hexadecimal keypad.
    ///
    /// `key` should be in the range `0..15`.
    pub fn release_key(&mut self, key: usize) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrements the sound and delay timers.
    ///
    /// They should be decremented at a rate of 60 Hz.
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }

    /// Returns whether the display has been updated.
    pub fn display_updated(&self) -> bool { self.display_updated }
    /// Returns the contents of the display.
    pub fn display(&self) -> &[u8; DISPLAY_WIDTH * DISPLAY_HEIGHT] { &*self.display }
}
<|endoftext|>


<commit_before>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::{Entry, Hasher};
use std::hash::Hash;

struct Dependency<T> {
    num_prec: usize,
    succ: HashSet<T>
}

impl<T: Hash<Hasher> + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash<Hasher> + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    ///# extern crate "topological-sort" as tsort;
    ///# fn main() {
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    ///# }
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> usize { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.insert(dep);
            },
            Entry::Occupied(e) => {
                if !e.into_mut().succ.insert(succ.clone()) {
                    // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                e.into_mut().num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash<Hasher> + Eq + Clone> Iterator for TopologicalSort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<i32>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[i32], ts: &mut TopologicalSort<i32>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<commit_msg>update to rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-20)<commit_after>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![feature(std_misc)]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: usize,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    ///# extern crate "topological-sort" as tsort;
    ///# fn main() {
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    ///# }
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> usize { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.insert(dep);
            },
            Entry::Occupied(e) => {
                if !e.into_mut().succ.insert(succ.clone()) {
                    // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.insert(dep);
            }
            Entry::Occupied(e) => {
                e.into_mut().num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator for TopologicalSort<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<i32>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[i32], ts: &mut TopologicalSort<i32>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<|endoftext|>


<commit_before>#![crate_name = "tar"]
#![crate_type = "lib"]
#![license = "MIT"]

use std::io::fs::File;
use std::collections::hashmap::HashMap;

pub fn new(filepath: &'static str) -> Tar {
    let mut fields = HashMap::<&str, uint>::new();
    fields.insert("path", 1);
    fields.insert("mode", 2);
    fields.insert("uid", 3);
    fields.insert("gid", 4);
    fields.insert("size", 5);
    fields.insert("mtime", 6);
    fields.insert("cksum", 7);
    fields.insert("type", 8);
    fields.insert("linkpath", 9);

    Tar {
        filepath: filepath,
        fields: fields
    }
}

struct TarHeader;

impl TarHeader {
    fn decode() {
        fail!();
    }

    fn encode() {
        fail!();
    }

    fn calcSum() {
        fail!();
    }

    fn checkSum() {
        fail!();
    }
}

pub struct Tar {
    filepath: &'static str,
    fields: HashMap<&'static str, uint>
}

impl Tar {

    pub fn read(&self) -> Vec<Vec<u8>> {
        static BLOCK_SIZE: uint = 512;

        let mut split_data = vec!();
        let mut cur_block = 0;
        let mut handle = File::open(&Path::new(self.filepath));
        let data = handle.read_to_end().unwrap();

        while cur_block < data.len() {
            split_data.push(Vec::from_slice(data.slice(cur_block, cur_block + BLOCK_SIZE)));
            cur_block += BLOCK_SIZE;
        }

        split_data
    }

    pub fn extract(&self) {
        fail!();
    }
}
<commit_msg>restructuring the file a bit, adding field_size hashmap<commit_after>#![crate_name = "tar"]
#![crate_type = "lib"]
#![license = "MIT"]

use std::io::fs::File;
use std::collections::hashmap::HashMap;

pub struct Tar {
    filepath: &'static str,
    fields: HashMap<&'static str, uint>,
    field_size: HashMap<&'static str, uint>
}

pub fn new(filepath: &'static str) -> Tar {
    let mut fields = HashMap::<&str, uint>::new();
    let mut field_size = HashMap::<&str, uint>::new();

    fields.insert("path", 1);
    fields.insert("mode", 2);
    fields.insert("uid", 3);
    fields.insert("gid", 4);
    fields.insert("size", 5);
    fields.insert("mtime", 6);
    fields.insert("cksum", 7);
    fields.insert("type", 8);
    fields.insert("linkpath", 9);

    Tar {
        filepath: filepath,
        fields: fields,
        field_size: field_size
    }
}

impl Tar {

    pub fn read(&self) -> Vec<Vec<u8>> {
        static BLOCK_SIZE: uint = 512;

        let mut split_data = vec!();
        let mut cur_block = 0;
        let mut handle = File::open(&Path::new(self.filepath));
        let data = handle.read_to_end().unwrap();

        while cur_block < data.len() {
            split_data.push(Vec::from_slice(data.slice(cur_block, cur_block + BLOCK_SIZE)));
            cur_block += BLOCK_SIZE;
        }

        split_data
    }

    pub fn extract(&self) {
        fail!();
    }
}

struct TarHeader;

impl TarHeader {
    fn decode() {
        fail!();
    }

    fn encode() {
        fail!();
    }

    fn calcSum() {
        fail!();
    }

    fn checkSum() {
        fail!();
    }
}
<|endoftext|>