<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use futures::stream::Stream;
use lazy_static::lazy_static;
use regex::Regex;

pub struct Entity {
    pub identifier: String,
}

pub enum Object {
    Entity(Entity),
    Literal(Literal),
}

pub enum Literal {
    LangLiteral(LangLiteral),
    StringLiteral(String),
    BooleanLiteral(bool),
    LongLiteral(i64),
    DoubleLiteral(f64),
}

pub struct LangLiteral {
    pub value: String,
    pub lang_tag: String,
}

pub struct Predicate {
    pub predicate: String,
}

pub enum Range {
    LangLiteralRange(LangLiteral, LangLiteral),
    StringLiteralRange(String, String),
    LongLiteralRange(i64, i64),
    DoubleLiteralRange(f64, f64),
}

pub struct Statement {
    pub subject: Entity,
    pub predicate: Predicate,
    pub object: Object,
    pub context: Entity,
}

pub struct CollectionName {
    pub name: String,
}

pub trait LigatureStore {
    fn read_tx(&self) -> &dyn ReadTx;
    fn write_tx(&self) -> &dyn WriteTx;

    /**
     * Close connection with the Store.
     */
    fn close(&self);

    fn is_open(&self) -> bool;
}

pub trait ReadTx {
    /**
     * Returns a Stream of all existing collections.
     */
    fn collections(&self) -> &dyn Stream<Item = CollectionName>;

    /**
     * Returns a Stream of all existing collections that start with the given prefix.
     */
    fn collections_prefix(&self, prefix: CollectionName) -> &dyn Stream<Item = CollectionName>;

    /**
     * Returns a Stream of all existing collections that are within the given range.
     * `from` is inclusive and `to` is exclusive.
     */
    fn collections_range(
        &self,
        from: CollectionName,
        to: CollectionName,
    ) -> &dyn Stream<Item = CollectionName>;

    /**
     * Accepts nothing but returns a Stream of all Statements in the Collection.
     */
    fn all_statements(&self, collection: CollectionName) -> &dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements(
        &self,
        collection: CollectionName,
        subject: Option<Entity>,
        predicate: Option<Predicate>,
        object: Option<Object>,
        context: Option<Entity>,
    ) -> &dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements_range(
        &self,
        collection: CollectionName,
        subject: Option<Entity>,
        predicate: Option<Predicate>,
        range: Option<Range>,
        context: Option<Entity>,
    ) -> &dyn Stream<Item = Statement>;

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);

    fn is_open(&self) -> bool;
}

pub trait WriteTx {
    /**
     * Creates a collection with the given name or does nothing if the collection already exists.
     * Only useful for creating an empty collection.
     */
    fn create_collection(&self, collection: CollectionName);

    /**
     * Deletes the collection of the name given and does nothing if the collection doesn't exist.
     */
    fn delete_collection(&self, collection: CollectionName);

    /**
     * Returns a new, unique to this collection identifier in the form _:NUMBER
     */
    fn new_entity(&self, collection: CollectionName) -> Entity;
    fn remove_entity(&self, collection: CollectionName, entity: Entity);
    fn add_statement(&self, collection: CollectionName, statement: Statement);
    fn remove_statement(&self, collection: CollectionName, statement: Statement);

    /**
     * Commits this transaction.
     */
    fn commit(&self);

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);

    fn is_open(&self) -> bool;
}

/**
 * Accepts a String representing an identifier and returns true or false depending on if it is valid.
 */
pub fn valid_predicate(identifier: &str) -> bool {
    lazy_static! {
        static ref RE: Regex =
            Regex::new("^[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*$").unwrap();
    }
    RE.is_match(identifier)
}

/**
 * Accepts a String representing a lang tag and returns true or false depending on if it is valid.
 */
pub fn valid_lang_tag(lang_tag: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new("^[a-zA-Z]+(-[a-zA-Z0-9]+)*$").unwrap();
    }
    RE.is_match(lang_tag)
}

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

    #[test]
    fn valid_identifier_tests() {
        assert_eq!(valid_predicate(""), false);
        assert_eq!(valid_predicate("http://localhost/people/7"), true);
        assert_eq!(valid_predicate("http://localhost(/people/7"), false);
        assert_eq!(valid_predicate("http://localhost /people/7"), false);
        assert_eq!(valid_predicate("hello"), true);
        assert_eq!(valid_predicate("_:"), true);
        assert_eq!(valid_predicate("_:valid"), true);
        assert_eq!(valid_predicate("_:1"), true);
        assert_eq!(valid_predicate("_:1344"), true);
    }

    #[test]
    fn valid_lang_tag_tests() {
        assert_eq!(valid_lang_tag(""), false);
        assert_eq!(valid_lang_tag("en"), true);
        assert_eq!(valid_lang_tag("en-"), false);
        assert_eq!(valid_lang_tag("en-fr"), true);
        assert_eq!(valid_lang_tag("en-fr-"), false);
        assert_eq!(valid_lang_tag("en-fr-sp"), true);
        assert_eq!(
            valid_lang_tag("ennnenefnk-dkfjkjfl-dfakjelfkjalkf-fakjeflkajlkfj"),
            true
        );
        assert_eq!(valid_lang_tag("en-fr-ef "), false);
    }
}
<commit_msg>making close accept a mut self<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use futures::stream::Stream;
use lazy_static::lazy_static;
use regex::Regex;

pub struct Entity {
    pub identifier: String,
}

pub enum Object {
    Entity(Entity),
    Literal(Literal),
}

pub enum Literal {
    LangLiteral(LangLiteral),
    StringLiteral(String),
    BooleanLiteral(bool),
    LongLiteral(i64),
    DoubleLiteral(f64),
}

pub struct LangLiteral {
    pub value: String,
    pub lang_tag: String,
}

pub struct Predicate {
    pub predicate: String,
}

pub enum Range {
    LangLiteralRange(LangLiteral, LangLiteral),
    StringLiteralRange(String, String),
    LongLiteralRange(i64, i64),
    DoubleLiteralRange(f64, f64),
}

pub struct Statement {
    pub subject: Entity,
    pub predicate: Predicate,
    pub object: Object,
    pub context: Entity,
}

pub struct CollectionName {
    pub name: String,
}

pub trait LigatureStore {
    fn read_tx(&self) -> &dyn ReadTx;
    fn write_tx(&self) -> &dyn WriteTx;

    /**
     * Close connection with the Store.
     */
    fn close(&mut self);

    fn is_open(&self) -> bool;
}

pub trait ReadTx {
    /**
     * Returns a Stream of all existing collections.
     */
    fn collections(&self) -> &dyn Stream<Item = CollectionName>;

    /**
     * Returns a Stream of all existing collections that start with the given prefix.
     */
    fn collections_prefix(&self, prefix: CollectionName) -> &dyn Stream<Item = CollectionName>;

    /**
     * Returns a Stream of all existing collections that are within the given range.
     * `from` is inclusive and `to` is exclusive.
     */
    fn collections_range(
        &self,
        from: CollectionName,
        to: CollectionName,
    ) -> &dyn Stream<Item = CollectionName>;

    /**
     * Accepts nothing but returns a Stream of all Statements in the Collection.
     */
    fn all_statements(&self, collection: CollectionName) -> &dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements(
        &self,
        collection: CollectionName,
        subject: Option<Entity>,
        predicate: Option<Predicate>,
        object: Option<Object>,
        context: Option<Entity>,
    ) -> &dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements_range(
        &self,
        collection: CollectionName,
        subject: Option<Entity>,
        predicate: Option<Predicate>,
        range: Option<Range>,
        context: Option<Entity>,
    ) -> &dyn Stream<Item = Statement>;

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);

    fn is_open(&self) -> bool;
}

pub trait WriteTx {
    /**
     * Creates a collection with the given name or does nothing if the collection already exists.
     * Only useful for creating an empty collection.
     */
    fn create_collection(&self, collection: CollectionName);

    /**
     * Deletes the collection of the name given and does nothing if the collection doesn't exist.
     */
    fn delete_collection(&self, collection: CollectionName);

    /**
     * Returns a new, unique to this collection identifier in the form _:NUMBER
     */
    fn new_entity(&self, collection: CollectionName) -> Entity;
    fn remove_entity(&self, collection: CollectionName, entity: Entity);
    fn add_statement(&self, collection: CollectionName, statement: Statement);
    fn remove_statement(&self, collection: CollectionName, statement: Statement);

    /**
     * Commits this transaction.
     */
    fn commit(&self);

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);

    fn is_open(&self) -> bool;
}

/**
 * Accepts a String representing an identifier and returns true or false depending on if it is valid.
 */
pub fn valid_predicate(identifier: &str) -> bool {
    lazy_static! {
        static ref RE: Regex =
            Regex::new("^[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*$").unwrap();
    }
    RE.is_match(identifier)
}

/**
 * Accepts a String representing a lang tag and returns true or false depending on if it is valid.
 */
pub fn valid_lang_tag(lang_tag: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new("^[a-zA-Z]+(-[a-zA-Z0-9]+)*$").unwrap();
    }
    RE.is_match(lang_tag)
}

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

    #[test]
    fn valid_identifier_tests() {
        assert_eq!(valid_predicate(""), false);
        assert_eq!(valid_predicate("http://localhost/people/7"), true);
        assert_eq!(valid_predicate("http://localhost(/people/7"), false);
        assert_eq!(valid_predicate("http://localhost /people/7"), false);
        assert_eq!(valid_predicate("hello"), true);
        assert_eq!(valid_predicate("_:"), true);
        assert_eq!(valid_predicate("_:valid"), true);
        assert_eq!(valid_predicate("_:1"), true);
        assert_eq!(valid_predicate("_:1344"), true);
    }

    #[test]
    fn valid_lang_tag_tests() {
        assert_eq!(valid_lang_tag(""), false);
        assert_eq!(valid_lang_tag("en"), true);
        assert_eq!(valid_lang_tag("en-"), false);
        assert_eq!(valid_lang_tag("en-fr"), true);
        assert_eq!(valid_lang_tag("en-fr-"), false);
        assert_eq!(valid_lang_tag("en-fr-sp"), true);
        assert_eq!(
            valid_lang_tag("ennnenefnk-dkfjkjfl-dfakjelfkjalkf-fakjeflkajlkfj"),
            true
        );
        assert_eq!(valid_lang_tag("en-fr-ef "), false);
    }
}
<|endoftext|>


<commit_before>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    unsafe {
        let mut sysinfo: libc::SYSTEM_INFO = ::std::mem::uninitialized();
        libc::GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    all(
        any(
            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "bitrig",
            target_os = "openbsd"
        ),
        not(unix)
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::funcs::bsd44::sysctl;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(unix)]
fn get_num_cpus() -> usize {
    unsafe {
        libc::sysconf(84  /*libc::_SC_NPROCESSORS_ONLN*/) as usize
    }
}

#[test]
fn it_works() {
    assert!(get() > 0);
}
<commit_msg>add upper bound test<commit_after>//! Replaces the deprecated functionality of std::os::num_cpus.
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

extern crate libc;

/// Returns the number of CPUs of the current machine.
#[inline]
pub fn get() -> usize {
    get_num_cpus()
}

#[cfg(windows)]
fn get_num_cpus() -> usize {
    unsafe {
        let mut sysinfo: libc::SYSTEM_INFO = ::std::mem::uninitialized();
        libc::GetSystemInfo(&mut sysinfo);
        sysinfo.dwNumberOfProcessors as usize
    }
}

#[cfg(
    all(
        any(
            target_os = "macos",
            target_os = "ios",
            target_os = "freebsd",
            target_os = "dragonfly",
            target_os = "bitrig",
            target_os = "openbsd"
        ),
        not(unix)
    )
)]
fn get_num_cpus() -> usize {
    use libc::{c_int, c_uint};
    use libc::funcs::bsd44::sysctl;

    //XXX: uplift to libc?
    const CTL_HW: c_int = 6;
    const HW_AVAILCPU: c_int = 25;
    const HW_NCPU: c_int = 3;

    let mut cpus: c_uint = 0;
    let mut CPUS_SIZE = ::std::mem::size_of::<c_uint>();
    let mut mib: [c_int; 4] = [CTL_HW, HW_AVAILCPU, 0, 0];

    unsafe {
        sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
    }

    if cpus < 1 {
        mib[1] = HW_NCPU;
        unsafe {
            sysctl(mib.as_mut_ptr(), 2, &mut cpus, &mut CPUS_SIZE, &mut (), 0);
        }
        if cpus < 1 {
            cpus = 1;
        }
    }

    cpus as usize
}

#[cfg(unix)]
fn get_num_cpus() -> usize {
    unsafe {
        libc::sysconf(84  /*libc::_SC_NPROCESSORS_ONLN*/) as usize
    }
}

#[test]
fn lower_bound() {
    assert!(get() > 0);
}

#[test]
fn upper_bound() {
    assert!(get() < 236,451);
}
<|endoftext|>


<commit_before>//! Z80 emulation library
extern crate libc;
mod z80e_core;
use libc::{ c_void };

pub enum Error {
    InvalidMutex,
    WouldBlock,
    Deadlock,
    Other(&'static str)
}
pub type Result<T> = std::result::Result<T, Error>;

/// An interface for a 16-bit addressed container of bytes.
pub trait Z80Memory {
    fn read_byte(&mut self, address: u16) -> u8;
    fn write_byte(&mut self, address: u16, value: u8);
}

impl Z80Memory for Vec<u8> {
    fn read_byte(&mut self, address: u16) -> u8 {
        self[address as usize]
    }
    fn write_byte(&mut self, address: u16, value: u8) {
        self[address as usize] = value;
    }
}

impl Z80Memory for [u8; 0x10000] {
    fn read_byte(&mut self, address: u16) -> u8 {
        self[address as usize]
    }
    fn write_byte(&mut self, address: u16, value: u8) {
        self[address as usize] = value;
    }
}

extern fn read_z80_memory<T: Z80Memory>(memory: *mut c_void, address: u16) -> u8 {
    let memory: &mut T = unsafe { &mut *(memory as *mut T) };
    memory.read_byte(address)
}

extern fn write_z80_memory<T: Z80Memory>(memory: *mut c_void, address: u16, value: u8) {
    let memory: &mut T = unsafe { &mut *(memory as *mut T) };
    memory.write_byte(address, value)
}

/// An interface for implementing one Z80 I/O port.
pub trait Z80IODevice {
    fn read_in(&mut self) -> u8;
    fn write_out(&mut self, value: u8);
}

extern fn read_z80_device<T: Z80IODevice>(device: *mut c_void) -> u8 {
    let device: &mut T = unsafe { &mut *(device as *mut T) };
    device.read_in()
}

extern fn write_z80_device<T: Z80IODevice>(device: *mut c_void, value: u8) {
    let device: &mut T = unsafe { &mut *(device as *mut T) };
    device.write_out(value)
}

pub enum StopReason {
    Done,
    Halted(i32),
    Hung(i32),
    Error(Error),
}

/// Z80 CPU implementation.
pub struct Z80 {
    core: *mut z80e_core::z80e_cpu,
}

impl Z80 {
    /// Allocate a new Z80 core and install its memory.
    pub fn new<T: Z80Memory>(memory: &mut T) -> Self {
        unsafe {
            let cpu = Z80 {
                core: z80e_core::cpu_init(),
            };
            (*cpu.core).memory = (memory as *mut _) as *mut c_void;
            (*cpu.core).read_byte = read_z80_memory::<T>;
            (*cpu.core).write_byte = write_z80_memory::<T>;
            cpu
        }
    }
    /// Install a device on a Z80 I/O port.
    pub fn install_device<T: Z80IODevice>(&mut self, port: u8, device: &mut T) {
        let port: usize = port as usize;
        unsafe {
            (*self.core).devices[port].device = (device as *mut _) as *mut c_void;
            (*self.core).devices[port].read_in = read_z80_device::<T>;
            (*self.core).devices[port].write_out = write_z80_device::<T>;
        }
    }
    pub fn execute(&mut self, cycles: i32) -> StopReason {
        unsafe {
            let cycles = z80e_core::cpu_execute(self.core, cycles);
            if cycles < 0 {
                return match cycles {
                    x if x == -libc::EINVAL => StopReason::Error(Error::InvalidMutex),
                    _ => StopReason::Error(Error::Other("Unknown error")),
                }
            } else {
                if (*self.core).halted {
                    if (*self.core).iff2 {
                        return StopReason::Halted(cycles)
                    } else {
                        return StopReason::Hung(cycles)
                    }
                } else {
                    return StopReason::Done
                }
            }
        }
    }
    pub fn interrupt(&mut self, bus: u8) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_interrupt(self.core, bus)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EDEADLK => Err(Error::Deadlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn clear_interrupt(&mut self) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_clear_interrupt(self.core)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EDEADLK => Err(Error::Deadlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn try_interrupt(&mut self, bus: u8) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_try_interrupt(self.core, bus)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EBUSY => Err(Error::WouldBlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn try_clear_interrupt(&mut self) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_try_clear_interrupt(self.core)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EBUSY => Err(Error::WouldBlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
}

impl Drop for Z80 {
    fn drop(&mut self) {
        unsafe {
            z80e_core::cpu_free(self.core);
        }
    }
}

#[test]
fn it_works() {
}
<commit_msg>Stop using early returns in inappropriate places<commit_after>//! Z80 emulation library
extern crate libc;
mod z80e_core;
use libc::{ c_void };

pub enum Error {
    InvalidMutex,
    WouldBlock,
    Deadlock,
    Other(&'static str)
}
pub type Result<T> = std::result::Result<T, Error>;

/// An interface for a 16-bit addressed container of bytes.
pub trait Z80Memory {
    fn read_byte(&mut self, address: u16) -> u8;
    fn write_byte(&mut self, address: u16, value: u8);
}

impl Z80Memory for Vec<u8> {
    fn read_byte(&mut self, address: u16) -> u8 {
        self[address as usize]
    }
    fn write_byte(&mut self, address: u16, value: u8) {
        self[address as usize] = value;
    }
}

impl Z80Memory for [u8; 0x10000] {
    fn read_byte(&mut self, address: u16) -> u8 {
        self[address as usize]
    }
    fn write_byte(&mut self, address: u16, value: u8) {
        self[address as usize] = value;
    }
}

extern fn read_z80_memory<T: Z80Memory>(memory: *mut c_void, address: u16) -> u8 {
    let memory: &mut T = unsafe { &mut *(memory as *mut T) };
    memory.read_byte(address)
}

extern fn write_z80_memory<T: Z80Memory>(memory: *mut c_void, address: u16, value: u8) {
    let memory: &mut T = unsafe { &mut *(memory as *mut T) };
    memory.write_byte(address, value)
}

/// An interface for implementing one Z80 I/O port.
pub trait Z80IODevice {
    fn read_in(&mut self) -> u8;
    fn write_out(&mut self, value: u8);
}

extern fn read_z80_device<T: Z80IODevice>(device: *mut c_void) -> u8 {
    let device: &mut T = unsafe { &mut *(device as *mut T) };
    device.read_in()
}

extern fn write_z80_device<T: Z80IODevice>(device: *mut c_void, value: u8) {
    let device: &mut T = unsafe { &mut *(device as *mut T) };
    device.write_out(value)
}

pub enum StopReason {
    Done,
    Halted(i32),
    Hung(i32),
    Error(Error),
}

/// Z80 CPU implementation.
pub struct Z80 {
    core: *mut z80e_core::z80e_cpu,
}

impl Z80 {
    /// Allocate a new Z80 core and install its memory.
    pub fn new<T: Z80Memory>(memory: &mut T) -> Self {
        unsafe {
            let cpu = Z80 {
                core: z80e_core::cpu_init(),
            };
            (*cpu.core).memory = (memory as *mut _) as *mut c_void;
            (*cpu.core).read_byte = read_z80_memory::<T>;
            (*cpu.core).write_byte = write_z80_memory::<T>;
            cpu
        }
    }
    /// Install a device on a Z80 I/O port.
    pub fn install_device<T: Z80IODevice>(&mut self, port: u8, device: &mut T) {
        let port: usize = port as usize;
        unsafe {
            (*self.core).devices[port].device = (device as *mut _) as *mut c_void;
            (*self.core).devices[port].read_in = read_z80_device::<T>;
            (*self.core).devices[port].write_out = write_z80_device::<T>;
        }
    }
    pub fn execute(&mut self, cycles: i32) -> StopReason {
        unsafe {
            let cycles = z80e_core::cpu_execute(self.core, cycles);
            return if cycles < 0 {
                match cycles {
                    x if x == -libc::EINVAL => StopReason::Error(Error::InvalidMutex),
                    _ => StopReason::Error(Error::Other("Unknown error")),
                }
            } else {
                if (*self.core).halted {
                    if (*self.core).iff2 {
                        StopReason::Halted(cycles)
                    } else {
                        StopReason::Hung(cycles)
                    }
                } else {
                    StopReason::Done
                }
            }
        }
    }
    pub fn interrupt(&mut self, bus: u8) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_interrupt(self.core, bus)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EDEADLK => Err(Error::Deadlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn clear_interrupt(&mut self) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_clear_interrupt(self.core)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EDEADLK => Err(Error::Deadlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn try_interrupt(&mut self, bus: u8) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_try_interrupt(self.core, bus)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EBUSY => Err(Error::WouldBlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
    pub fn try_clear_interrupt(&mut self) -> Result<()> {
        let status = unsafe {
            z80e_core::cpu_try_clear_interrupt(self.core)
        };
        match status {
            0 => Ok(()),
            libc::EINVAL => Err(Error::InvalidMutex),
            libc::EBUSY => Err(Error::WouldBlock),
            _ => Err(Error::Other("Unknown error")),
        }
    }
}

impl Drop for Z80 {
    fn drop(&mut self) {
        unsafe {
            z80e_core::cpu_free(self.core);
        }
    }
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

//! `sysinfo` is a crate used to get a system's information.
//!
//! Before any attempt to read the different structs' information, you need to update them to
//! get up-to-date information.
//!
//! # Examples
//!
//! ```
//! use sysinfo::{ProcessExt, SystemExt};
//!
//! let mut system = sysinfo::System::new_all();
//!
//! // First we update all information of our system struct.
//! system.refresh_all();
//!
//! // Now let's print every process' id and name:
//! for (pid, proc_) in system.get_processes() {
//!     println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status());
//! }
//!
//! // Then let's print the temperature of the different components:
//! for component in system.get_components() {
//!     println!("{:?}", component);
//! }
//!
//! // And then all disks' information:
//! for disk in system.get_disks() {
//!     println!("{:?}", disk);
//! }
//!
//! // And finally the RAM and SWAP information:
//! println!("total memory: {} KB", system.get_total_memory());
//! println!("used memory : {} KB", system.get_used_memory());
//! println!("total swap  : {} KB", system.get_total_swap());
//! println!("used swap   : {} KB", system.get_used_swap());
//!
//! // Display system information:
//! println!("System name:             {:?}", system.get_name());
//! println!("System kernel version:   {:?}", system.get_kernel_version());
//! println!("System OS version:       {:?}", system.get_os_version());
//! println!("System host name:        {:?}", system.get_host_name());
//! ```

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]
//#![deny(warnings)]
#![allow(unknown_lints)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]

#[cfg(doctest)]
doc_comment::doctest!("../README.md");

#[cfg(feature = "debug")]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(target_os = "ios"))]
#[cfg(not(feature = "debug"))]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
    {
        false
    }
}

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

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        s.refresh_all();
        assert_eq!(
            s.get_processes()
                .iter()
                .all(|(_, proc_)| proc_.memory() == 0),
            false
        );
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        assert!(s.get_users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_all();
        assert!(s.get_users().is_empty());

        let s = System::new_all();
        assert!(s.get_users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        let users = s.get_users();
        assert!(users.len() >= MIN_USERS);

        for user in users {
            match user.get_name() {
                "root" => {
                    assert_eq!(*user.get_uid(), 0);
                    assert_eq!(*user.get_gid(), 0);
                }
                _ => {
                    assert!(*user.get_uid() > 0);
                    #[cfg(not(target_os = "windows"))]
                    assert!(*user.get_gid() > 0);
                }
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unknown systems.
        if MIN_USERS > 0 {
            let s = System::new();
            assert!(!s.get_name().expect("Failed to get system name").is_empty());

            assert!(!s
                .get_kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s
                .get_os_version()
                .expect("Failed to get os version")
                .is_empty());

            assert!(!s
                .get_long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unknown systems.
        if MIN_USERS > 0 {
            let s = System::new();
            assert!(!s
                .get_host_name()
                .expect("Failed to get host name")
                .is_empty());
        }
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
doc_comment::doc_comment!(
    "
```
fn is_send<T: Send>() {}
is_send::<sysinfo::System>();
```

```
fn is_sync<T: Sync>() {}
is_sync::<sysinfo::System>();
```"
);
<commit_msg>Build sysinfo_debug macro on ios too<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

//! `sysinfo` is a crate used to get a system's information.
//!
//! Before any attempt to read the different structs' information, you need to update them to
//! get up-to-date information.
//!
//! # Examples
//!
//! ```
//! use sysinfo::{ProcessExt, SystemExt};
//!
//! let mut system = sysinfo::System::new_all();
//!
//! // First we update all information of our system struct.
//! system.refresh_all();
//!
//! // Now let's print every process' id and name:
//! for (pid, proc_) in system.get_processes() {
//!     println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status());
//! }
//!
//! // Then let's print the temperature of the different components:
//! for component in system.get_components() {
//!     println!("{:?}", component);
//! }
//!
//! // And then all disks' information:
//! for disk in system.get_disks() {
//!     println!("{:?}", disk);
//! }
//!
//! // And finally the RAM and SWAP information:
//! println!("total memory: {} KB", system.get_total_memory());
//! println!("used memory : {} KB", system.get_used_memory());
//! println!("total swap  : {} KB", system.get_total_swap());
//! println!("used swap   : {} KB", system.get_used_swap());
//!
//! // Display system information:
//! println!("System name:             {:?}", system.get_name());
//! println!("System kernel version:   {:?}", system.get_kernel_version());
//! println!("System OS version:       {:?}", system.get_os_version());
//! println!("System host name:        {:?}", system.get_host_name());
//! ```

#![crate_name = "sysinfo"]
#![crate_type = "lib"]
#![crate_type = "rlib"]
#![deny(missing_docs)]
#![deny(broken_intra_doc_links)]
//#![deny(warnings)]
#![allow(unknown_lints)]
#![allow(clippy::upper_case_acronyms)]
#![allow(renamed_and_removed_lints)]

#[cfg(doctest)]
doc_comment::doctest!("../README.md");

#[cfg(feature = "debug")]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{
        eprintln!($($x)*);
    }}
}

#[cfg(not(feature = "debug"))]
#[doc(hidden)]
macro_rules! sysinfo_debug {
    ($($x:tt)*) => {{}};
}

cfg_if::cfg_if! {
    if #[cfg(any(target_os = "macos", target_os = "ios"))] {
        mod apple;
        use apple as sys;
        extern crate core_foundation_sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(windows)] {
        mod windows;
        use windows as sys;
        extern crate winapi;
        extern crate ntapi;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
        mod linux;
        use linux as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 1;
    } else {
        mod unknown;
        use unknown as sys;

        #[cfg(test)]
        const MIN_USERS: usize = 0;
    }
}

pub use common::{
    AsU32, DiskType, DiskUsage, Gid, LoadAvg, NetworksIter, Pid, RefreshKind, Signal, Uid, User,
};
pub use sys::{Component, Disk, NetworkData, Networks, Process, ProcessStatus, Processor, System};
pub use traits::{
    ComponentExt, DiskExt, NetworkExt, NetworksExt, ProcessExt, ProcessorExt, SystemExt, UserExt,
};

#[cfg(feature = "c-interface")]
pub use c_interface::*;
pub use utils::get_current_pid;

#[cfg(feature = "c-interface")]
mod c_interface;
mod common;
mod debug;
mod system;
mod traits;
mod utils;

/// This function is only used on linux targets, on the other platforms it does nothing and returns
/// `false`.
///
/// On linux, to improve performance, we keep a `/proc` file open for each process we index with
/// a maximum number of files open equivalent to half of the system limit.
///
/// The problem is that some users might need all the available file descriptors so we need to
/// allow them to change this limit.
///
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
///
/// Returns `true` if the new value has been set.
///
/// ```no_run
/// use sysinfo::{System, SystemExt, set_open_files_limit};
///
/// // We call the function before any call to the processes update.
/// if !set_open_files_limit(10) {
///     // It'll always return false on non-linux targets.
///     eprintln!("failed to update the open files limit...");
/// }
/// let s = System::new_all();
/// ```
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
        if _new_limit < 0 {
            _new_limit = 0;
        }
        let max = sys::system::get_max_nb_fds();
        if _new_limit > max {
            _new_limit = max;
        }
        if let Ok(ref mut x) = unsafe { sys::system::REMAINING_FILES.lock() } {
            // If files are already open, to be sure that the number won't be bigger when those
            // files are closed, we subtract the current number of opened files to the new limit.
            let diff = max - **x;
            **x = _new_limit - diff;
            true
        } else {
            false
        }
    }
    #[cfg(all(not(target_os = "linux"), not(target_os = "android")))]
    {
        false
    }
}

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

    #[test]
    fn check_memory_usage() {
        let mut s = System::new();

        s.refresh_all();
        assert_eq!(
            s.get_processes()
                .iter()
                .all(|(_, proc_)| proc_.memory() == 0),
            false
        );
    }

    #[test]
    fn check_users() {
        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        assert!(s.get_users().len() >= MIN_USERS);

        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_all();
        assert!(s.get_users().is_empty());

        let s = System::new_all();
        assert!(s.get_users().len() >= MIN_USERS);
    }

    #[test]
    fn check_uid_gid() {
        let mut s = System::new();
        assert!(s.get_users().is_empty());
        s.refresh_users_list();
        let users = s.get_users();
        assert!(users.len() >= MIN_USERS);

        for user in users {
            match user.get_name() {
                "root" => {
                    assert_eq!(*user.get_uid(), 0);
                    assert_eq!(*user.get_gid(), 0);
                }
                _ => {
                    assert!(*user.get_uid() > 0);
                    #[cfg(not(target_os = "windows"))]
                    assert!(*user.get_gid() > 0);
                }
            }
        }
    }

    #[test]
    fn check_system_info() {
        // We don't want to test on unknown systems.
        if MIN_USERS > 0 {
            let s = System::new();
            assert!(!s.get_name().expect("Failed to get system name").is_empty());

            assert!(!s
                .get_kernel_version()
                .expect("Failed to get kernel version")
                .is_empty());

            assert!(!s
                .get_os_version()
                .expect("Failed to get os version")
                .is_empty());

            assert!(!s
                .get_long_os_version()
                .expect("Failed to get long OS version")
                .is_empty());
        }
    }

    #[test]
    fn check_host_name() {
        // We don't want to test on unknown systems.
        if MIN_USERS > 0 {
            let s = System::new();
            assert!(!s
                .get_host_name()
                .expect("Failed to get host name")
                .is_empty());
        }
    }
}

// Used to check that System is Send and Sync.
#[cfg(doctest)]
doc_comment::doc_comment!(
    "
```
fn is_send<T: Send>() {}
is_send::<sysinfo::System>();
```

```
fn is_sync<T: Sync>() {}
is_sync::<sysinfo::System>();
```"
);
<|endoftext|>


<commit_before>extern crate gdk_pixbuf_sys;
extern crate glib_sys as glib;
extern crate gobject_2_0_sys as gobject;
extern crate gtypes;

use gdk_pixbuf_sys::GdkPixbuf;
use glib::{GList, GError, GVariant};
use gobject::GObject;
use gtypes::gboolean;
use std::os::raw::c_char;
use std::os::raw::c_int;

enum NotifyNotificationPrivate {}

#[repr(C)]
pub struct NotifyNotification {
    _parent_object: GObject,
    _priv_: NotifyNotificationPrivate,
}

#[repr(C)]
pub enum NotifyUrgency {
    NotifyUrgencyLow,
    NotifyUrgencyNormal,
    NotifyUrgencyCritical,
}

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;

    pub fn notify_get_server_info(ret_name: *mut *mut c_char,
                                  ret_vendor: *mut *mut c_char,
                                  ret_version: *mut *mut c_char,
                                  ret_spec_version: *mut *mut c_char);

    pub fn notify_notification_new(summary: *const c_char,
                                   body: *const c_char,
                                   icon: *const c_char)
                                   -> *mut NotifyNotification;

    pub fn notify_notification_show(notification: *mut NotifyNotification,
                                    error: *mut *mut GError);

    pub fn notify_notification_set_hint(notification: *mut NotifyNotification,
                                        key: *const c_char,
                                        value: *mut GVariant);

    pub fn notify_notification_update(notification: *mut NotifyNotification,
                                      summary: *const c_char,
                                      body: *const c_char,
                                      icon: *const c_char)
                                      -> gboolean;

    pub fn notify_notification_set_timeout(notification: *mut NotifyNotification, timeout: c_int);

    pub fn notify_notification_set_category(notification: *mut NotifyNotification,
                                             category: *const c_char);

    pub fn notify_notification_set_urgency(notification: *mut NotifyNotification,
                                            urgency: NotifyUrgency);

    pub fn notify_notification_set_image_from_pixbuf(notification: *mut NotifyNotification,
                                                      pixbuf: *mut GdkPixbuf);

    pub fn notify_notification_clear_hints(notification: *mut NotifyNotification);
}
<commit_msg>Add notify_notification_close()<commit_after>extern crate gdk_pixbuf_sys;
extern crate glib_sys as glib;
extern crate gobject_2_0_sys as gobject;
extern crate gtypes;

use gdk_pixbuf_sys::GdkPixbuf;
use glib::{GList, GError, GVariant};
use gobject::GObject;
use gtypes::gboolean;
use std::os::raw::c_char;
use std::os::raw::c_int;

enum NotifyNotificationPrivate {}

#[repr(C)]
pub struct NotifyNotification {
    _parent_object: GObject,
    _priv_: NotifyNotificationPrivate,
}

#[repr(C)]
pub enum NotifyUrgency {
    NotifyUrgencyLow,
    NotifyUrgencyNormal,
    NotifyUrgencyCritical,
}

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;

    pub fn notify_get_server_info(ret_name: *mut *mut c_char,
                                  ret_vendor: *mut *mut c_char,
                                  ret_version: *mut *mut c_char,
                                  ret_spec_version: *mut *mut c_char);

    pub fn notify_notification_new(summary: *const c_char,
                                   body: *const c_char,
                                   icon: *const c_char)
                                   -> *mut NotifyNotification;

    pub fn notify_notification_show(notification: *mut NotifyNotification,
                                    error: *mut *mut GError);

    pub fn notify_notification_set_hint(notification: *mut NotifyNotification,
                                        key: *const c_char,
                                        value: *mut GVariant);

    pub fn notify_notification_update(notification: *mut NotifyNotification,
                                      summary: *const c_char,
                                      body: *const c_char,
                                      icon: *const c_char)
                                      -> gboolean;

    pub fn notify_notification_set_timeout(notification: *mut NotifyNotification, timeout: c_int);

    pub fn notify_notification_set_category(notification: *mut NotifyNotification,
                                             category: *const c_char);

    pub fn notify_notification_set_urgency(notification: *mut NotifyNotification,
                                            urgency: NotifyUrgency);

    pub fn notify_notification_set_image_from_pixbuf(notification: *mut NotifyNotification,
                                                      pixbuf: *mut GdkPixbuf);

    pub fn notify_notification_clear_hints(notification: *mut NotifyNotification);

    pub fn notify_notification_close(notification: *mut NotifyNotification,
                                      error: *mut *mut GError);
}
<|endoftext|>


<commit_before>//! A wrapper around the uchardet library. Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! ```
//! use uchardet::detect_encoding_name;
//!
//! assert_eq!("WINDOWS-1252",
//!            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
//!                0x69, 0x73, 0xe9, 0x94]).unwrap());
//! ```
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

// Increase the compiler's recursion limit for the `error_chain` crate.
#![recursion_limit = "1024"]
#![deny(missing_docs)]

#[macro_use]
extern crate error_chain;
extern crate libc;
extern crate uchardet_sys as ffi;

use libc::size_t;
use std::ffi::CStr;
use std::str::from_utf8;

pub use errors::*;

#[allow(missing_docs)]
mod errors {
    error_chain! {
        errors {
            UnrecognizableCharset {
                description("unrecognizable charset")
                display("uchardet was unable to recognize a charset")
            }
            OutOfMemory {
                description("out of memory error")
                display("uchardet ran out of memory")
            }
            Other(int: i32) {
                description("unknown error")
                display("uchardet returned unknown error {}", int)
            }
        }
    }

    impl ErrorKind {
        pub fn from_nsresult(nsresult: ::ffi::nsresult) -> ErrorKind {
            assert!(nsresult != 0);
            match nsresult {
                1 => ErrorKind::OutOfMemory,
                int => ErrorKind::Other(int),
            }
        }

    }
}

/// Detects the encoding of text using the uchardet library.
///
/// EXPERIMENTAL: This may be replaced by a better API soon.
struct EncodingDetector {
    ptr: ffi::uchardet_t
}

/// Return the name of the charset used in `data` or an error if uchardet
/// was unable to detect a charset.
///
/// ```
/// use uchardet::detect_encoding_name;
///
/// assert_eq!("ASCII",
///            detect_encoding_name("ascii".as_bytes()).unwrap());
/// assert_eq!("UTF-8",
///            detect_encoding_name("©français".as_bytes()).unwrap());
/// assert_eq!("WINDOWS-1252",
///            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
///                0x69, 0x73, 0xe9, 0x94]).unwrap());
/// ```
pub fn detect_encoding_name(data: &[u8]) -> Result<String> {
    let mut detector = EncodingDetector::new();
    try!(detector.handle_data(data));
    detector.data_end();
    detector.charset()
}

impl EncodingDetector {
    /// Create a new EncodingDetector.
    fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(!ptr.is_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector. This is a no-op if a
    /// charset has been detected.
    fn handle_data(&mut self, data: &[u8]) -> Result<()> {
        let nsresult = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match nsresult {
            0 => Ok(()),
            int => {
                Err(ErrorKind::from_nsresult(int).into())
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding. This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain. From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding. May return
    /// an error if uchardet was unable to detect an encoding.
    fn charset(&self) -> Result<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(!internal_str.is_null());
            let bytes = CStr::from_ptr(internal_str).to_bytes();
            let charset = from_utf8(bytes);
            match charset {
                Err(_) =>
                    panic!("uchardet_get_charset returned a charset name \
                            containing invalid characters"),
                Ok("") => Err(ErrorKind::UnrecognizableCharset.into()),
                Ok(encoding) => Ok(encoding.to_string())
            }
        }
    }
}

impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<commit_msg>Make `from_nsresult` private<commit_after>//! A wrapper around the uchardet library. Detects character encodings.
//!
//! Note that the underlying implemention is written in C and C++, and I'm
//! not aware of any security audits which have been performed against it.
//!
//! ```
//! use uchardet::detect_encoding_name;
//!
//! assert_eq!("WINDOWS-1252",
//!            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
//!                0x69, 0x73, 0xe9, 0x94]).unwrap());
//! ```
//!
//! For more information, see [this project on
//! GitHub](https://github.com/emk/rust-uchardet).

// Increase the compiler's recursion limit for the `error_chain` crate.
#![recursion_limit = "1024"]
#![deny(missing_docs)]

#[macro_use]
extern crate error_chain;
extern crate libc;
extern crate uchardet_sys as ffi;

use libc::size_t;
use std::ffi::CStr;
use std::str::from_utf8;

pub use errors::*;

/// We declare our `error_chain!` in a private submodule so that we can
/// `allow(missing_docs)`.
#[allow(missing_docs)]
mod errors {
    error_chain! {
        errors {
            UnrecognizableCharset {
                description("unrecognizable charset")
                display("uchardet was unable to recognize a charset")
            }
            OutOfMemory {
                description("out of memory error")
                display("uchardet ran out of memory")
            }
            Other(int: i32) {
                description("unknown error")
                display("uchardet returned unknown error {}", int)
            }
        }
    }
}

impl ErrorKind {
    /// Convert an `nsresult` into a Rust error.  We panic if the error
    /// value is zero.
    fn from_nsresult(nsresult: ::ffi::nsresult) -> ErrorKind {
        assert!(nsresult != 0);
        match nsresult {
            1 => ErrorKind::OutOfMemory,
            int => ErrorKind::Other(int),
        }
    }
}

/// Detects the encoding of text using the uchardet library.
///
/// EXPERIMENTAL: This may be replaced by a better API soon.
struct EncodingDetector {
    ptr: ffi::uchardet_t
}

/// Return the name of the charset used in `data` or an error if uchardet
/// was unable to detect a charset.
///
/// ```
/// use uchardet::detect_encoding_name;
///
/// assert_eq!("ASCII",
///            detect_encoding_name("ascii".as_bytes()).unwrap());
/// assert_eq!("UTF-8",
///            detect_encoding_name("©français".as_bytes()).unwrap());
/// assert_eq!("WINDOWS-1252",
///            detect_encoding_name(&[0x46, 0x93, 0x72, 0x61, 0x6e, 0xe7, 0x6f,
///                0x69, 0x73, 0xe9, 0x94]).unwrap());
/// ```
pub fn detect_encoding_name(data: &[u8]) -> Result<String> {
    let mut detector = EncodingDetector::new();
    try!(detector.handle_data(data));
    detector.data_end();
    detector.charset()
}

impl EncodingDetector {
    /// Create a new EncodingDetector.
    fn new() -> EncodingDetector {
        let ptr = unsafe { ffi::uchardet_new() };
        assert!(!ptr.is_null());
        EncodingDetector{ptr: ptr}
    }

    /// Pass a chunk of raw bytes to the detector. This is a no-op if a
    /// charset has been detected.
    fn handle_data(&mut self, data: &[u8]) -> Result<()> {
        let nsresult = unsafe {
            ffi::uchardet_handle_data(self.ptr, data.as_ptr() as *const i8,
                                      data.len() as size_t)
        };
        match nsresult {
            0 => Ok(()),
            int => {
                Err(ErrorKind::from_nsresult(int).into())
            }
        }
    }

    /// Notify the detector that we're done calling `handle_data`, and that
    /// we want it to make a guess as to our encoding. This is a no-op if
    /// no data has been passed yet, or if an encoding has been detected
    /// for certain. From reading the code, it appears that you can safely
    /// call `handle_data` after calling this, but I'm not certain.
    fn data_end(&mut self) {
        unsafe { ffi::uchardet_data_end(self.ptr); }
    }

    /// Get the decoder's current best guess as to the encoding. May return
    /// an error if uchardet was unable to detect an encoding.
    fn charset(&self) -> Result<String> {
        unsafe {
            let internal_str = ffi::uchardet_get_charset(self.ptr);
            assert!(!internal_str.is_null());
            let bytes = CStr::from_ptr(internal_str).to_bytes();
            let charset = from_utf8(bytes);
            match charset {
                Err(_) =>
                    panic!("uchardet_get_charset returned a charset name \
                            containing invalid characters"),
                Ok("") => Err(ErrorKind::UnrecognizableCharset.into()),
                Ok(encoding) => Ok(encoding.to_string())
            }
        }
    }
}

impl Drop for EncodingDetector {
    fn drop(&mut self) {
        unsafe { ffi::uchardet_delete(self.ptr) };
    }
}
<|endoftext|>


<commit_before>//! This library parses a Puppetfile

#![crate_name = "puppetfile"]
#![deny(missing_doc)]
#![feature(globs)]

extern crate http;
extern crate serialize;
extern crate semver;
extern crate url;

use std::fmt;
use serialize::json;
use semver::VersionReq;
use http::client::RequestWriter;
use http::method::Get;
use url::Url;

mod puppetfile_parser;

#[cfg(test)]
mod test;

/// This represents a Puppetfile
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Puppetfile {
    /// The forge URL
    pub forge: String,
    /// All Modules contained in the Puppetfile
    pub modules: Vec<Module>
}

#[experimental]
impl Puppetfile {
    /// Try parsing the contents of a Puppetfile into a Puppetfile struct
    pub fn parse(contents: &str) -> Result<Puppetfile, String> {
        puppetfile_parser::parse(contents)
    }
}
impl fmt::Show for Puppetfile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "forge '{}'\n\n", self.forge);
        self.modules.iter().fold(res, |prev_res, module| { prev_res.and(write!(f, "\n{}\n", module)) })
    }
}

/// The representation of a puppet module
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Module {
    /// Name of the module
    pub name: String,
    /// More information about the module
    pub info: Vec<PuppetModuleInfo>
}

#[deriving(Decodable)]
struct ForgeVersionResponse {
    version: String
}

#[experimental]
impl Module {
    /// The current version of the module returned from the forge API
    pub fn forge_version(&self, forge_url: &String) -> Result<semver::Version, semver::ParseError> {
        let request: RequestWriter = RequestWriter::new(Get, self.version_url(forge_url)).unwrap();
        let mut response = match request.read_response() {
            Ok(response) => response,
            Err((_request, error)) => fail!(":-( {}", error),
        };
        let response_string = response.read_to_string().unwrap();
        let version_struct: ForgeVersionResponse = json::decode(response_string.as_slice()).unwrap();
        semver::Version::parse(version_struct.version.as_slice())
    }

    /// Builds the URL for the forge API for fetching the version
    pub fn version_url(&self, forge_url: &String) -> Url {
        let stripped_url = match forge_url.as_slice().ends_with("/") {
            true => forge_url.as_slice().slice_to(forge_url.len() - 1),
            _    => forge_url.as_slice()
        };
        let (user, mod_name) = self.user_name_pair().unwrap();
        Url::parse(format!("{}/users/{}/modules/{}/releases/find.json", stripped_url, user, mod_name).as_slice()).unwrap()
    }

    /// Returns user and module name from 'user/mod_name'
    pub fn user_name_pair(&self) -> Option<(&str, &str)> {
        if self.name.as_slice().contains("/") {
            let mut parts = self.name.as_slice().split('/');
            Some((parts.next().unwrap(), parts.next().unwrap()))
        } else {
            None
        }
    }

    /// Returns the version if specified
    pub fn version(&self) -> Option<VersionReq> {
        for info in self.info.iter() {
            match *info {
                Version(ref v) => return Some(v.clone()),
                ModuleInfo(..) => ()
            }
        }
        None
    }
}
impl fmt::Show for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "mod '{}'", self.name);
        self.info.iter().fold(res, |prev_res, mod_info| {
            match *mod_info {
                Version(..) => prev_res.and(write!(f, ", '{}'", mod_info)),
                ModuleInfo(..) => prev_res.and(write!(f, ",\n  {}", mod_info)),
            }
        })
    }
}

/// Further Information on Puppet Modules
#[deriving(PartialEq, Clone)]
pub enum PuppetModuleInfo {
    /// Version as String
    Version(VersionReq),
    /// Key Value based Information
    ModuleInfo(String, String)
}
impl PuppetModuleInfo {
    /// Returns `true` if the option is a `Version` value
    pub fn is_version(&self) -> bool {
        match *self {
            Version(..)    => true,
            ModuleInfo(..) => false
        }
    }
}

impl fmt::Show for PuppetModuleInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version(ref v) => write!(f, "{}", v),
            ModuleInfo(ref k, ref v) => write!(f, ":{} => '{}'", k, v)
        }
    }
}

<commit_msg>module.version() returns Option<&VersionReq><commit_after>//! This library parses a Puppetfile

#![crate_name = "puppetfile"]
#![deny(missing_doc)]
#![feature(globs)]

extern crate http;
extern crate serialize;
extern crate semver;
extern crate url;

use std::fmt;
use serialize::json;
use semver::VersionReq;
use http::client::RequestWriter;
use http::method::Get;
use url::Url;

mod puppetfile_parser;

#[cfg(test)]
mod test;

/// This represents a Puppetfile
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Puppetfile {
    /// The forge URL
    pub forge: String,
    /// All Modules contained in the Puppetfile
    pub modules: Vec<Module>
}

#[experimental]
impl Puppetfile {
    /// Try parsing the contents of a Puppetfile into a Puppetfile struct
    pub fn parse(contents: &str) -> Result<Puppetfile, String> {
        puppetfile_parser::parse(contents)
    }
}
impl fmt::Show for Puppetfile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "forge '{}'\n\n", self.forge);
        self.modules.iter().fold(res, |prev_res, module| { prev_res.and(write!(f, "\n{}\n", module)) })
    }
}

/// The representation of a puppet module
#[deriving(PartialEq, Clone)]
#[experimental]
pub struct Module {
    /// Name of the module
    pub name: String,
    /// More information about the module
    pub info: Vec<PuppetModuleInfo>
}

#[deriving(Decodable)]
struct ForgeVersionResponse {
    version: String
}

#[experimental]
impl Module {
    /// The current version of the module returned from the forge API
    pub fn forge_version(&self, forge_url: &String) -> Result<semver::Version, semver::ParseError> {
        let request: RequestWriter = RequestWriter::new(Get, self.version_url(forge_url)).unwrap();
        let mut response = match request.read_response() {
            Ok(response) => response,
            Err((_request, error)) => fail!(":-( {}", error),
        };
        let response_string = response.read_to_string().unwrap();
        let version_struct: ForgeVersionResponse = json::decode(response_string.as_slice()).unwrap();
        semver::Version::parse(version_struct.version.as_slice())
    }

    /// Builds the URL for the forge API for fetching the version
    pub fn version_url(&self, forge_url: &String) -> Url {
        let stripped_url = match forge_url.as_slice().ends_with("/") {
            true => forge_url.as_slice().slice_to(forge_url.len() - 1),
            _    => forge_url.as_slice()
        };
        let (user, mod_name) = self.user_name_pair().unwrap();
        Url::parse(format!("{}/users/{}/modules/{}/releases/find.json", stripped_url, user, mod_name).as_slice()).unwrap()
    }

    /// Returns user and module name from 'user/mod_name'
    pub fn user_name_pair(&self) -> Option<(&str, &str)> {
        if self.name.as_slice().contains("/") {
            let mut parts = self.name.as_slice().split('/');
            Some((parts.next().unwrap(), parts.next().unwrap()))
        } else {
            None
        }
    }

    /// Returns the version if specified
    pub fn version(&self) -> Option<&VersionReq> {
        for info in self.info.iter() {
            match *info {
                Version(ref v) => return Some(v),
                ModuleInfo(..) => ()
            }
        }
        None
    }
}
impl fmt::Show for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = write!(f, "mod '{}'", self.name);
        self.info.iter().fold(res, |prev_res, mod_info| {
            match *mod_info {
                Version(..) => prev_res.and(write!(f, ", '{}'", mod_info)),
                ModuleInfo(..) => prev_res.and(write!(f, ",\n  {}", mod_info)),
            }
        })
    }
}

/// Further Information on Puppet Modules
#[deriving(PartialEq, Clone)]
pub enum PuppetModuleInfo {
    /// Version as String
    Version(VersionReq),
    /// Key Value based Information
    ModuleInfo(String, String)
}
impl PuppetModuleInfo {
    /// Returns `true` if the option is a `Version` value
    pub fn is_version(&self) -> bool {
        match *self {
            Version(..)    => true,
            ModuleInfo(..) => false
        }
    }
}

impl fmt::Show for PuppetModuleInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version(ref v) => write!(f, "{}", v),
            ModuleInfo(ref k, ref v) => write!(f, ":{} => '{}'", k, v)
        }
    }
}

<|endoftext|>


<commit_before>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

#![deny(missing_docs)]

extern crate goblin;

use goblin::{elf, mach};
use std::cmp::Ordering;
use std::io::Cursor;

/// An object file.
pub struct File<'a> {
    kind: ObjectKind<'a>,
    data: &'a [u8],
}

enum ObjectKind<'a> {
    Elf(elf::Elf<'a>),
    MachO(mach::MachO<'a>),
}

/// The kind of a sections.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: &'a [u8],
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

impl<'a> File<'a> {
    /// Parse the raw object file data.
    pub fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let kind = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => {
                let elf = elf::Elf::parse(data).map_err(|_| "Could not parse ELF header")?;
                ObjectKind::Elf(elf)
            }
            goblin::Hint::Mach(_) => {
                let macho =
                    mach::MachO::parse(data, 0).map_err(|_| "Could not parse Mach-O header")?;
                ObjectKind::MachO(macho)
            }
            _ => return Err("Unknown file magic"),
        };
        Ok(File { kind, data })
    }

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    pub fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf_get_section(elf, section_name, self.data),
            ObjectKind::MachO(ref macho) => macho_get_section(macho, section_name),
        }
    }

    /// Get a `Vec` of the symbols defined in the file.
    pub fn get_symbols(&self) -> Vec<Symbol<'a>> {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf_get_symbols(elf),
            ObjectKind::MachO(ref macho) => macho_get_symbols(macho),
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    pub fn is_little_endian(&self) -> bool {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf.little_endian,
            ObjectKind::MachO(ref macho) => macho.header.is_little_endian(),
        }
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> &'a [u8] {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}

fn elf_get_section<'a>(elf: &elf::Elf<'a>, section_name: &str, data: &'a [u8]) -> Option<&'a [u8]> {
    for header in &elf.section_headers {
        if let Some(Ok(name)) = elf.shdr_strtab.get(header.sh_name) {
            if name == section_name {
                return Some(&data[header.sh_offset as usize..][..header.sh_size as usize]);
            }
        }
    }
    None
}

fn elf_get_symbols<'a>(elf: &elf::Elf<'a>) -> Vec<Symbol<'a>> {
    // Determine section kinds.
    // The section kinds are inherited by symbols in those sections.
    let mut section_kinds = Vec::new();
    for sh in &elf.section_headers {
        let kind = match sh.sh_type {
            elf::section_header::SHT_PROGBITS => {
                if sh.sh_flags & elf::section_header::SHF_EXECINSTR as u64 != 0 {
                    SectionKind::Text
                } else if sh.sh_flags & elf::section_header::SHF_WRITE as u64 != 0 {
                    SectionKind::Data
                } else {
                    SectionKind::ReadOnlyData
                }
            }
            elf::section_header::SHT_NOBITS => SectionKind::UninitializedData,
            _ => SectionKind::Unknown,
        };
        section_kinds.push(kind);
    }

    let mut symbols = Vec::new();
    // Skip undefined symbol index.
    for sym in elf.syms.iter().skip(1) {
        let kind = match elf::sym::st_type(sym.st_info) {
            elf::sym::STT_OBJECT => SymbolKind::Data,
            elf::sym::STT_FUNC => SymbolKind::Text,
            elf::sym::STT_SECTION => SymbolKind::Section,
            elf::sym::STT_FILE => SymbolKind::File,
            elf::sym::STT_COMMON => SymbolKind::Common,
            elf::sym::STT_TLS => SymbolKind::Tls,
            _ => SymbolKind::Unknown,
        };
        let global = elf::sym::st_bind(sym.st_info) != elf::sym::STB_LOCAL;
        let section_kind = if sym.st_shndx == elf::section_header::SHN_UNDEF as usize
            || sym.st_shndx >= section_kinds.len()
        {
            None
        } else {
            Some(section_kinds[sym.st_shndx])
        };
        let name = match elf.strtab.get(sym.st_name) {
            Some(Ok(name)) => name.as_bytes(),
            _ => continue,
        };
        symbols.push(Symbol {
            kind,
            section: sym.st_shndx,
            section_kind,
            global,
            name,
            address: sym.st_value,
            size: sym.st_size,
        });
    }
    symbols
}

fn macho_get_section<'a>(macho: &mach::MachO<'a>, section_name: &str) -> Option<&'a [u8]> {
    let segment_name = if section_name == ".eh_frame" {
        "__TEXT"
    } else {
        "__DWARF"
    };
    let section_name = macho_translate_section_name(section_name);

    for segment in &macho.segments {
        if let Ok(name) = segment.name() {
            if name == segment_name {
                for section in segment {
                    if let Ok((section, data)) = section {
                        if let Ok(name) = section.name() {
                            if name.as_bytes() == &*section_name {
                                return Some(data);
                            }
                        }
                    }
                }
            }
        }
    }
    None
}

// Translate the "." prefix to the "__" prefix used by OSX/Mach-O, eg
// ".debug_info" to "__debug_info".
fn macho_translate_section_name(section_name: &str) -> Vec<u8> {
    let mut name = Vec::with_capacity(section_name.len() + 1);
    name.push(b'_');
    name.push(b'_');
    for ch in &section_name.as_bytes()[1..] {
        name.push(*ch);
    }
    name
}

fn macho_get_symbols<'a>(macho: &mach::MachO<'a>) -> Vec<Symbol<'a>> {
    // Determine section kinds and end addresses.
    // The section kinds are inherited by symbols in those sections.
    // The section end addresses are needed for calculating symbol sizes.
    let mut section_kinds = Vec::new();
    let mut section_ends = Vec::new();
    for segment in &macho.segments {
        for section in segment {
            if let Ok((section, _)) = section {
                let sectname = section
                    .name()
                    .map(str::as_bytes)
                    .unwrap_or(&section.sectname[..]);
                let segname = section
                    .segname()
                    .map(str::as_bytes)
                    .unwrap_or(&section.segname[..]);
                let (section_kind, symbol_kind) = if segname == b"__TEXT" && sectname == b"__text" {
                    (SectionKind::Text, SymbolKind::Text)
                } else if segname == b"__DATA" && sectname == b"__data" {
                    (SectionKind::Data, SymbolKind::Data)
                } else if segname == b"__DATA" && sectname == b"__bss" {
                    (SectionKind::UninitializedData, SymbolKind::Data)
                } else {
                    (SectionKind::Other, SymbolKind::Unknown)
                };
                let section_index = section_kinds.len();
                section_kinds.push((section_kind, symbol_kind));
                section_ends.push(Symbol {
                    kind: SymbolKind::Section,
                    section: section_index + 1,
                    section_kind: Some(section_kind),
                    global: false,
                    name: &[],
                    address: section.addr + section.size,
                    size: 0,
                });
            } else {
                // Add placeholder so that indexing works.
                section_kinds.push((SectionKind::Unknown, SymbolKind::Unknown));
            }
        }
    }

    let mut symbols = Vec::new();
    for sym in macho.symbols() {
        if let Ok((name, nlist)) = sym {
            // Skip STAB debugging symbols.
            // FIXME: use N_STAB constant
            if nlist.n_type & 0xe0 != 0 {
                continue;
            }
            let n_type = nlist.n_type & mach::symbols::NLIST_TYPE_MASK;
            let (section_kind, kind) = if n_type == mach::symbols::N_SECT {
                if nlist.n_sect == 0 || nlist.n_sect - 1 >= section_kinds.len() {
                    (None, SymbolKind::Unknown)
                } else {
                    let (section_kind, kind) = section_kinds[nlist.n_sect - 1];
                    (Some(section_kind), kind)
                }
            } else {
                (None, SymbolKind::Unknown)
            };
            symbols.push(Symbol {
                kind,
                section: nlist.n_sect,
                section_kind,
                global: nlist.is_global(),
                name: name.as_bytes(),
                address: nlist.n_value,
                size: 0,
            });
        }
    }

    {
        // Calculate symbol sizes by sorting and finding the next symbol.
        let mut symbol_refs = Vec::with_capacity(symbols.len() + section_ends.len());
        symbol_refs.extend(symbols.iter_mut().filter(|s| !s.is_undefined()));
        symbol_refs.extend(section_ends.iter_mut());
        symbol_refs.sort_by(|a, b| {
            let ord = a.section.cmp(&b.section);
            if ord != Ordering::Equal {
                return ord;
            }
            let ord = a.address.cmp(&b.address);
            if ord != Ordering::Equal {
                return ord;
            }
            // Place the dummy end of section symbols last.
            (a.kind == SymbolKind::Section).cmp(&(b.kind == SymbolKind::Section))
        });

        for i in 0..symbol_refs.len() {
            let (before, after) = symbol_refs.split_at_mut(i + 1);
            let sym = &mut before[i];
            if sym.kind != SymbolKind::Section {
                if let Some(next) = after
                    .iter()
                    .skip_while(|x| {
                        x.kind != SymbolKind::Section && x.address == sym.address
                    })
                    .next()
                {
                    sym.size = next.address - sym.address;
                }
            }
        }
    }

    symbols
}

#[doc(hidden)]
#[deprecated]
pub trait Object {}
<commit_msg>Derive Debug on Symbol<commit_after>//! # `object`
//!
//! The `object` crate provides a unified interface to working with object files
//! across platforms.
//!
//! See the [`File` struct](./struct.File.html) for details.

#![deny(missing_docs)]

extern crate goblin;

use goblin::{elf, mach};
use std::cmp::Ordering;
use std::io::Cursor;

/// An object file.
pub struct File<'a> {
    kind: ObjectKind<'a>,
    data: &'a [u8],
}

enum ObjectKind<'a> {
    Elf(elf::Elf<'a>),
    MachO(mach::MachO<'a>),
}

/// The kind of a sections.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SectionKind {
    /// The section kind is unknown.
    Unknown,
    /// An executable code section.
    Text,
    /// A data section.
    Data,
    /// A read only data section.
    ReadOnlyData,
    /// An uninitialized data section.
    UninitializedData,
    /// Some other type of text or data section.
    Other,
}

/// A symbol table entry.
#[derive(Debug)]
pub struct Symbol<'a> {
    kind: SymbolKind,
    section: usize,
    section_kind: Option<SectionKind>,
    global: bool,
    name: &'a [u8],
    address: u64,
    size: u64,
}

/// The kind of a symbol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolKind {
    /// The symbol kind is unknown.
    Unknown,
    /// The symbol is for executable code.
    Text,
    /// The symbol is for a data object.
    Data,
    /// The symbol is for a section.
    Section,
    /// The symbol is the name of a file. It precedes symbols within that file.
    File,
    /// The symbol is for an uninitialized common block.
    Common,
    /// The symbol is for a thread local storage entity.
    Tls,
}

impl<'a> File<'a> {
    /// Parse the raw object file data.
    pub fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let mut cursor = Cursor::new(data);
        let kind = match goblin::peek(&mut cursor).map_err(|_| "Could not parse file magic")? {
            goblin::Hint::Elf(_) => {
                let elf = elf::Elf::parse(data).map_err(|_| "Could not parse ELF header")?;
                ObjectKind::Elf(elf)
            }
            goblin::Hint::Mach(_) => {
                let macho =
                    mach::MachO::parse(data, 0).map_err(|_| "Could not parse Mach-O header")?;
                ObjectKind::MachO(macho)
            }
            _ => return Err("Unknown file magic"),
        };
        Ok(File { kind, data })
    }

    /// Get the contents of the section named `section_name`, if such
    /// a section exists.
    pub fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf_get_section(elf, section_name, self.data),
            ObjectKind::MachO(ref macho) => macho_get_section(macho, section_name),
        }
    }

    /// Get a `Vec` of the symbols defined in the file.
    pub fn get_symbols(&self) -> Vec<Symbol<'a>> {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf_get_symbols(elf),
            ObjectKind::MachO(ref macho) => macho_get_symbols(macho),
        }
    }

    /// Return true if the file is little endian, false if it is big endian.
    pub fn is_little_endian(&self) -> bool {
        match self.kind {
            ObjectKind::Elf(ref elf) => elf.little_endian,
            ObjectKind::MachO(ref macho) => macho.header.is_little_endian(),
        }
    }
}

impl<'a> Symbol<'a> {
    /// Return the kind of this symbol.
    #[inline]
    pub fn kind(&self) -> SymbolKind {
        self.kind
    }

    /// Returns the section kind for the symbol, or `None` if the symbol is undefnined.
    #[inline]
    pub fn section_kind(&self) -> Option<SectionKind> {
        self.section_kind
    }

    /// Return true if the symbol is undefined.
    #[inline]
    pub fn is_undefined(&self) -> bool {
        self.section_kind.is_none()
    }

    /// Return true if the symbol is global.
    #[inline]
    pub fn is_global(&self) -> bool {
        self.global
    }

    /// Return true if the symbol is local.
    #[inline]
    pub fn is_local(&self) -> bool {
        !self.global
    }

    /// The name of the symbol.
    #[inline]
    pub fn name(&self) -> &'a [u8] {
        self.name
    }

    /// The address of the symbol. May be zero if the address is unknown.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// The size of the symbol. May be zero if the size is unknown.
    #[inline]
    pub fn size(&self) -> u64 {
        self.size
    }
}

fn elf_get_section<'a>(elf: &elf::Elf<'a>, section_name: &str, data: &'a [u8]) -> Option<&'a [u8]> {
    for header in &elf.section_headers {
        if let Some(Ok(name)) = elf.shdr_strtab.get(header.sh_name) {
            if name == section_name {
                return Some(&data[header.sh_offset as usize..][..header.sh_size as usize]);
            }
        }
    }
    None
}

fn elf_get_symbols<'a>(elf: &elf::Elf<'a>) -> Vec<Symbol<'a>> {
    // Determine section kinds.
    // The section kinds are inherited by symbols in those sections.
    let mut section_kinds = Vec::new();
    for sh in &elf.section_headers {
        let kind = match sh.sh_type {
            elf::section_header::SHT_PROGBITS => {
                if sh.sh_flags & elf::section_header::SHF_EXECINSTR as u64 != 0 {
                    SectionKind::Text
                } else if sh.sh_flags & elf::section_header::SHF_WRITE as u64 != 0 {
                    SectionKind::Data
                } else {
                    SectionKind::ReadOnlyData
                }
            }
            elf::section_header::SHT_NOBITS => SectionKind::UninitializedData,
            _ => SectionKind::Unknown,
        };
        section_kinds.push(kind);
    }

    let mut symbols = Vec::new();
    // Skip undefined symbol index.
    for sym in elf.syms.iter().skip(1) {
        let kind = match elf::sym::st_type(sym.st_info) {
            elf::sym::STT_OBJECT => SymbolKind::Data,
            elf::sym::STT_FUNC => SymbolKind::Text,
            elf::sym::STT_SECTION => SymbolKind::Section,
            elf::sym::STT_FILE => SymbolKind::File,
            elf::sym::STT_COMMON => SymbolKind::Common,
            elf::sym::STT_TLS => SymbolKind::Tls,
            _ => SymbolKind::Unknown,
        };
        let global = elf::sym::st_bind(sym.st_info) != elf::sym::STB_LOCAL;
        let section_kind = if sym.st_shndx == elf::section_header::SHN_UNDEF as usize
            || sym.st_shndx >= section_kinds.len()
        {
            None
        } else {
            Some(section_kinds[sym.st_shndx])
        };
        let name = match elf.strtab.get(sym.st_name) {
            Some(Ok(name)) => name.as_bytes(),
            _ => continue,
        };
        symbols.push(Symbol {
            kind,
            section: sym.st_shndx,
            section_kind,
            global,
            name,
            address: sym.st_value,
            size: sym.st_size,
        });
    }
    symbols
}

fn macho_get_section<'a>(macho: &mach::MachO<'a>, section_name: &str) -> Option<&'a [u8]> {
    let segment_name = if section_name == ".eh_frame" {
        "__TEXT"
    } else {
        "__DWARF"
    };
    let section_name = macho_translate_section_name(section_name);

    for segment in &macho.segments {
        if let Ok(name) = segment.name() {
            if name == segment_name {
                for section in segment {
                    if let Ok((section, data)) = section {
                        if let Ok(name) = section.name() {
                            if name.as_bytes() == &*section_name {
                                return Some(data);
                            }
                        }
                    }
                }
            }
        }
    }
    None
}

// Translate the "." prefix to the "__" prefix used by OSX/Mach-O, eg
// ".debug_info" to "__debug_info".
fn macho_translate_section_name(section_name: &str) -> Vec<u8> {
    let mut name = Vec::with_capacity(section_name.len() + 1);
    name.push(b'_');
    name.push(b'_');
    for ch in &section_name.as_bytes()[1..] {
        name.push(*ch);
    }
    name
}

fn macho_get_symbols<'a>(macho: &mach::MachO<'a>) -> Vec<Symbol<'a>> {
    // Determine section kinds and end addresses.
    // The section kinds are inherited by symbols in those sections.
    // The section end addresses are needed for calculating symbol sizes.
    let mut section_kinds = Vec::new();
    let mut section_ends = Vec::new();
    for segment in &macho.segments {
        for section in segment {
            if let Ok((section, _)) = section {
                let sectname = section
                    .name()
                    .map(str::as_bytes)
                    .unwrap_or(&section.sectname[..]);
                let segname = section
                    .segname()
                    .map(str::as_bytes)
                    .unwrap_or(&section.segname[..]);
                let (section_kind, symbol_kind) = if segname == b"__TEXT" && sectname == b"__text" {
                    (SectionKind::Text, SymbolKind::Text)
                } else if segname == b"__DATA" && sectname == b"__data" {
                    (SectionKind::Data, SymbolKind::Data)
                } else if segname == b"__DATA" && sectname == b"__bss" {
                    (SectionKind::UninitializedData, SymbolKind::Data)
                } else {
                    (SectionKind::Other, SymbolKind::Unknown)
                };
                let section_index = section_kinds.len();
                section_kinds.push((section_kind, symbol_kind));
                section_ends.push(Symbol {
                    kind: SymbolKind::Section,
                    section: section_index + 1,
                    section_kind: Some(section_kind),
                    global: false,
                    name: &[],
                    address: section.addr + section.size,
                    size: 0,
                });
            } else {
                // Add placeholder so that indexing works.
                section_kinds.push((SectionKind::Unknown, SymbolKind::Unknown));
            }
        }
    }

    let mut symbols = Vec::new();
    for sym in macho.symbols() {
        if let Ok((name, nlist)) = sym {
            // Skip STAB debugging symbols.
            // FIXME: use N_STAB constant
            if nlist.n_type & 0xe0 != 0 {
                continue;
            }
            let n_type = nlist.n_type & mach::symbols::NLIST_TYPE_MASK;
            let (section_kind, kind) = if n_type == mach::symbols::N_SECT {
                if nlist.n_sect == 0 || nlist.n_sect - 1 >= section_kinds.len() {
                    (None, SymbolKind::Unknown)
                } else {
                    let (section_kind, kind) = section_kinds[nlist.n_sect - 1];
                    (Some(section_kind), kind)
                }
            } else {
                (None, SymbolKind::Unknown)
            };
            symbols.push(Symbol {
                kind,
                section: nlist.n_sect,
                section_kind,
                global: nlist.is_global(),
                name: name.as_bytes(),
                address: nlist.n_value,
                size: 0,
            });
        }
    }

    {
        // Calculate symbol sizes by sorting and finding the next symbol.
        let mut symbol_refs = Vec::with_capacity(symbols.len() + section_ends.len());
        symbol_refs.extend(symbols.iter_mut().filter(|s| !s.is_undefined()));
        symbol_refs.extend(section_ends.iter_mut());
        symbol_refs.sort_by(|a, b| {
            let ord = a.section.cmp(&b.section);
            if ord != Ordering::Equal {
                return ord;
            }
            let ord = a.address.cmp(&b.address);
            if ord != Ordering::Equal {
                return ord;
            }
            // Place the dummy end of section symbols last.
            (a.kind == SymbolKind::Section).cmp(&(b.kind == SymbolKind::Section))
        });

        for i in 0..symbol_refs.len() {
            let (before, after) = symbol_refs.split_at_mut(i + 1);
            let sym = &mut before[i];
            if sym.kind != SymbolKind::Section {
                if let Some(next) = after
                    .iter()
                    .skip_while(|x| {
                        x.kind != SymbolKind::Section && x.address == sym.address
                    })
                    .next()
                {
                    sym.size = next.address - sym.address;
                }
            }
        }
    }

    symbols
}

#[doc(hidden)]
#[deprecated]
pub trait Object {}
<|endoftext|>