<commit_before>//! zmq.rs is a native implementation of [ØMQ] in the Rust programming language. It is still in a
//! very early stage of designing and development, so it is **not** supposed to be used seriously now.
//!
//! # Examples
//!
//! There are only very few interfaces implemented till now. Try this example for now:
//!
//! ```rust
//! extern crate zeromq;
//!
//! fn main() {
//!     let ctx = zeromq::Context::new();
//!
//!     let mut req = ctx.socket(zeromq::SocketType::REQ);
//!     req.connect("tcp://127.0.0.1:12347").unwrap();
//!
//!     let mut rep = ctx.socket(zeromq::SocketType::REP);
//!     rep.bind("tcp://127.0.0.1:12347").unwrap();
//!
//!     let mut msg = box zeromq::Msg::new(4);
//!     msg.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
//!
//!     req.msg_send(msg).unwrap();
//!     println!("We got: {}", rep.msg_recv().unwrap());
//! }
//! ```
//!
//!  [ØMQ]: http://zeromq.org/

#![crate_name = "zeromq"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![feature(phase)]
#[phase(plugin, link)] extern crate log;

pub use ctx::Context;
pub use consts::SocketType;
pub use consts::SocketOption;
pub use consts::ErrorCode;
pub use msg::Msg;
pub use rep::RepSocket;
pub use req::ReqSocket;
pub use result::{ZmqResult, ZmqError};
pub use socket::ZmqSocket;

mod ctx;
mod consts;
mod inproc;
mod msg;
mod rep;
mod req;
mod result;
mod socket;
mod socket_base;
mod stream_engine;
mod tcp_connecter;
mod tcp_listener;
mod options;
mod v2_encoder;
mod v2_decoder;
mod v2_protocol;

#[cfg(test)]
mod test {
    #[test]
    fn test_socket_type() {
        assert_eq!(super::SocketType::REQ as int, 3);
    }

    #[test]
    fn test_socket_create() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.getsockopt(super::SocketOption::TYPE), super::SocketType::REQ as int);
    }

    #[test]
    fn test_socket_bind() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.bind("").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("://127").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("tcp://").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("tcpp://127.0.0.1:12345").unwrap_err().code, super::ErrorCode::EPROTONOSUPPORT);
        assert_eq!(s.bind("tcp://10.0.1.255:12345").unwrap_err().code, super::ErrorCode::ECONNREFUSED);
        assert_eq!(s.bind("tcp://10.0.1.1:12z45").unwrap_err().code, super::ErrorCode::EINVAL);
        assert!(s.bind("tcp://127.0.0.1:12345").is_ok());
        assert_eq!(s.bind("tcp://127.0.0.1:12345").unwrap_err().code, super::ErrorCode::ECONNREFUSED);
    }

    #[test]
    fn test_socket_connect() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.connect("").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("://127").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("tcp://").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("tcpp://127.0.0.1:12346").unwrap_err().code, super::ErrorCode::EPROTONOSUPPORT);
        assert_eq!(s.connect("tcp://10.0.1.1:12z46").unwrap_err().code, super::ErrorCode::EINVAL);
        assert!(s.connect("tcp://127.0.0.1:12346").is_ok());
        assert!(s.connect("tcp://127.0.0.1:12346").is_ok());
    }

    #[test]
    fn test_socket_small_message() {
        let c = super::Context::new();
        let mut req = c.socket(super::SocketType::REQ);
        let mut rep = c.socket(super::SocketType::REP);
        assert!(rep.bind("tcp://127.0.0.1:12347").is_ok());
        assert!(req.connect("tcp://127.0.0.1:12347").is_ok());

        let mut msg_sent = box super::Msg::new(4);
        msg_sent.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
        assert!(req.msg_send(msg_sent).is_ok());

        let msg_recv = rep.msg_recv().unwrap();
        assert_eq!(msg_recv.data, [65u8, 66u8, 67u8, 68u8].to_vec());
    }

    #[test]
    fn test_inproc_and_moved_socket() {
        let c = super::Context::new();
        let req = c.socket(super::SocketType::REQ);

        spawn(move || {
            let mut req = req;
            assert!(req.connect("inproc://#1").is_ok());

            let mut msg_sent = box super::Msg::new(4);
            msg_sent.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
            assert!(req.msg_send(msg_sent).is_ok());
        });

        let mut rep = c.socket(super::SocketType::REP);
        assert!(rep.bind("inproc://#1").is_ok());
        let msg_recv = rep.msg_recv().unwrap();
        assert_eq!(msg_recv.data, [65u8, 66u8, 67u8, 68u8].to_vec());
    }
}
<commit_msg>feature phase -> macro_use<commit_after>//! zmq.rs is a native implementation of [ØMQ] in the Rust programming language. It is still in a
//! very early stage of designing and development, so it is **not** supposed to be used seriously now.
//!
//! # Examples
//!
//! There are only very few interfaces implemented till now. Try this example for now:
//!
//! ```rust
//! extern crate zeromq;
//!
//! fn main() {
//!     let ctx = zeromq::Context::new();
//!
//!     let mut req = ctx.socket(zeromq::SocketType::REQ);
//!     req.connect("tcp://127.0.0.1:12347").unwrap();
//!
//!     let mut rep = ctx.socket(zeromq::SocketType::REP);
//!     rep.bind("tcp://127.0.0.1:12347").unwrap();
//!
//!     let mut msg = box zeromq::Msg::new(4);
//!     msg.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
//!
//!     req.msg_send(msg).unwrap();
//!     println!("We got: {}", rep.msg_recv().unwrap());
//! }
//! ```
//!
//!  [ØMQ]: http://zeromq.org/

#![crate_name = "zeromq"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#[macro_use] extern crate log;

pub use ctx::Context;
pub use consts::SocketType;
pub use consts::SocketOption;
pub use consts::ErrorCode;
pub use msg::Msg;
pub use rep::RepSocket;
pub use req::ReqSocket;
pub use result::{ZmqResult, ZmqError};
pub use socket::ZmqSocket;

mod ctx;
mod consts;
mod inproc;
mod msg;
mod rep;
mod req;
mod result;
mod socket;
mod socket_base;
mod stream_engine;
mod tcp_connecter;
mod tcp_listener;
mod options;
mod v2_encoder;
mod v2_decoder;
mod v2_protocol;

#[cfg(test)]
mod test {
    #[test]
    fn test_socket_type() {
        assert_eq!(super::SocketType::REQ as int, 3);
    }

    #[test]
    fn test_socket_create() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.getsockopt(super::SocketOption::TYPE), super::SocketType::REQ as int);
    }

    #[test]
    fn test_socket_bind() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.bind("").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("://127").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("tcp://").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.bind("tcpp://127.0.0.1:12345").unwrap_err().code, super::ErrorCode::EPROTONOSUPPORT);
        assert_eq!(s.bind("tcp://10.0.1.255:12345").unwrap_err().code, super::ErrorCode::ECONNREFUSED);
        assert_eq!(s.bind("tcp://10.0.1.1:12z45").unwrap_err().code, super::ErrorCode::EINVAL);
        assert!(s.bind("tcp://127.0.0.1:12345").is_ok());
        assert_eq!(s.bind("tcp://127.0.0.1:12345").unwrap_err().code, super::ErrorCode::ECONNREFUSED);
    }

    #[test]
    fn test_socket_connect() {
        let c = super::Context::new();
        let s = c.socket(super::SocketType::REQ);
        assert_eq!(s.connect("").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("://127").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("tcp://").unwrap_err().code, super::ErrorCode::EINVAL);
        assert_eq!(s.connect("tcpp://127.0.0.1:12346").unwrap_err().code, super::ErrorCode::EPROTONOSUPPORT);
        assert_eq!(s.connect("tcp://10.0.1.1:12z46").unwrap_err().code, super::ErrorCode::EINVAL);
        assert!(s.connect("tcp://127.0.0.1:12346").is_ok());
        assert!(s.connect("tcp://127.0.0.1:12346").is_ok());
    }

    #[test]
    fn test_socket_small_message() {
        let c = super::Context::new();
        let mut req = c.socket(super::SocketType::REQ);
        let mut rep = c.socket(super::SocketType::REP);
        assert!(rep.bind("tcp://127.0.0.1:12347").is_ok());
        assert!(req.connect("tcp://127.0.0.1:12347").is_ok());

        let mut msg_sent = box super::Msg::new(4);
        msg_sent.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
        assert!(req.msg_send(msg_sent).is_ok());

        let msg_recv = rep.msg_recv().unwrap();
        assert_eq!(msg_recv.data, [65u8, 66u8, 67u8, 68u8].to_vec());
    }

    #[test]
    fn test_inproc_and_moved_socket() {
        let c = super::Context::new();
        let req = c.socket(super::SocketType::REQ);

        spawn(move || {
            let mut req = req;
            assert!(req.connect("inproc://#1").is_ok());

            let mut msg_sent = box super::Msg::new(4);
            msg_sent.data.push_all([65u8, 66u8, 67u8, 68u8].as_slice());
            assert!(req.msg_send(msg_sent).is_ok());
        });

        let mut rep = c.socket(super::SocketType::REP);
        assert!(rep.bind("inproc://#1").is_ok());
        let msg_recv = rep.msg_recv().unwrap();
        assert_eq!(msg_recv.data, [65u8, 66u8, 67u8, 68u8].to_vec());
    }
}
<|endoftext|>


<commit_before>//! This is the main lib.rs file for Xt Core

// This file is part of Xt.

// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2017  The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

#![cfg_attr(feature = "ci", feature(plugin))]
#![cfg_attr(feature = "ci", plugin(clippy))]
#![cfg_attr(feature = "ci", allow(unstable_features))]
#![deny(missing_docs, missing_debug_implementations,
        missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate slog;
extern crate slog_json;
extern crate slog_async;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

pub mod logging;
pub mod rpc;
pub mod server;
pub mod utils;
<commit_msg>Again, fix CI and Clippy bug ok then<commit_after>//! This is the main lib.rs file for Xt Core

// This file is part of Xt.

// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2017  The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

#![cfg_attr(feature = "ci", feature(plugin))]
#![cfg_attr(feature = "ci", plugin(clippy))]
#![cfg_attr(feature = "ci", allow(unstable_features))]

#![deny(missing_docs, missing_debug_implementations,
        missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unused_import_braces,
        unused_qualifications)]

#[macro_use]
extern crate slog;
extern crate slog_json;
extern crate slog_async;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

pub mod logging;
pub mod rpc;
pub mod server;
pub mod utils;
<|endoftext|>


<commit_before>//! Shared interrupt description and set-up code.
//! See the `bits*::irq` modules for arch-specific portions.

use bitflags::*;

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ({}, vec={}) {}",
            self.mnemonic, self.irqtype, self.vector, self.description
        )
    }
}

pub const DIVIDE_ERROR_VECTOR: u8 = 0;
pub const DEBUG_VECTOR: u8 = 1;
pub const NONMASKABLE_INTERRUPT_VECTOR: u8 = 2;
pub const BREAKPOINT_VECTOR: u8 = 3;
pub const OVERFLOW_VECTOR: u8 = 4;
pub const BOUND_RANGE_EXCEEDED_VECTOR: u8 = 5;
pub const INVALID_OPCODE_VECTOR: u8 = 6;
pub const DEVICE_NOT_AVAILABLE_VECTOR: u8 = 7;
pub const DOUBLE_FAULT_VECTOR: u8 = 8;
pub const COPROCESSOR_SEGMENT_OVERRUN_VECTOR: u8 = 9;
pub const INVALID_TSS_VECTOR: u8 = 10;
pub const SEGMENT_NOT_PRESENT_VECTOR: u8 = 11;
pub const STACK_SEGEMENT_FAULT_VECTOR: u8 = 12;
pub const GENERAL_PROTECTION_FAULT_VECTOR: u8 = 13;
pub const PAGE_FAULT_VECTOR: u8 = 14;
pub const X87_FPU_VECTOR: u8 = 16;
pub const ALIGNMENT_CHECK_VECTOR: u8 = 17;
pub const MACHINE_CHECK_VECTOR: u8 = 18;
pub const SIMD_FLOATING_POINT_VECTOR: u8 = 19;
pub const VIRTUALIZATION_VECTOR: u8 = 20;

/// x86 External Interrupts (1-32).
pub static EXCEPTIONS: [InterruptDescription; 32] = [
    InterruptDescription {
        vector: DIVIDE_ERROR_VECTOR,
        mnemonic: "#DE",
        description: "Divide Error",
        irqtype: "Fault",
        source: "DIV and IDIV instructions.",
    },
    InterruptDescription {
        vector: DEBUG_VECTOR,
        mnemonic: "#DB",
        description: "Debug",
        irqtype: "Fault / Trap",
        source: "Debug condition",
    },
    InterruptDescription {
        vector: NONMASKABLE_INTERRUPT_VECTOR,
        mnemonic: "NMI",
        description: "Nonmaskable Interrupt",
        irqtype: "Interrupt",
        source: "Nonmaskable external interrupt.",
    },
    InterruptDescription {
        vector: BREAKPOINT_VECTOR,
        mnemonic: "#BP",
        description: "Breakpoint",
        irqtype: "Trap",
        source: "INT 3 instruction.",
    },
    InterruptDescription {
        vector: OVERFLOW_VECTOR,
        mnemonic: "#OF",
        description: "Overflow",
        irqtype: "Trap",
        source: "INTO instruction.",
    },
    InterruptDescription {
        vector: BOUND_RANGE_EXCEEDED_VECTOR,
        mnemonic: "#BR",
        description: "BOUND Range Exceeded",
        irqtype: "Fault",
        source: "BOUND instruction.",
    },
    InterruptDescription {
        vector: INVALID_OPCODE_VECTOR,
        mnemonic: "#UD",
        description: "Invalid Opcode (Undefined \
                      Opcode)",
        irqtype: "Fault",
        source: "UD2 instruction or reserved \
                 opcode.",
    },
    InterruptDescription {
        vector: DEVICE_NOT_AVAILABLE_VECTOR,
        mnemonic: "#NM",
        description: "Device Not Available (No \
                      Math Coprocessor)",
        irqtype: "Fault",
        source: "Floating-point or WAIT/FWAIT \
                 instruction.",
    },
    InterruptDescription {
        vector: DOUBLE_FAULT_VECTOR,
        mnemonic: "#DF",
        description: "Double Fault",
        irqtype: "Abort",
        source: "Any instruction that can \
                 generate an exception, an NMI, \
                 or an INTR.",
    },
    InterruptDescription {
        vector: COPROCESSOR_SEGMENT_OVERRUN_VECTOR,
        mnemonic: "",
        description: "Coprocessor Segment Overrun",
        irqtype: "Fault",
        source: "Floating-point instruction.",
    },
    InterruptDescription {
        vector: INVALID_TSS_VECTOR,
        mnemonic: "#TS",
        description: "Invalid TSS",
        irqtype: "Fault",
        source: "Task switch or TSS access.",
    },
    InterruptDescription {
        vector: SEGMENT_NOT_PRESENT_VECTOR,
        mnemonic: "#NP",
        description: "Segment Not Present",
        irqtype: "Fault",
        source: "Loading segment registers or \
                 accessing system segments.",
    },
    InterruptDescription {
        vector: STACK_SEGEMENT_FAULT_VECTOR,
        mnemonic: "#SS",
        description: "Stack-Segment Fault",
        irqtype: "Fault",
        source: "Stack operations and SS register \
                 loads.",
    },
    InterruptDescription {
        vector: GENERAL_PROTECTION_FAULT_VECTOR,
        mnemonic: "#GP",
        description: "General Protection",
        irqtype: "Fault",
        source: "Any memory reference and other \
                 protection checks.",
    },
    InterruptDescription {
        vector: PAGE_FAULT_VECTOR,
        mnemonic: "#PF",
        description: "Page Fault",
        irqtype: "Fault",
        source: "Any memory reference.",
    },
    InterruptDescription {
        vector: 15,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "None.",
    },
    InterruptDescription {
        vector: X87_FPU_VECTOR,
        mnemonic: "#MF",
        description: "x87 FPU Floating-Point",
        irqtype: "Fault",
        source: "x87 FPU instructions.",
    },
    InterruptDescription {
        vector: ALIGNMENT_CHECK_VECTOR,
        mnemonic: "#AC",
        description: "Alignment Check",
        irqtype: "Fault",
        source: "Unaligned memory access.",
    },
    InterruptDescription {
        vector: MACHINE_CHECK_VECTOR,
        mnemonic: "#MC",
        description: "Machine Check",
        irqtype: "Abort",
        source: "Internal machine error.",
    },
    InterruptDescription {
        vector: SIMD_FLOATING_POINT_VECTOR,
        mnemonic: "#XM",
        description: "SIMD Floating-Point",
        irqtype: "Fault",
        source: "SSE SIMD instructions.",
    },
    InterruptDescription {
        vector: VIRTUALIZATION_VECTOR,
        mnemonic: "#VE",
        description: "Virtualization",
        irqtype: "Fault",
        source: "EPT violation.",
    },
    InterruptDescription {
        vector: 21,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 22,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 23,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 24,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 25,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 26,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 27,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 28,
        mnemonic: "",
        description: "",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 29,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 30,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 31,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
];

bitflags! {
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub struct PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const P = bit!(0);

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const WR = bit!(1);

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const US = bit!(2);

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const RSVD = bit!(3);

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const ID = bit!(4);

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PK = bit!(5);
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PageFaultError::P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PageFaultError::WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PageFaultError::US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PageFaultError::RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PageFaultError::ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

/// Enable Interrupts.
///
/// # Safety
/// Only allowed if we have IO privileges for the current operating level in RFlags.
pub unsafe fn enable() {
    llvm_asm!("sti");
}

/// Disable Interrupts.
///
/// # Safety
/// Only allowed if we have IO privileges for the current operating level in RFlags.
pub unsafe fn disable() {
    llvm_asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ($x:expr) => {{
        llvm_asm!("int $0" :: "N" ($x));
    }};
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;
    #[test]
    fn bit_macro() {
        assert!(PageFaultError::PK.bits() == 0b100000);
        assert!(PageFaultError::ID.bits() == 0b10000);
        assert!(PageFaultError::RSVD.bits() == 0b1000);
        assert!(PageFaultError::US.bits() == 0b100);
        assert!(PageFaultError::WR.bits() == 0b10);
        assert!(PageFaultError::P.bits() == 0b1);
    }
}
<commit_msg>Some trivial transforms from llvm_asm to asm.<commit_after>//! Shared interrupt description and set-up code.
//! See the `bits*::irq` modules for arch-specific portions.

use bitflags::*;

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} ({}, vec={}) {}",
            self.mnemonic, self.irqtype, self.vector, self.description
        )
    }
}

pub const DIVIDE_ERROR_VECTOR: u8 = 0;
pub const DEBUG_VECTOR: u8 = 1;
pub const NONMASKABLE_INTERRUPT_VECTOR: u8 = 2;
pub const BREAKPOINT_VECTOR: u8 = 3;
pub const OVERFLOW_VECTOR: u8 = 4;
pub const BOUND_RANGE_EXCEEDED_VECTOR: u8 = 5;
pub const INVALID_OPCODE_VECTOR: u8 = 6;
pub const DEVICE_NOT_AVAILABLE_VECTOR: u8 = 7;
pub const DOUBLE_FAULT_VECTOR: u8 = 8;
pub const COPROCESSOR_SEGMENT_OVERRUN_VECTOR: u8 = 9;
pub const INVALID_TSS_VECTOR: u8 = 10;
pub const SEGMENT_NOT_PRESENT_VECTOR: u8 = 11;
pub const STACK_SEGEMENT_FAULT_VECTOR: u8 = 12;
pub const GENERAL_PROTECTION_FAULT_VECTOR: u8 = 13;
pub const PAGE_FAULT_VECTOR: u8 = 14;
pub const X87_FPU_VECTOR: u8 = 16;
pub const ALIGNMENT_CHECK_VECTOR: u8 = 17;
pub const MACHINE_CHECK_VECTOR: u8 = 18;
pub const SIMD_FLOATING_POINT_VECTOR: u8 = 19;
pub const VIRTUALIZATION_VECTOR: u8 = 20;

/// x86 External Interrupts (1-32).
pub static EXCEPTIONS: [InterruptDescription; 32] = [
    InterruptDescription {
        vector: DIVIDE_ERROR_VECTOR,
        mnemonic: "#DE",
        description: "Divide Error",
        irqtype: "Fault",
        source: "DIV and IDIV instructions.",
    },
    InterruptDescription {
        vector: DEBUG_VECTOR,
        mnemonic: "#DB",
        description: "Debug",
        irqtype: "Fault / Trap",
        source: "Debug condition",
    },
    InterruptDescription {
        vector: NONMASKABLE_INTERRUPT_VECTOR,
        mnemonic: "NMI",
        description: "Nonmaskable Interrupt",
        irqtype: "Interrupt",
        source: "Nonmaskable external interrupt.",
    },
    InterruptDescription {
        vector: BREAKPOINT_VECTOR,
        mnemonic: "#BP",
        description: "Breakpoint",
        irqtype: "Trap",
        source: "INT 3 instruction.",
    },
    InterruptDescription {
        vector: OVERFLOW_VECTOR,
        mnemonic: "#OF",
        description: "Overflow",
        irqtype: "Trap",
        source: "INTO instruction.",
    },
    InterruptDescription {
        vector: BOUND_RANGE_EXCEEDED_VECTOR,
        mnemonic: "#BR",
        description: "BOUND Range Exceeded",
        irqtype: "Fault",
        source: "BOUND instruction.",
    },
    InterruptDescription {
        vector: INVALID_OPCODE_VECTOR,
        mnemonic: "#UD",
        description: "Invalid Opcode (Undefined \
                      Opcode)",
        irqtype: "Fault",
        source: "UD2 instruction or reserved \
                 opcode.",
    },
    InterruptDescription {
        vector: DEVICE_NOT_AVAILABLE_VECTOR,
        mnemonic: "#NM",
        description: "Device Not Available (No \
                      Math Coprocessor)",
        irqtype: "Fault",
        source: "Floating-point or WAIT/FWAIT \
                 instruction.",
    },
    InterruptDescription {
        vector: DOUBLE_FAULT_VECTOR,
        mnemonic: "#DF",
        description: "Double Fault",
        irqtype: "Abort",
        source: "Any instruction that can \
                 generate an exception, an NMI, \
                 or an INTR.",
    },
    InterruptDescription {
        vector: COPROCESSOR_SEGMENT_OVERRUN_VECTOR,
        mnemonic: "",
        description: "Coprocessor Segment Overrun",
        irqtype: "Fault",
        source: "Floating-point instruction.",
    },
    InterruptDescription {
        vector: INVALID_TSS_VECTOR,
        mnemonic: "#TS",
        description: "Invalid TSS",
        irqtype: "Fault",
        source: "Task switch or TSS access.",
    },
    InterruptDescription {
        vector: SEGMENT_NOT_PRESENT_VECTOR,
        mnemonic: "#NP",
        description: "Segment Not Present",
        irqtype: "Fault",
        source: "Loading segment registers or \
                 accessing system segments.",
    },
    InterruptDescription {
        vector: STACK_SEGEMENT_FAULT_VECTOR,
        mnemonic: "#SS",
        description: "Stack-Segment Fault",
        irqtype: "Fault",
        source: "Stack operations and SS register \
                 loads.",
    },
    InterruptDescription {
        vector: GENERAL_PROTECTION_FAULT_VECTOR,
        mnemonic: "#GP",
        description: "General Protection",
        irqtype: "Fault",
        source: "Any memory reference and other \
                 protection checks.",
    },
    InterruptDescription {
        vector: PAGE_FAULT_VECTOR,
        mnemonic: "#PF",
        description: "Page Fault",
        irqtype: "Fault",
        source: "Any memory reference.",
    },
    InterruptDescription {
        vector: 15,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "None.",
    },
    InterruptDescription {
        vector: X87_FPU_VECTOR,
        mnemonic: "#MF",
        description: "x87 FPU Floating-Point",
        irqtype: "Fault",
        source: "x87 FPU instructions.",
    },
    InterruptDescription {
        vector: ALIGNMENT_CHECK_VECTOR,
        mnemonic: "#AC",
        description: "Alignment Check",
        irqtype: "Fault",
        source: "Unaligned memory access.",
    },
    InterruptDescription {
        vector: MACHINE_CHECK_VECTOR,
        mnemonic: "#MC",
        description: "Machine Check",
        irqtype: "Abort",
        source: "Internal machine error.",
    },
    InterruptDescription {
        vector: SIMD_FLOATING_POINT_VECTOR,
        mnemonic: "#XM",
        description: "SIMD Floating-Point",
        irqtype: "Fault",
        source: "SSE SIMD instructions.",
    },
    InterruptDescription {
        vector: VIRTUALIZATION_VECTOR,
        mnemonic: "#VE",
        description: "Virtualization",
        irqtype: "Fault",
        source: "EPT violation.",
    },
    InterruptDescription {
        vector: 21,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 22,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 23,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 24,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 25,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 26,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 27,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 28,
        mnemonic: "",
        description: "",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 29,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: ".",
    },
    InterruptDescription {
        vector: 30,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
    InterruptDescription {
        vector: 31,
        mnemonic: "",
        description: "RESERVED",
        irqtype: "",
        source: "",
    },
];

bitflags! {
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    pub struct PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const P = bit!(0);

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const WR = bit!(1);

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const US = bit!(2);

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const RSVD = bit!(3);

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const ID = bit!(4);

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PK = bit!(5);
    }
}

impl fmt::Display for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PageFaultError::P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PageFaultError::WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PageFaultError::US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PageFaultError::RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PageFaultError::ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

/// Enable Interrupts.
///
/// # Safety
/// Only allowed if we have IO privileges for the current operating level in RFlags.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
///
/// # Safety
/// Only allowed if we have IO privileges for the current operating level in RFlags.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ($x:expr) => {{
        asm!("int $0" :: "N" ($x));
    }};
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;
    #[test]
    fn bit_macro() {
        assert!(PageFaultError::PK.bits() == 0b100000);
        assert!(PageFaultError::ID.bits() == 0b10000);
        assert!(PageFaultError::RSVD.bits() == 0b1000);
        assert!(PageFaultError::US.bits() == 0b100);
        assert!(PageFaultError::WR.bits() == 0b10);
        assert!(PageFaultError::P.bits() == 0b1);
    }
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2016 Saurav Sachidanand

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

mod ffi;
mod error;

use ffi::*;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use error::NFDError;

/// Result of opening a file dialog
pub enum Response {
    /// User pressed okay. `String` is the file path selected
    Okay(String),
    /// User pressed okay on mupliple selections. Result contains a Vec of all the files
    OkayMultiple(Vec<String>),
    /// User pressed cancel
    Cancel,
}

#[derive(Copy, Clone, PartialEq)]
pub enum DialogType {
    SingleFile,
    MultipleFiles,
    SaveFile,
}

pub struct DialogBuilder<'a> {
    filter: Option<&'a str>,
    default_path: Option<&'a str>,
    dialog_type: DialogType,
}

impl<'a> DialogBuilder<'a> {

    pub fn new(dialog_type: DialogType) -> Self {
        DialogBuilder {
            filter: None,
            default_path: None,
            dialog_type: dialog_type,
        }
    }

    pub fn filter(&'a mut self, filter: &'a str) -> &mut DialogBuilder {
        self.filter = Some(filter);
        self
    }

    pub fn default_path(&'a mut self, path: &'a str) -> &mut DialogBuilder {
        self.default_path = Some(path);
        self
    }

    pub fn open(&self) -> Result<Response> {
        open_dialog(self.filter, self.default_path, self.dialog_type.clone())
    }
}

pub fn dialog<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::SingleFile)
}

pub fn dialog_multiple<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::MultipleFiles)
}

pub fn dialog_save<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::SaveFile)
}

pub type Result<T> = std::result::Result<T, NFDError>;

/// Open single file dialog
pub fn open_file_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::SingleFile)
}

/// Open mulitple file dialog
pub fn open_file_multiple_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::MultipleFiles)
}

/// Open save dialog
pub fn open_save_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::SaveFile)
}

pub fn open_dialog(filter_list: Option<&str>, default_path: Option<&str>, dialog_type: DialogType) -> Result<Response> {
    let result;
    let filter_list_cstring;
    let default_path_cstring;

    let filter_list_ptr = match filter_list {
        Some(fl_str) => {
            filter_list_cstring = try!(CString::new(fl_str));
            filter_list_cstring.as_ptr()
        }
        None => std::ptr::null()
    };

    let default_path_ptr = match default_path {
        Some(dp_str) => {
            default_path_cstring = try!(CString::new(dp_str));
            default_path_cstring.as_ptr()
        }
        None => std::ptr::null()
    };

    let mut out_path: *mut c_char = std::ptr::null_mut();
    let ptr_out_path = &mut out_path as *mut *mut c_char;

    let mut out_multiple = nfdpathset_t::default();
    let ptr_out_multyple = &mut out_multiple as *mut nfdpathset_t;

    unsafe {
        result = match dialog_type {
            DialogType::SingleFile => {
                NFD_OpenDialog(filter_list_ptr, default_path_ptr, ptr_out_path)
            },

            DialogType::MultipleFiles => {
                NFD_OpenDialogMultiple(filter_list_ptr, default_path_ptr, ptr_out_multyple)
            },

            DialogType::SaveFile => {
                NFD_SaveDialog(filter_list_ptr, default_path_ptr, ptr_out_path)
            },
        };

        match result {
            nfdresult_t::NFD_OKAY =>{
                if dialog_type == DialogType::SingleFile {
                    Ok(Response::Okay(CStr::from_ptr(out_path).to_string_lossy().into_owned()))
                } else {
                    let count = NFD_PathSet_GetCount(&out_multiple);
                    let mut res = Vec::with_capacity(count);
                    for i in 0..count {
                        let path = CStr::from_ptr(NFD_PathSet_GetPath(&out_multiple, i)).to_string_lossy().into_owned();
                        res.push(path)

                    }

                    NFD_PathSet_Free(ptr_out_multyple);

                    Ok(Response::OkayMultiple(res))
                }
            },

            nfdresult_t::NFD_CANCEL => Ok(Response::Cancel),
            nfdresult_t::NFD_ERROR => Err(NFDError::Error(CStr::from_ptr(NFD_GetError()).to_string_lossy().into_owned())),
        }
    }
}
<commit_msg>Fix bug with Save Dialog<commit_after>/*
   Copyright (c) 2016 Saurav Sachidanand

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

mod ffi;
mod error;

use ffi::*;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use error::NFDError;

/// Result of opening a file dialog
pub enum Response {
    /// User pressed okay. `String` is the file path selected
    Okay(String),
    /// User pressed okay on mupliple selections. Result contains a Vec of all the files
    OkayMultiple(Vec<String>),
    /// User pressed cancel
    Cancel,
}

#[derive(Copy, Clone, PartialEq)]
pub enum DialogType {
    SingleFile,
    MultipleFiles,
    SaveFile,
}

pub struct DialogBuilder<'a> {
    filter: Option<&'a str>,
    default_path: Option<&'a str>,
    dialog_type: DialogType,
}

impl<'a> DialogBuilder<'a> {

    pub fn new(dialog_type: DialogType) -> Self {
        DialogBuilder {
            filter: None,
            default_path: None,
            dialog_type: dialog_type,
        }
    }

    pub fn filter(&'a mut self, filter: &'a str) -> &mut DialogBuilder {
        self.filter = Some(filter);
        self
    }

    pub fn default_path(&'a mut self, path: &'a str) -> &mut DialogBuilder {
        self.default_path = Some(path);
        self
    }

    pub fn open(&self) -> Result<Response> {
        open_dialog(self.filter, self.default_path, self.dialog_type.clone())
    }
}

pub fn dialog<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::SingleFile)
}

pub fn dialog_multiple<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::MultipleFiles)
}

pub fn dialog_save<'a>() -> DialogBuilder<'a> {
    DialogBuilder::new(DialogType::SaveFile)
}

pub type Result<T> = std::result::Result<T, NFDError>;

/// Open single file dialog
pub fn open_file_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::SingleFile)
}

/// Open mulitple file dialog
pub fn open_file_multiple_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::MultipleFiles)
}

/// Open save dialog
pub fn open_save_dialog(filter_list: Option<&str>, default_path: Option<&str>) -> Result<Response> {
    open_dialog(filter_list, default_path, DialogType::SaveFile)
}

pub fn open_dialog(filter_list: Option<&str>, default_path: Option<&str>, dialog_type: DialogType) -> Result<Response> {
    let result;
    let filter_list_cstring;
    let default_path_cstring;

    let filter_list_ptr = match filter_list {
        Some(fl_str) => {
            filter_list_cstring = try!(CString::new(fl_str));
            filter_list_cstring.as_ptr()
        }
        None => std::ptr::null()
    };

    let default_path_ptr = match default_path {
        Some(dp_str) => {
            default_path_cstring = try!(CString::new(dp_str));
            default_path_cstring.as_ptr()
        }
        None => std::ptr::null()
    };

    let mut out_path: *mut c_char = std::ptr::null_mut();
    let ptr_out_path = &mut out_path as *mut *mut c_char;

    let mut out_multiple = nfdpathset_t::default();
    let ptr_out_multiple = &mut out_multiple as *mut nfdpathset_t;

    unsafe {
        result = match dialog_type {
            DialogType::SingleFile => {
                NFD_OpenDialog(filter_list_ptr, default_path_ptr, ptr_out_path)
            },

            DialogType::MultipleFiles => {
                NFD_OpenDialogMultiple(filter_list_ptr, default_path_ptr, ptr_out_multiple)
            },

            DialogType::SaveFile => {
                NFD_SaveDialog(filter_list_ptr, default_path_ptr, ptr_out_path)
            },
        };

        match result {
            nfdresult_t::NFD_OKAY =>{
                if dialog_type == DialogType::MultipleFiles {
                    let count = NFD_PathSet_GetCount(&out_multiple);
                    let mut res = Vec::with_capacity(count);
                    for i in 0..count {
                        let path = CStr::from_ptr(NFD_PathSet_GetPath(&out_multiple, i)).to_string_lossy().into_owned();
                        res.push(path)

                    }

                    NFD_PathSet_Free(ptr_out_multiple);

                    Ok(Response::OkayMultiple(res))
                } else {
                    Ok(Response::Okay(CStr::from_ptr(out_path).to_string_lossy().into_owned()))
                }
            },

            nfdresult_t::NFD_CANCEL => Ok(Response::Cancel),
            nfdresult_t::NFD_ERROR => Err(NFDError::Error(CStr::from_ptr(NFD_GetError()).to_string_lossy().into_owned())),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;
use std::mem;

#[cfg(test)]
extern crate test;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

pub type NodeIdx = usize;

/// Interface required for Triadic Census.
/// Nodes are externally represented by `NodeIdx`.
pub trait DirectedGraph {
    fn node_count(&self) -> NodeIdx;
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool;
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F);
}

fn tricode<G: DirectedGraph>(graph: &G, v: NodeIdx, u: NodeIdx, w: NodeIdx) -> usize {
    let mut tricode = 0;
    if graph.has_edge(v, u) {
        tricode |= 1 << 0;
    }
    if graph.has_edge(u, v) {
        tricode |= 1 << 1;
    }
    if graph.has_edge(v, w) {
        tricode |= 1 << 2;
    }
    if graph.has_edge(w, v) {
        tricode |= 1 << 3;
    }
    if graph.has_edge(u, w) {
        tricode |= 1 << 4;
    }
    if graph.has_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<G: DirectedGraph>(graph: &G) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();

        for v in 0..n {
            let mut neighbors_v = HashSet::new();
            graph.each_undirected_neighbor(v, |u| {
                if u > v {
                    neighbors_v.insert(u);
                }
            });

            for u in neighbors_v {
                let mut s = HashSet::new(); // XXX: Use bitset? // reuse
                graph.each_undirected_neighbor(u, |nu| {
                    s.insert(nu);
                });
                graph.each_undirected_neighbor(v, |nv| {
                    s.insert(nv);
                });
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.has_edge(v, u) && graph.has_edge(u, v) {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for w in s {
                    if u < w ||
                       (v < w && w < u && !(graph.has_edge(v, w) || graph.has_edge(w, v))) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

pub struct SimpleDiGraph {
    g: Graph<(), (), Directed>,
}

impl SimpleDiGraph {
    pub fn new() -> SimpleDiGraph {
        SimpleDiGraph { g: Graph::new() }
    }

    pub fn add_node(&mut self) -> NodeIdx {
        self.g.add_node(()).index()
    }

    pub fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx) {
        self.g.add_edge(NodeIndex::new(src), NodeIndex::new(dst), ());
    }

    pub fn from(num_nodes: usize, edge_list: &[(NodeIdx, NodeIdx)]) -> SimpleDiGraph {
        let mut g = SimpleDiGraph::new();
        for _ in 0..num_nodes {
            let _ = g.add_node();
        }
        for &(src, dst) in edge_list {
            g.add_edge(src, dst);
        }
        g
    }
}

impl DirectedGraph for SimpleDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        self.g.find_edge(NodeIndex::new(src), NodeIndex::new(dst)).is_some()
    }

    #[inline]
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, mut callback: F) {
        for n in self.g.neighbors_undirected(NodeIndex::new(node)) {
            callback(n.index())
        }
    }
}

#[test]
fn test_simple() {
    let mut g = SimpleDiGraph::new();

    let n1 = g.add_node();
    let n2 = g.add_node();
    let n3 = g.add_node();

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3);
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1);
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3);
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let mut prev = g.add_node();
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let first = g.add_node();
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    g.add_edge(prev, first);
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&line_graph(20));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&line_graph(40));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}

#[cfg(test)]
mod example_graphs;

#[bench]
fn bench_erdos_renyi_graph(b: &mut test::Bencher) {
    let g = SimpleDiGraph::from(example_graphs::GRAPH1_NODES, &example_graphs::GRAPH1_EDGES);
    b.iter(|| {
        let _c = TriadicCensus::from_graph(&g);
    });
}
<commit_msg>Slightly improve performance<commit_after>#![feature(test)]
extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;
use std::mem;

#[cfg(test)]
extern crate test;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

pub type NodeIdx = usize;

/// Interface required for Triadic Census.
/// Nodes are externally represented by `NodeIdx`.
pub trait DirectedGraph {
    fn node_count(&self) -> NodeIdx;
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool;
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F);
}

fn tricode<G: DirectedGraph>(graph: &G, v: NodeIdx, u: NodeIdx, w: NodeIdx) -> usize {
    let mut tricode = 0;
    if graph.has_edge(v, u) {
        tricode |= 1 << 0;
    }
    if graph.has_edge(u, v) {
        tricode |= 1 << 1;
    }
    if graph.has_edge(v, w) {
        tricode |= 1 << 2;
    }
    if graph.has_edge(w, v) {
        tricode |= 1 << 3;
    }
    if graph.has_edge(u, w) {
        tricode |= 1 << 4;
    }
    if graph.has_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<G: DirectedGraph>(graph: &G) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();
        let mut neighbors_v = HashSet::new();
        let mut s = HashSet::new(); // XXX: Use bitset? // reuse

        for v in 0..n {
            neighbors_v.clear();
            graph.each_undirected_neighbor(v, |u| {
                if u > v {
                    neighbors_v.insert(u);
                }
            });

            for &u in neighbors_v.iter() {
                s.clear();
                graph.each_undirected_neighbor(u, |nu| {
                    s.insert(nu);
                });
                graph.each_undirected_neighbor(v, |nv| {
                    s.insert(nv);
                });
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.has_edge(v, u) && graph.has_edge(u, v) {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for &w in s.iter() {
                    if u < w ||
                       (v < w && w < u && !(graph.has_edge(v, w) || graph.has_edge(w, v))) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

pub struct SimpleDiGraph {
    g: Graph<(), (), Directed>,
}

impl SimpleDiGraph {
    pub fn new() -> SimpleDiGraph {
        SimpleDiGraph { g: Graph::new() }
    }

    pub fn add_node(&mut self) -> NodeIdx {
        self.g.add_node(()).index()
    }

    pub fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx) {
        self.g.add_edge(NodeIndex::new(src), NodeIndex::new(dst), ());
    }

    pub fn from(num_nodes: usize, edge_list: &[(NodeIdx, NodeIdx)]) -> SimpleDiGraph {
        let mut g = SimpleDiGraph::new();
        for _ in 0..num_nodes {
            let _ = g.add_node();
        }
        for &(src, dst) in edge_list {
            g.add_edge(src, dst);
        }
        g
    }
}

impl DirectedGraph for SimpleDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        self.g.find_edge(NodeIndex::new(src), NodeIndex::new(dst)).is_some()
    }

    #[inline]
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, mut callback: F) {
        for n in self.g.neighbors_undirected(NodeIndex::new(node)) {
            callback(n.index())
        }
    }
}

#[test]
fn test_simple() {
    let mut g = SimpleDiGraph::new();

    let n1 = g.add_node();
    let n2 = g.add_node();
    let n3 = g.add_node();

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3);
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1);
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3);
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let mut prev = g.add_node();
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let first = g.add_node();
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    g.add_edge(prev, first);
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&line_graph(20));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&line_graph(40));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}

#[cfg(test)]
mod example_graphs;

#[bench]
fn bench_erdos_renyi_graph(b: &mut test::Bencher) {
    let g = SimpleDiGraph::from(example_graphs::GRAPH1_NODES, &example_graphs::GRAPH1_EDGES);
    b.iter(|| {
        let _c = TriadicCensus::from_graph(&g);
    });
}
<|endoftext|>


<commit_before>// 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.

//! # LLDB
//!
//! This crate provides a safe binding to the public API for [LLDB], the
//! debugger provided by the [LLVM project]. LLDB provides a modern, high
//! performance debugger framework and is the default debugger for macOS
//! and iOS.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on [crates.io].
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! lldb = "0.0.10"
//! ```
//!
//! ### macOS Installation Notes
//!
//! On macOS, this library relies upon being able to find
//! the `LLDB.framework` that is provided by Xcode.app.
//!
//! In your own application, you will need to configure the
//! `@rpath` for your executable to point to the location
//! of the `LLDB.framework` that you are using. Doing this
//! automatically is not currently supported by Cargo.
//!
//! For testing, you can use the version provided by
//! Xcode.app by setting an environment variable:
//!
//! ```shell
//! export DYLD_FRAMEWORK_PATH=/Applications/Xcode.app/Contents/SharedFrameworks
//! ```
//!
//! ### Linux Installation Notes
//!
//! Install the `lldb` and `lldb-dev` packages for your platform so that
//! you have both LLDB itself installed as well as the headers and
//! other support files required.
//!
//! ### Windows Installation Notes
//!
//! Support for building this has not yet been provided for Windows.
//! Contributions are welcome!
//!
//! ## Usage
//!
//! The primary entry point is [`SBDebugger`]. This will be how you
//! create a debug target and begin the actually interesting stuff.
//!
//! ## Important Classes
//!
//! The LLDB API provides many structs and a wide range of functionality. Some of the
//! most common usages will involve these structs and their corresponding methods:
//!
//! * [`SBDebugger`]: Manages the entire debug experience and creates [`SBTarget`]s.
//! * [`SBTarget`]: The target program running under the debugger.
//! * [`SBProcess`]: The process associated with the target program.
//! * [`SBThread`]: A thread of execution. [`SBProcess`] contains
//!   [`SBThread`]s.
//! * [`SBFrame`]: One of the stack frames associated with
//!   a thread. [`SBThread`] contains [`SBFrame`]s.
//! * [`SBSymbolContext`]: A container that stores various debugger
//!   related info.
//! * [`SBValue`]: The value of a variable, a register, or an
//!   expression.
//! * [`SBModule`]: An executable image and its associated object
//!   and symbol files.  [`SBTarget`] contains [`SBModule`]s.
//! * [`SBBreakpoint`]: A logical breakpoint and its associated
//!   settings. [`SBTarget`] contains [`SBBreakpoint`]s.
//! * [`SBSymbol`]: The symbol possibly associated with a stack frame.
//! * [`SBCompileUnit`]: A compilation unit, or compiled source file.
//! * [`SBFunction`]: A generic function, which can be inlined or not.
//! * [`SBBlock`]: A lexical block. [`SBFunction`] contains [`SBBlock`]s.
//! * [`SBLineEntry`]: Specifies an association with a contiguous range of
//!   instructions and a source file location. [`SBCompileUnit`] contains
//!   [`SBLineEntry`]s.
//!
//! ## Support and Maintenance
//!
//! I am developing this library largely on my own so far. I am able
//! to offer support and maintenance, but would very much appreciate
//! donations via [Patreon](https://patreon.com/endoli). I can also
//! provide commercial support, so feel free to
//! [contact me](mailto:bruce.mitchener@gmail.com).
//!
//! [LLDB]: https://lldb.llvm.org/
//! [LLVM project]: https://llvm.org/
//! [crates.io]: https://crates.io/crates/lldb

#![allow(clippy::upper_case_acronyms)]
#![warn(missing_docs)]
#![deny(
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

extern crate lldb_sys as sys;

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

pub use crate::sys::{lldb_addr_t, lldb_offset_t, lldb_pid_t, lldb_tid_t, lldb_user_id_t};

pub use crate::sys::{
    AccessType, BasicType, BreakpointEventType, ByteOrder, CommandArgumentType, CommandFlags,
    ConnectionStatus, DescriptionLevel, DynamicValueType, EmulateInstructionOptions, Encoding,
    ErrorType, ExpressionEvaluationPhase, ExpressionResults, FilePermissions, Format,
    FrameComparison, FunctionNameType, GdbSignal, InputReaderAction, InputReaderGranularity,
    InstrumentationRuntimeType, LanguageType, LaunchFlags, MatchType, MemberFunctionKind, PathType,
    Permissions, QueueItemKind, QueueKind, RegisterKind, ReturnStatus, RunMode, ScriptLanguage,
    SectionType, StateType, StopReason, SymbolContextItem, SymbolType, TemplateArgumentKind,
    TypeClass, TypeFlags, TypeOptions, TypeSummaryCapping, ValueType, WatchpointEventType,
    WatchpointKind,
};

mod address;
mod attachinfo;
mod block;
mod breakpoint;
mod breakpointlist;
mod breakpointlocation;
mod broadcaster;
mod commandinterpreter;
mod compileunit;
mod data;
mod debugger;
mod error;
mod event;
mod expressionoptions;
mod file;
mod filespec;
mod filespeclist;
mod frame;
mod function;
mod instruction;
mod instructionlist;
mod launchinfo;
mod lineentry;
mod listener;
mod module;
mod modulespec;
mod platform;
mod process;
mod processinfo;
mod queue;
mod queueitem;
mod section;
mod stream;
mod stringlist;
mod structureddata;
mod symbol;
mod symbolcontext;
mod symbolcontextlist;
mod target;
mod thread;
mod typelist;
mod types;
mod value;
mod valuelist;
mod variablesoptions;
mod watchpoint;

pub use self::address::SBAddress;
pub use self::attachinfo::SBAttachInfo;
pub use self::block::SBBlock;
pub use self::breakpoint::{SBBreakpoint, SBBreakpointLocationIter};
pub use self::breakpointlist::{SBBreakpointList, SBBreakpointListIter};
pub use self::breakpointlocation::SBBreakpointLocation;
pub use self::broadcaster::SBBroadcaster;
pub use self::commandinterpreter::SBCommandInterpreter;
pub use self::compileunit::SBCompileUnit;
pub use self::data::SBData;
pub use self::debugger::{SBDebugger, SBDebuggerTargetIter};
pub use self::error::SBError;
pub use self::event::SBEvent;
pub use self::expressionoptions::SBExpressionOptions;
pub use self::file::SBFile;
pub use self::filespec::SBFileSpec;
pub use self::filespeclist::{SBFileSpecList, SBFileSpecListIter};
pub use self::frame::SBFrame;
pub use self::function::SBFunction;
pub use self::instruction::SBInstruction;
pub use self::instructionlist::{SBInstructionList, SBInstructionListIter};
pub use self::launchinfo::SBLaunchInfo;
pub use self::lineentry::SBLineEntry;
pub use self::listener::SBListener;
pub use self::module::{SBModule, SBModuleSectionIter};
pub use self::modulespec::SBModuleSpec;
pub use self::platform::SBPlatform;
pub use self::process::{
    SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter, SBProcessQueueIter,
    SBProcessThreadIter,
};
pub use self::processinfo::SBProcessInfo;
pub use self::queue::{SBQueue, SBQueueQueueItemIter, SBQueueThreadIter};
pub use self::queueitem::SBQueueItem;
pub use self::section::{SBSection, SBSectionSubSectionIter};
pub use self::stream::SBStream;
pub use self::stringlist::{SBStringList, SBStringListIter};
pub use self::structureddata::SBStructuredData;
pub use self::symbol::SBSymbol;
pub use self::symbolcontext::SBSymbolContext;
pub use self::symbolcontextlist::SBSymbolContextList;
pub use self::target::{
    SBTarget, SBTargetBreakpointIter, SBTargetEvent, SBTargetEventModuleIter, SBTargetModuleIter,
    SBTargetWatchpointIter,
};
pub use self::thread::{SBThread, SBThreadEvent, SBThreadFrameIter};
pub use self::typelist::{SBTypeList, SBTypeListIter};
pub use self::types::SBType;
pub use self::value::SBValue;
pub use self::valuelist::{SBValueList, SBValueListIter};
pub use self::variablesoptions::SBVariablesOptions;
pub use self::watchpoint::SBWatchpoint;

/// Which syntax should be used in disassembly?
///
/// On x86, there are 2 syntaxes used for disassembly. Other
/// architectures need not be concerned by this and can just
/// use `DisassemblyFlavor::Default` all the time.
#[derive(Clone, Copy, Debug)]
pub enum DisassemblyFlavor {
    /// The primary syntax used by the GNU Assembler and in the
    /// Linux world.
    ///
    /// AT&T syntax:
    ///
    /// * Operations has a suffix, indicating the operand size.
    /// * Prefixes registers with `%` and immediate values with `$`.
    /// * Orders operands with source first, then destination.
    /// * Memory operands are somewhat complicated.
    ///
    /// For example:
    ///
    /// ```asm
    /// movb $0x05, %al
    /// ```
    ///
    /// This syntax is described in detail in [GAS Syntax].
    ///
    /// [GAS Syntax]: https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
    ATT,
    /// The default syntax.
    Default,
    /// The primary syntax used on Windows.
    ///
    /// This differs from AT&T syntax in that:
    ///
    /// * Operations are not suffixed.
    /// * Registers are not prefixed with `%`, immediate values have a suffix.
    /// * Operands are ordered so that the destination is first, then the source.
    ///
    /// For example:
    ///
    /// ```asm
    /// mov al, 05h
    /// ```
    ///
    Intel,
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Re-export `lldb-sys` as `lldb::sys`.<commit_after>// 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.

//! # LLDB
//!
//! This crate provides a safe binding to the public API for [LLDB], the
//! debugger provided by the [LLVM project]. LLDB provides a modern, high
//! performance debugger framework and is the default debugger for macOS
//! and iOS.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on [crates.io].
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! lldb = "0.0.10"
//! ```
//!
//! ### macOS Installation Notes
//!
//! On macOS, this library relies upon being able to find
//! the `LLDB.framework` that is provided by Xcode.app.
//!
//! In your own application, you will need to configure the
//! `@rpath` for your executable to point to the location
//! of the `LLDB.framework` that you are using. Doing this
//! automatically is not currently supported by Cargo.
//!
//! For testing, you can use the version provided by
//! Xcode.app by setting an environment variable:
//!
//! ```shell
//! export DYLD_FRAMEWORK_PATH=/Applications/Xcode.app/Contents/SharedFrameworks
//! ```
//!
//! ### Linux Installation Notes
//!
//! Install the `lldb` and `lldb-dev` packages for your platform so that
//! you have both LLDB itself installed as well as the headers and
//! other support files required.
//!
//! ### Windows Installation Notes
//!
//! Support for building this has not yet been provided for Windows.
//! Contributions are welcome!
//!
//! ## Usage
//!
//! The primary entry point is [`SBDebugger`]. This will be how you
//! create a debug target and begin the actually interesting stuff.
//!
//! ## Important Classes
//!
//! The LLDB API provides many structs and a wide range of functionality. Some of the
//! most common usages will involve these structs and their corresponding methods:
//!
//! * [`SBDebugger`]: Manages the entire debug experience and creates [`SBTarget`]s.
//! * [`SBTarget`]: The target program running under the debugger.
//! * [`SBProcess`]: The process associated with the target program.
//! * [`SBThread`]: A thread of execution. [`SBProcess`] contains
//!   [`SBThread`]s.
//! * [`SBFrame`]: One of the stack frames associated with
//!   a thread. [`SBThread`] contains [`SBFrame`]s.
//! * [`SBSymbolContext`]: A container that stores various debugger
//!   related info.
//! * [`SBValue`]: The value of a variable, a register, or an
//!   expression.
//! * [`SBModule`]: An executable image and its associated object
//!   and symbol files.  [`SBTarget`] contains [`SBModule`]s.
//! * [`SBBreakpoint`]: A logical breakpoint and its associated
//!   settings. [`SBTarget`] contains [`SBBreakpoint`]s.
//! * [`SBSymbol`]: The symbol possibly associated with a stack frame.
//! * [`SBCompileUnit`]: A compilation unit, or compiled source file.
//! * [`SBFunction`]: A generic function, which can be inlined or not.
//! * [`SBBlock`]: A lexical block. [`SBFunction`] contains [`SBBlock`]s.
//! * [`SBLineEntry`]: Specifies an association with a contiguous range of
//!   instructions and a source file location. [`SBCompileUnit`] contains
//!   [`SBLineEntry`]s.
//!
//! ## Support and Maintenance
//!
//! I am developing this library largely on my own so far. I am able
//! to offer support and maintenance, but would very much appreciate
//! donations via [Patreon](https://patreon.com/endoli). I can also
//! provide commercial support, so feel free to
//! [contact me](mailto:bruce.mitchener@gmail.com).
//!
//! [LLDB]: https://lldb.llvm.org/
//! [LLVM project]: https://llvm.org/
//! [crates.io]: https://crates.io/crates/lldb

#![allow(clippy::upper_case_acronyms)]
#![warn(missing_docs)]
#![deny(
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

// Re-export of `lldb-sys` in the event that access to the same version
// as used by this crate is needed. In general, it is preferable to add
// bindings for missing functionality to this crate.
pub extern crate lldb_sys as sys;

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

pub use crate::sys::{lldb_addr_t, lldb_offset_t, lldb_pid_t, lldb_tid_t, lldb_user_id_t};

pub use crate::sys::{
    AccessType, BasicType, BreakpointEventType, ByteOrder, CommandArgumentType, CommandFlags,
    ConnectionStatus, DescriptionLevel, DynamicValueType, EmulateInstructionOptions, Encoding,
    ErrorType, ExpressionEvaluationPhase, ExpressionResults, FilePermissions, Format,
    FrameComparison, FunctionNameType, GdbSignal, InputReaderAction, InputReaderGranularity,
    InstrumentationRuntimeType, LanguageType, LaunchFlags, MatchType, MemberFunctionKind, PathType,
    Permissions, QueueItemKind, QueueKind, RegisterKind, ReturnStatus, RunMode, ScriptLanguage,
    SectionType, StateType, StopReason, SymbolContextItem, SymbolType, TemplateArgumentKind,
    TypeClass, TypeFlags, TypeOptions, TypeSummaryCapping, ValueType, WatchpointEventType,
    WatchpointKind,
};

mod address;
mod attachinfo;
mod block;
mod breakpoint;
mod breakpointlist;
mod breakpointlocation;
mod broadcaster;
mod commandinterpreter;
mod compileunit;
mod data;
mod debugger;
mod error;
mod event;
mod expressionoptions;
mod file;
mod filespec;
mod filespeclist;
mod frame;
mod function;
mod instruction;
mod instructionlist;
mod launchinfo;
mod lineentry;
mod listener;
mod module;
mod modulespec;
mod platform;
mod process;
mod processinfo;
mod queue;
mod queueitem;
mod section;
mod stream;
mod stringlist;
mod structureddata;
mod symbol;
mod symbolcontext;
mod symbolcontextlist;
mod target;
mod thread;
mod typelist;
mod types;
mod value;
mod valuelist;
mod variablesoptions;
mod watchpoint;

pub use self::address::SBAddress;
pub use self::attachinfo::SBAttachInfo;
pub use self::block::SBBlock;
pub use self::breakpoint::{SBBreakpoint, SBBreakpointLocationIter};
pub use self::breakpointlist::{SBBreakpointList, SBBreakpointListIter};
pub use self::breakpointlocation::SBBreakpointLocation;
pub use self::broadcaster::SBBroadcaster;
pub use self::commandinterpreter::SBCommandInterpreter;
pub use self::compileunit::SBCompileUnit;
pub use self::data::SBData;
pub use self::debugger::{SBDebugger, SBDebuggerTargetIter};
pub use self::error::SBError;
pub use self::event::SBEvent;
pub use self::expressionoptions::SBExpressionOptions;
pub use self::file::SBFile;
pub use self::filespec::SBFileSpec;
pub use self::filespeclist::{SBFileSpecList, SBFileSpecListIter};
pub use self::frame::SBFrame;
pub use self::function::SBFunction;
pub use self::instruction::SBInstruction;
pub use self::instructionlist::{SBInstructionList, SBInstructionListIter};
pub use self::launchinfo::SBLaunchInfo;
pub use self::lineentry::SBLineEntry;
pub use self::listener::SBListener;
pub use self::module::{SBModule, SBModuleSectionIter};
pub use self::modulespec::SBModuleSpec;
pub use self::platform::SBPlatform;
pub use self::process::{
    SBProcess, SBProcessEvent, SBProcessEventRestartedReasonIter, SBProcessQueueIter,
    SBProcessThreadIter,
};
pub use self::processinfo::SBProcessInfo;
pub use self::queue::{SBQueue, SBQueueQueueItemIter, SBQueueThreadIter};
pub use self::queueitem::SBQueueItem;
pub use self::section::{SBSection, SBSectionSubSectionIter};
pub use self::stream::SBStream;
pub use self::stringlist::{SBStringList, SBStringListIter};
pub use self::structureddata::SBStructuredData;
pub use self::symbol::SBSymbol;
pub use self::symbolcontext::SBSymbolContext;
pub use self::symbolcontextlist::SBSymbolContextList;
pub use self::target::{
    SBTarget, SBTargetBreakpointIter, SBTargetEvent, SBTargetEventModuleIter, SBTargetModuleIter,
    SBTargetWatchpointIter,
};
pub use self::thread::{SBThread, SBThreadEvent, SBThreadFrameIter};
pub use self::typelist::{SBTypeList, SBTypeListIter};
pub use self::types::SBType;
pub use self::value::SBValue;
pub use self::valuelist::{SBValueList, SBValueListIter};
pub use self::variablesoptions::SBVariablesOptions;
pub use self::watchpoint::SBWatchpoint;

/// Which syntax should be used in disassembly?
///
/// On x86, there are 2 syntaxes used for disassembly. Other
/// architectures need not be concerned by this and can just
/// use `DisassemblyFlavor::Default` all the time.
#[derive(Clone, Copy, Debug)]
pub enum DisassemblyFlavor {
    /// The primary syntax used by the GNU Assembler and in the
    /// Linux world.
    ///
    /// AT&T syntax:
    ///
    /// * Operations has a suffix, indicating the operand size.
    /// * Prefixes registers with `%` and immediate values with `$`.
    /// * Orders operands with source first, then destination.
    /// * Memory operands are somewhat complicated.
    ///
    /// For example:
    ///
    /// ```asm
    /// movb $0x05, %al
    /// ```
    ///
    /// This syntax is described in detail in [GAS Syntax].
    ///
    /// [GAS Syntax]: https://en.wikibooks.org/wiki/X86_Assembly/GAS_Syntax
    ATT,
    /// The default syntax.
    Default,
    /// The primary syntax used on Windows.
    ///
    /// This differs from AT&T syntax in that:
    ///
    /// * Operations are not suffixed.
    /// * Registers are not prefixed with `%`, immediate values have a suffix.
    /// * Operands are ordered so that the destination is first, then the source.
    ///
    /// For example:
    ///
    /// ```asm
    /// mov al, 05h
    /// ```
    ///
    Intel,
}

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


<commit_before>//! [Experimental] Generic programming with SIMD

#![cfg_attr(test, feature(test))]
#![cfg_attr(test, plugin(quickcheck_macros))]
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(core)]
#![feature(plugin)]
#![feature(simd)]

#[cfg(test)] extern crate "test" as stdtest;
#[cfg(test)] extern crate approx;
#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate rand;

use traits::Simd;

#[cfg(test)]
mod test;
#[cfg(test)]
mod bench;

mod f32;
mod f64;

pub mod traits;

#[allow(missing_docs, non_camel_case_types)]
#[derive(Copy, Debug)]
#[simd]
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);

#[allow(missing_docs, non_camel_case_types)]
#[derive(Copy, Debug)]
#[simd]
pub struct f64x2(pub f64, pub f64);

/// Sum the elements of a slice using SIMD ops
///
/// # Benchmarks
///
/// Size: 1 million elements
///
/// ``` ignore
/// test bench::f32::plain::sum ... bench:    962914 ns/iter (+/- 64354)
/// test bench::f32::simd::sum  ... bench:    242686 ns/iter (+/- 11847)
/// test bench::f64::plain::sum ... bench:    995390 ns/iter (+/- 27834)
/// test bench::f64::simd::sum  ... bench:    504943 ns/iter (+/- 22928)
/// ```
pub fn sum<T: Simd>(slice: &[T]) -> T {
    use std::ops::Add;

    use traits::Vector;

    let (head, body, tail) = <T::Vector as Vector>::cast(slice);
    let sum = body.iter().map(|&x| x).fold(<T::Vector as Vector>::zeroed(), Add::add).sum();
    let sum = head.iter().map(|&x| x).fold(sum, Add::add);
    tail.iter().map(|&x| x).fold(sum, Add::add)
}

/// "Casts" a `&[A]` into an aligned `&[B]`, the elements (both in the front and in the back) that
/// don't fit in the aligned slice, will be returned as slices.
unsafe fn cast<'a, A, B>(slice: &'a [A]) -> (&'a [A], &'a [B], &'a [A]) {
    use std::raw::Repr;
    use std::{raw, mem};

    /// Rounds down `n` to the nearest multiple of `k`
    fn round_down(n: usize, k: usize) -> usize {
        n - n % k
    }

    /// Rounds up `n` to the nearest multiple of `k`
    fn round_up(n: usize, k: usize) -> usize {
        let r = n % k;

        if r == 0 {
            n
        } else {
            n + k - r
        }
    }

    let align_of_b = mem::align_of::<B>();
    let size_of_a = mem::size_of::<A>();
    let size_of_b = mem::size_of::<B>();

    let raw::Slice { data: start, len } = slice.repr();
    let end = start.offset(len as isize);

    let (head_start, tail_end) = (start as usize, end as usize);

    let body_start = round_up(head_start, align_of_b);
    let body_end = round_down(tail_end, align_of_b);

    if body_start >= body_end {
        (slice, &[], &[])
    } else {
        let head_end = body_start;
        let head_len = (head_end - head_start) / size_of_a;

        let body_len = (body_end - body_start) / size_of_b;

        let tail_start = body_end;
        let tail_len = (tail_end - tail_start) / size_of_a;

        let head = mem::transmute(raw::Slice { data: head_start as *const A, len: head_len });
        let body = mem::transmute(raw::Slice { data: body_start as *const B, len: body_len });
        let tail = mem::transmute(raw::Slice { data: tail_start as *const A, len: tail_len });

        (head, body, tail)
    }
}
<commit_msg>refactor: move all bounds to where clauses<commit_after>//! [Experimental] Generic programming with SIMD

#![cfg_attr(test, feature(test))]
#![cfg_attr(test, plugin(quickcheck_macros))]
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(core)]
#![feature(plugin)]
#![feature(simd)]

#[cfg(test)] extern crate "test" as stdtest;
#[cfg(test)] extern crate approx;
#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate rand;

use traits::Simd;

#[cfg(test)]
mod test;
#[cfg(test)]
mod bench;

mod f32;
mod f64;

pub mod traits;

#[allow(missing_docs, non_camel_case_types)]
#[derive(Copy, Debug)]
#[simd]
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);

#[allow(missing_docs, non_camel_case_types)]
#[derive(Copy, Debug)]
#[simd]
pub struct f64x2(pub f64, pub f64);

/// Sum the elements of a slice using SIMD ops
///
/// # Benchmarks
///
/// Size: 1 million elements
///
/// ``` ignore
/// test bench::f32::plain::sum ... bench:    962914 ns/iter (+/- 64354)
/// test bench::f32::simd::sum  ... bench:    242686 ns/iter (+/- 11847)
/// test bench::f64::plain::sum ... bench:    995390 ns/iter (+/- 27834)
/// test bench::f64::simd::sum  ... bench:    504943 ns/iter (+/- 22928)
/// ```
pub fn sum<T>(slice: &[T]) -> T where
    T: Simd,
{
    use std::ops::Add;

    use traits::Vector;

    let (head, body, tail) = <T::Vector as Vector>::cast(slice);
    let sum = body.iter().map(|&x| x).fold(<T::Vector as Vector>::zeroed(), Add::add).sum();
    let sum = head.iter().map(|&x| x).fold(sum, Add::add);
    tail.iter().map(|&x| x).fold(sum, Add::add)
}

/// "Casts" a `&[A]` into an aligned `&[B]`, the elements (both in the front and in the back) that
/// don't fit in the aligned slice, will be returned as slices.
unsafe fn cast<'a, A, B>(slice: &'a [A]) -> (&'a [A], &'a [B], &'a [A]) {
    use std::raw::Repr;
    use std::{raw, mem};

    /// Rounds down `n` to the nearest multiple of `k`
    fn round_down(n: usize, k: usize) -> usize {
        n - n % k
    }

    /// Rounds up `n` to the nearest multiple of `k`
    fn round_up(n: usize, k: usize) -> usize {
        let r = n % k;

        if r == 0 {
            n
        } else {
            n + k - r
        }
    }

    let align_of_b = mem::align_of::<B>();
    let size_of_a = mem::size_of::<A>();
    let size_of_b = mem::size_of::<B>();

    let raw::Slice { data: start, len } = slice.repr();
    let end = start.offset(len as isize);

    let (head_start, tail_end) = (start as usize, end as usize);

    let body_start = round_up(head_start, align_of_b);
    let body_end = round_down(tail_end, align_of_b);

    if body_start >= body_end {
        (slice, &[], &[])
    } else {
        let head_end = body_start;
        let head_len = (head_end - head_start) / size_of_a;

        let body_len = (body_end - body_start) / size_of_b;

        let tail_start = body_end;
        let tail_len = (tail_end - tail_start) / size_of_a;

        let head = mem::transmute(raw::Slice { data: head_start as *const A, len: head_len });
        let body = mem::transmute(raw::Slice { data: body_start as *const B, len: body_len });
        let tail = mem::transmute(raw::Slice { data: tail_start as *const A, len: tail_len });

        (head, body, tail)
    }
}
<|endoftext|>