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

//! # Disassemble
//!
//! This crate provides basic functionality for working with
//! disassembled code. It provides (or will provide) functionality
//! for performing:
//!
//! * Working with code that has already been compiled to machine
//!   code for any CPU, bytecode, compiler IR or JIT compiler
//!   output like that of V8 or the JVM. You provide an adapter
//!   to teach [`Instruction`] how to report the correct information
//!   for your generated code.
//! * Reconstructing the [control flow graph] from a body of compiled
//!   code.
//! * **(Future)** Reconstructing loops and higher level control
//!   flow constructs.
//! * **(Future)** Performing [data flow analysis].
//! * **(Future)** Generating HTML and other rich output formats
//!   to assist in visualizing structure and higher level presentations
//!   of the data derived from the generated code.
//! * **(Future)** Writing decompilers that generate C or
//!   other languages from lower level generated code.
//! * **(Future)** Writing tools for reverse engineering. Many tools
//!   for reverse engineering require extracting and inferring higher
//!   level structure from the low level generated code. This crate
//!   provides those capabilities for re-use by anyone.
//! * **(Future)** Writing views that display disassembled code for
//!   debuggers, profilers and other systems level tools.
//!
//! The actual disassembly with the implementation of [`Instruction`]
//! and other elements of the system will be provided by other
//! crates that integrate with other systems, such as the [Capstone
//! Engine]. This crate is written such that it should work with
//! nearly any machine code, VM bytecode or JIT compiler output,
//! given an appropriate implementation of [`Instruction`].
//!
//! It is possible (likely?) that some functionality from within
//! this crate may move in the future to a separate crate for broader
//! re-use. This might impact [`Symbol`] among other things.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on
//! [crates.io](https://crates.io/crates/disassemble).
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! [dependencies]
//! disassemble = "0.0.1"
//! ```
//!
//! Then, let `rustc` know that you're going to use this crate at the
//! top of your own crate:
//!
//! ```
//! extern crate disassemble;
//! # fn main() {}
//! ```
//!
//! ## Future Directions
//!
//! In the future, we want to extend this library to support a number of
//! additional features:
//!
//! * Implement DOT output for the [`ControlFlowGraph`]. This can probably be done with the
//!   help of [`petgraph`].
//! * HTML output modes?
//! * Implement loop finding. (Havlak)
//! * Implement the [Capstone Engine] backend as a separate crate.
//! * Make [`Instruction`] aware of operands, registers
//! * Data flow support. Memory SSA?
//! * Should we deal with mangled symbols at this level?
//! * So much more!
//!
//! ## Contributions
//!
//! Contributions are welcome.
//!
//! [Capstone Engine]: http://www.capstone-engine.org/
//! [`ControlFlowGraph`]: struct.ControlFlowGraph.html
//! [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
//! [data flow analysis]: https://en.wikipedia.org/wiki/Data-flow_analysis
//! [`Function`]: struct.Function.html
//! [`Instruction`]: trait.Instruction.html
//! [`petgraph`]: https://crates.io/crates/petgraph
//! [`Symbol`]: struct.Symbol.html

#![warn(missing_docs)]
#![deny(trivial_numeric_casts,
        unsafe_code, unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate petgraph;

#[cfg(feature = "capstone")]
extern crate capstone_rust;

#[cfg(feature = "webassembly")]
extern crate parity_wasm;

mod address;
mod basicblock;
mod callgraphanalysis;
#[cfg(feature = "capstone")]
mod capstone;
mod cfg;
mod function;
mod instruction;
mod loops;
mod memory;
mod symbol;
#[cfg(feature = "webassembly")]
mod webassembly;

pub use self::address::Address;
pub use self::basicblock::{BasicBlock, BasicBlockEdge, EdgeType};
pub use self::callgraphanalysis::{CallGraphAnalysis, CallSite, CallSiteTarget};
pub use self::cfg::ControlFlowGraph;
pub use self::function::Function;
pub use self::instruction::Instruction;
pub use self::loops::{find_loops, LoopStructureGraph, SimpleLoop};
pub use self::memory::{Error, Memory, Segment};
pub use self::symbol::Symbol;
#[cfg(feature = "webassembly")]
pub use self::webassembly::WasmInstruction;

#[cfg(test)]
mod tests {
    //! Test Instructions
    //!
    //! This provides some test implementations of `Instruction` for
    //! use in testing out this crate without having to hook up to
    //! a real disassembler.

    use address::Address;
    use instruction::Instruction;

    /// Opcodes that we'll use as instructions.
    #[derive(Debug)]
    pub enum Opcode {
        Add,
        CJmp(Address),
        Jmp(Address),
        Call(Address),
        Ret,
    }

    #[derive(Debug)]
    pub struct TestInstruction {
        address: Address,
        opcode: Opcode,
    }

    impl TestInstruction {
        /// Construct a `TestInstruction`.
        pub fn new(address: u64, opcode: Opcode) -> Self {
            TestInstruction {
                address: Address::new(address),
                opcode: opcode,
            }
        }
    }

    impl Instruction for TestInstruction {
        fn address(&self) -> Address {
            self.address
        }

        fn comment(&self) -> Option<String> {
            None
        }

        fn cycle_count(&self) -> Option<u32> {
            None
        }

        fn is_call(&self) -> bool {
            match self.opcode {
                Opcode::Call(..) => true,
                _ => false,
            }
        }

        fn is_local_conditional_jump(&self) -> bool {
            match self.opcode {
                Opcode::CJmp(..) => true,
                _ => false,
            }
        }

        fn is_local_jump(&self) -> bool {
            match self.opcode {
                Opcode::CJmp(..) => true,
                Opcode::Jmp(..) => true,
                _ => false,
            }
        }

        fn is_return(&self) -> bool {
            match self.opcode {
                Opcode::Ret => true,
                _ => false,
            }
        }

        fn target_address(&self) -> Option<Address> {
            match self.opcode {
                Opcode::CJmp(addr) => Some(addr),
                Opcode::Jmp(addr) => Some(addr),
                Opcode::Call(addr) => Some(addr),
                _ => None,
            }
        }
    }
}
<commit_msg>Fix tests: Implement mnemonic on the test instruction.<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.

//! # Disassemble
//!
//! This crate provides basic functionality for working with
//! disassembled code. It provides (or will provide) functionality
//! for performing:
//!
//! * Working with code that has already been compiled to machine
//!   code for any CPU, bytecode, compiler IR or JIT compiler
//!   output like that of V8 or the JVM. You provide an adapter
//!   to teach [`Instruction`] how to report the correct information
//!   for your generated code.
//! * Reconstructing the [control flow graph] from a body of compiled
//!   code.
//! * **(Future)** Reconstructing loops and higher level control
//!   flow constructs.
//! * **(Future)** Performing [data flow analysis].
//! * **(Future)** Generating HTML and other rich output formats
//!   to assist in visualizing structure and higher level presentations
//!   of the data derived from the generated code.
//! * **(Future)** Writing decompilers that generate C or
//!   other languages from lower level generated code.
//! * **(Future)** Writing tools for reverse engineering. Many tools
//!   for reverse engineering require extracting and inferring higher
//!   level structure from the low level generated code. This crate
//!   provides those capabilities for re-use by anyone.
//! * **(Future)** Writing views that display disassembled code for
//!   debuggers, profilers and other systems level tools.
//!
//! The actual disassembly with the implementation of [`Instruction`]
//! and other elements of the system will be provided by other
//! crates that integrate with other systems, such as the [Capstone
//! Engine]. This crate is written such that it should work with
//! nearly any machine code, VM bytecode or JIT compiler output,
//! given an appropriate implementation of [`Instruction`].
//!
//! It is possible (likely?) that some functionality from within
//! this crate may move in the future to a separate crate for broader
//! re-use. This might impact [`Symbol`] among other things.
//!
//! ## Installation
//!
//! This crate works with Cargo and is on
//! [crates.io](https://crates.io/crates/disassemble).
//! Add it to your `Cargo.toml` like so:
//!
//! ```toml
//! [dependencies]
//! disassemble = "0.0.1"
//! ```
//!
//! Then, let `rustc` know that you're going to use this crate at the
//! top of your own crate:
//!
//! ```
//! extern crate disassemble;
//! # fn main() {}
//! ```
//!
//! ## Future Directions
//!
//! In the future, we want to extend this library to support a number of
//! additional features:
//!
//! * Implement DOT output for the [`ControlFlowGraph`]. This can probably be done with the
//!   help of [`petgraph`].
//! * HTML output modes?
//! * Implement loop finding. (Havlak)
//! * Implement the [Capstone Engine] backend as a separate crate.
//! * Make [`Instruction`] aware of operands, registers
//! * Data flow support. Memory SSA?
//! * Should we deal with mangled symbols at this level?
//! * So much more!
//!
//! ## Contributions
//!
//! Contributions are welcome.
//!
//! [Capstone Engine]: http://www.capstone-engine.org/
//! [`ControlFlowGraph`]: struct.ControlFlowGraph.html
//! [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
//! [data flow analysis]: https://en.wikipedia.org/wiki/Data-flow_analysis
//! [`Function`]: struct.Function.html
//! [`Instruction`]: trait.Instruction.html
//! [`petgraph`]: https://crates.io/crates/petgraph
//! [`Symbol`]: struct.Symbol.html

#![warn(missing_docs)]
#![deny(trivial_numeric_casts,
        unsafe_code, unstable_features,
        unused_import_braces, unused_qualifications)]

extern crate petgraph;

#[cfg(feature = "capstone")]
extern crate capstone_rust;

#[cfg(feature = "webassembly")]
extern crate parity_wasm;

mod address;
mod basicblock;
mod callgraphanalysis;
#[cfg(feature = "capstone")]
mod capstone;
mod cfg;
mod function;
mod instruction;
mod loops;
mod memory;
mod symbol;
#[cfg(feature = "webassembly")]
mod webassembly;

pub use self::address::Address;
pub use self::basicblock::{BasicBlock, BasicBlockEdge, EdgeType};
pub use self::callgraphanalysis::{CallGraphAnalysis, CallSite, CallSiteTarget};
pub use self::cfg::ControlFlowGraph;
pub use self::function::Function;
pub use self::instruction::Instruction;
pub use self::loops::{find_loops, LoopStructureGraph, SimpleLoop};
pub use self::memory::{Error, Memory, Segment};
pub use self::symbol::Symbol;
#[cfg(feature = "webassembly")]
pub use self::webassembly::WasmInstruction;

#[cfg(test)]
mod tests {
    //! Test Instructions
    //!
    //! This provides some test implementations of `Instruction` for
    //! use in testing out this crate without having to hook up to
    //! a real disassembler.

    use address::Address;
    use instruction::Instruction;

    /// Opcodes that we'll use as instructions.
    #[derive(Debug)]
    pub enum Opcode {
        Add,
        CJmp(Address),
        Jmp(Address),
        Call(Address),
        Ret,
    }

    #[derive(Debug)]
    pub struct TestInstruction {
        address: Address,
        opcode: Opcode,
    }

    impl TestInstruction {
        /// Construct a `TestInstruction`.
        pub fn new(address: u64, opcode: Opcode) -> Self {
            TestInstruction {
                address: Address::new(address),
                opcode: opcode,
            }
        }
    }

    impl Instruction for TestInstruction {
        fn address(&self) -> Address {
            self.address
        }

        fn comment(&self) -> Option<String> {
            None
        }

        fn mnemonic(&self) -> &str {
            match self.opcode {
                Opcode::Add => "add",
                Opcode::CJmp(..) => "conditional-jump",
                Opcode::Jmp(..) => "jump",
                Opcode::Call(..) => "call",
                Opcode::Ret => "return",
            }
        }

        fn cycle_count(&self) -> Option<u32> {
            None
        }

        fn is_call(&self) -> bool {
            match self.opcode {
                Opcode::Call(..) => true,
                _ => false,
            }
        }

        fn is_local_conditional_jump(&self) -> bool {
            match self.opcode {
                Opcode::CJmp(..) => true,
                _ => false,
            }
        }

        fn is_local_jump(&self) -> bool {
            match self.opcode {
                Opcode::CJmp(..) => true,
                Opcode::Jmp(..) => true,
                _ => false,
            }
        }

        fn is_return(&self) -> bool {
            match self.opcode {
                Opcode::Ret => true,
                _ => false,
            }
        }

        fn target_address(&self) -> Option<Address> {
            match self.opcode {
                Opcode::CJmp(addr) => Some(addr),
                Opcode::Jmp(addr) => Some(addr),
                Opcode::Call(addr) => Some(addr),
                _ => None,
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::c_str::CString;

mod ffi;

#[deriving(Show)]
pub struct CpuInfo {
    num_cores: int,
    num_logical_cpus: int,
    total_logical_cpus: int,
    l1_data_cache: Option<int>,
    l1_instruction_cache: Option<int>,
    l2_cache: Option<int>,
    l3_cache: Option<int>,
}

pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

pub fn version() -> String {
    let version_string = unsafe {
        let ptr = ffi::cpuid_lib_version();
        CString::new(ptr, false)
    };
    version_string.as_str().unwrap().to_string()
}

pub fn error() -> String {
    let error_string = unsafe {
        let ptr = ffi::cpuid_error();
        CString::new(ptr, false)
    };
    error_string.as_str().unwrap().to_string()
}

pub fn identify() -> Result<CpuInfo, String> {
    let mut raw = ffi::cpu_raw_data_t {
        basic_cpuid: [[0, ..ffi::MAX_CPUID_LEVEL], ..4u],
        ext_cpuid: [[0, ..ffi::MAX_EXT_CPUID_LEVEL], ..4u],
        intel_fn4: [[0, ..ffi::MAX_INTELFN4_LEVEL], ..4u],
        intel_fn11: [[0, ..ffi::MAX_INTELFN11_LEVEL], ..4u],
    };
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    // TODO: use raw in the call to cpu_identify
    let mut data = ffi::cpu_id_t {
        vendor_str: [0, ..ffi::VENDOR_STR_MAX],
        brand_str: [0, ..ffi::BRAND_STR_MAX],
        vendor: 0,
        flags: [0u8, ..ffi::CPU_FLAGS_MAX],
        family: 0,
        model: 0,
        stepping: 0,
        ext_family: 0,
        ext_model: 0,
        num_cores: 0,
        num_logical_cpus: 0,
        total_logical_cpus: 0,
        l1_data_cache: 0,
        l1_instruction_cache: 0,
        l2_cache: 0,
        l3_cache: 0,
        l1_assoc: 0,
        l2_assoc: 0,
        l3_assoc: 0,
        l1_cacheline: 0,
        l2_cacheline: 0,
        l3_cacheline: 0,
        cpu_codename: [0, ..64],
        sse_size: 0,
        detection_hints: [0u8, ..ffi::CPU_HINTS_MAX],
    };
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            num_cores: data.num_cores as int,
            num_logical_cpus: data.num_logical_cpus as int,
            total_logical_cpus: data.total_logical_cpus as int,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache as int) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache as int) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache as int) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache as int) } else { None },
        })
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<commit_msg>Bail out early if cpuid_get_raw_data failed.<commit_after>extern crate libc;

use std::c_str::CString;

mod ffi;

#[deriving(Show)]
pub struct CpuInfo {
    num_cores: int,
    num_logical_cpus: int,
    total_logical_cpus: int,
    l1_data_cache: Option<int>,
    l1_instruction_cache: Option<int>,
    l2_cache: Option<int>,
    l3_cache: Option<int>,
}

pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

pub fn version() -> String {
    let version_string = unsafe {
        let ptr = ffi::cpuid_lib_version();
        CString::new(ptr, false)
    };
    version_string.as_str().unwrap().to_string()
}

pub fn error() -> String {
    let error_string = unsafe {
        let ptr = ffi::cpuid_error();
        CString::new(ptr, false)
    };
    error_string.as_str().unwrap().to_string()
}

pub fn identify() -> Result<CpuInfo, String> {
    let mut raw = ffi::cpu_raw_data_t {
        basic_cpuid: [[0, ..ffi::MAX_CPUID_LEVEL], ..4u],
        ext_cpuid: [[0, ..ffi::MAX_EXT_CPUID_LEVEL], ..4u],
        intel_fn4: [[0, ..ffi::MAX_INTELFN4_LEVEL], ..4u],
        intel_fn11: [[0, ..ffi::MAX_INTELFN11_LEVEL], ..4u],
    };
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    if raw_result != 0 {
        return Err(error());
    }
    let mut data = ffi::cpu_id_t {
        vendor_str: [0, ..ffi::VENDOR_STR_MAX],
        brand_str: [0, ..ffi::BRAND_STR_MAX],
        vendor: 0,
        flags: [0u8, ..ffi::CPU_FLAGS_MAX],
        family: 0,
        model: 0,
        stepping: 0,
        ext_family: 0,
        ext_model: 0,
        num_cores: 0,
        num_logical_cpus: 0,
        total_logical_cpus: 0,
        l1_data_cache: 0,
        l1_instruction_cache: 0,
        l2_cache: 0,
        l3_cache: 0,
        l1_assoc: 0,
        l2_assoc: 0,
        l3_assoc: 0,
        l1_cacheline: 0,
        l2_cacheline: 0,
        l3_cacheline: 0,
        cpu_codename: [0, ..64],
        sse_size: 0,
        detection_hints: [0u8, ..ffi::CPU_HINTS_MAX],
    };
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            num_cores: data.num_cores as int,
            num_logical_cpus: data.num_logical_cpus as int,
            total_logical_cpus: data.total_logical_cpus as int,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache as int) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache as int) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache as int) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache as int) } else { None },
        })
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://hyperium.github.io/hyper/")]
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(missing_debug_implementations)]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # Hyper
//!
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper provides both a [Client](client/index.html) and a
//! [Server](server/index.html), along with a
//! [typed Headers system](header/index.html).
extern crate rustc_serialize as serialize;
extern crate time;
#[macro_use] extern crate url;
#[cfg(feature = "openssl")]
extern crate openssl;
#[cfg(feature = "openssl-verify")]
extern crate openssl_verify;
#[cfg(feature = "security-framework")]
extern crate security_framework;
#[cfg(feature = "serde-serialization")]
extern crate serde;
extern crate cookie;
extern crate unicase;
extern crate httparse;
extern crate rotor;
extern crate spmc;
extern crate traitobject;
extern crate typeable;
extern crate vecio;

#[macro_use]
extern crate language_tags;

#[macro_use]
extern crate mime as mime_crate;

#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use url::Url;
pub use client::Client;
pub use error::{Result, Error};
pub use http::{Next, Encoder, Decoder, Control};
pub use header::Headers;
pub use method::Method::{self, Get, Head, Post, Delete};
pub use status::StatusCode::{self, Ok, BadRequest, NotFound};
pub use server::Server;
pub use uri::RequestUri;
pub use version::HttpVersion;
pub use language_tags::LanguageTag;

macro_rules! rotor_try {
    ($e:expr) => ({
        match $e {
            Ok(v) => v,
            Err(e) => return ::rotor::Response::error(e.into())
        }
    });
}

#[cfg(test)]
mod mock;
pub mod client;
pub mod error;
pub mod method;
pub mod header;
mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

/// Re-exporting the mime crate, for convenience.
pub mod mime {
    pub use mime_crate::*;
}

/*
#[allow(unconditional_recursion)]
fn _assert_send<T: Send>() {
    _assert_send::<Client>();
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
    _assert_send::<error::Error>();
}

#[allow(unconditional_recursion)]
fn _assert_sync<T: Sync>() {
    _assert_sync::<Client>();
    _assert_sync::<error::Error>();
}
*/
<commit_msg>fix(lib): make ControlError public<commit_after>#![doc(html_root_url = "https://hyperium.github.io/hyper/")]
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(missing_debug_implementations)]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # Hyper
//!
//! Hyper is a fast, modern HTTP implementation written in and for Rust. It
//! is a low-level typesafe abstraction over raw HTTP, providing an elegant
//! layer over "stringly-typed" HTTP.
//!
//! Hyper provides both a [Client](client/index.html) and a
//! [Server](server/index.html), along with a
//! [typed Headers system](header/index.html).
extern crate rustc_serialize as serialize;
extern crate time;
#[macro_use] extern crate url;
#[cfg(feature = "openssl")]
extern crate openssl;
#[cfg(feature = "openssl-verify")]
extern crate openssl_verify;
#[cfg(feature = "security-framework")]
extern crate security_framework;
#[cfg(feature = "serde-serialization")]
extern crate serde;
extern crate cookie;
extern crate unicase;
extern crate httparse;
extern crate rotor;
extern crate spmc;
extern crate traitobject;
extern crate typeable;
extern crate vecio;

#[macro_use]
extern crate language_tags;

#[macro_use]
extern crate mime as mime_crate;

#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use url::Url;
pub use client::Client;
pub use error::{Result, Error};
pub use http::{Next, Encoder, Decoder, Control, ControlError};
pub use header::Headers;
pub use method::Method::{self, Get, Head, Post, Delete};
pub use status::StatusCode::{self, Ok, BadRequest, NotFound};
pub use server::Server;
pub use uri::RequestUri;
pub use version::HttpVersion;
pub use language_tags::LanguageTag;

macro_rules! rotor_try {
    ($e:expr) => ({
        match $e {
            Ok(v) => v,
            Err(e) => return ::rotor::Response::error(e.into())
        }
    });
}

#[cfg(test)]
mod mock;
pub mod client;
pub mod error;
pub mod method;
pub mod header;
mod http;
pub mod net;
pub mod server;
pub mod status;
pub mod uri;
pub mod version;

/// Re-exporting the mime crate, for convenience.
pub mod mime {
    pub use mime_crate::*;
}

/*
#[allow(unconditional_recursion)]
fn _assert_send<T: Send>() {
    _assert_send::<Client>();
    _assert_send::<client::Request<net::Fresh>>();
    _assert_send::<client::Response>();
    _assert_send::<error::Error>();
}

#[allow(unconditional_recursion)]
fn _assert_sync<T: Sync>() {
    _assert_sync::<Client>();
    _assert_sync::<error::Error>();
}
*/
<|endoftext|>


<commit_before>// Copyright (c) 2016 Daniel Grunwald
//
// 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.

#![cfg_attr(feature="nightly", allow(incomplete_features))]
#![cfg_attr(feature="nightly", feature(
    specialization, // for impl FromPyObject<'s> for Vec<...> (#31844)
))]
#![allow(
    unused_imports, // because some imports are only necessary with python 2.x or 3.x
    clippy::missing_safety_doc,
    clippy::manual_strip,
    clippy::match_like_matches_macro
)]

//! Rust bindings to the Python interpreter.
//!
//! # Ownership and Lifetimes
//! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
//!
//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional
//! references to the same Python object.
//!
//! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects.
//! As a result, this API will allow mutating Python objects even if they are not stored
//! in a mutable Rust variable.
//!
//! The Python interpreter uses a global interpreter lock (GIL)
//! to ensure thread-safety.
//! This API uses a zero-sized `struct Python<'p>` as a token to indicate
//! that a function can assume that the GIL is held.
//!
//! You obtain a `Python` instance by acquiring the GIL,
//! and have to pass it into all operations that call into the Python runtime.
//!
//! # Python 2.7
//! The library will use the python3 bindings by default. To use the python2 bindings
//! you must specific the `python27` feature explicitly in your `Cargo.toml`.
//!
//! ```ignore
//! [dependencies.cpython]
//! version = "*"
//! default-features = false
//! features = ["python27-sys"]
//! ```
//!
//! # Error Handling
//! The vast majority of operations in this library will return `PyResult<...>`.
//! This is an alias for the type `Result<..., PyErr>`.
//!
//! A `PyErr` represents a Python exception. Errors within the rust-cpython library are
//! also exposed as Python exceptions.
//!
//! # Example
//! ```
//! use cpython::{Python, PyDict, PyResult};
//!
//! fn main() {
//!     let gil = Python::acquire_gil();
//!     hello(gil.python()).unwrap();
//! }
//!
//! fn hello(py: Python) -> PyResult<()> {
//!     let sys = py.import("sys")?;
//!     let version: String = sys.get(py, "version")?.extract(py)?;
//!
//!     let locals = PyDict::new(py);
//!     locals.set_item(py, "os", py.import("os")?)?;
//!     let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?;
//!
//!     println!("Hello {}, I'm Python {}", user, version);
//!     Ok(())
//! }
//! ```

use std::{mem, ptr};

#[cfg(feature = "python27-sys")]
pub(crate) use python27_sys as ffi;

#[cfg(feature = "python3-sys")]
pub(crate) use python3_sys as ffi;

pub use ffi::Py_ssize_t;

pub use crate::conversion::{FromPyObject, RefFromPyObject, ToPyObject};
pub use crate::err::{PyErr, PyResult};
pub use crate::objectprotocol::{ObjectProtocol, NumberProtocol};
pub use crate::objects::*;
pub use crate::py_class::CompareOp;
pub use crate::python::{
    PyClone, PyDrop, Python, PythonObject, PythonObjectDowncastError,
    PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject,
};
pub use crate::pythonrun::{prepare_freethreaded_python, GILGuard, GILProtected};
pub use crate::sharedref::{
    PyLeakedRef, PyLeakedRefMut, PySharedRef, PySharedRefCell, UnsafePyLeaked,
};

#[cfg(feature = "python27-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = libc::c_long;

#[cfg(feature = "python3-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = ffi::Py_hash_t;

/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
    ($s: tt) => (
        // TODO: verify that $s is a string literal without nuls
        unsafe {
            std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr() as *const _)
        }
    );
);

// AST coercion macros (https://danielkeep.github.io/tlborm/book/blk-ast-coercion.html)
#[macro_export]
#[doc(hidden)]
macro_rules! py_coerce_expr {
    ($s:expr) => {
        $s
    };
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_coerce_item {
    ($s:item) => {
        $s
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_replace_expr {
    ($_t:tt $sub:expr) => {
        $sub
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_impl_to_py_object_for_python_object {
    ($T: ty) => {
        /// Identity conversion: allows using existing `PyObject` instances where
        /// `T: ToPyObject` is expected.
        impl $crate::ToPyObject for $T {
            type ObjectType = $T;

            #[inline]
            fn to_py_object(&self, py: $crate::Python) -> $T {
                $crate::PyClone::clone_ref(self, py)
            }

            #[inline]
            fn into_py_object(self, _py: $crate::Python) -> $T {
                self
            }

            #[inline]
            fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
            where
                F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R,
            {
                f($crate::PythonObject::as_object(self).as_ptr())
            }
        }
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_impl_from_py_object_for_python_object {
    ($T:ty) => {
        impl<'s> $crate::FromPyObject<'s> for $T {
            #[inline]
            fn extract(py: $crate::Python, obj: &'s $crate::PyObject) -> $crate::PyResult<$T> {
                use $crate::PyClone;
                Ok(obj.clone_ref(py).cast_into::<$T>(py)?)
            }
        }

        impl<'s> $crate::FromPyObject<'s> for &'s $T {
            #[inline]
            fn extract(py: $crate::Python, obj: &'s $crate::PyObject) -> $crate::PyResult<&'s $T> {
                Ok(obj.cast_as::<$T>(py)?)
            }
        }
    };
}

pub mod argparse;
pub mod buffer;
mod conversion;
mod err;
mod function;
mod objectprotocol;
mod objects;
mod python;
mod pythonrun;
//pub mod rustobject;
pub mod py_class;
mod sharedref;

#[cfg(feature = "serde-convert")]
pub mod serde;

/// Private re-exports for macros. Do not use.
#[doc(hidden)]
pub mod _detail {
    pub mod ffi {
        pub use crate::ffi::*;
    }
    pub mod libc {
        pub use libc::{c_char, c_int, c_void};
    }
    pub use crate::err::{from_owned_ptr_or_panic, result_from_owned_ptr};
    pub use crate::function::{
        handle_callback, py_fn_impl, AbortOnDrop, PyObjectCallbackConverter,
        PythonObjectCallbackConverter,
    };
    pub use paste;
}

/// Expands to an `extern "C"` function that allows Python to load
/// the rust code as a Python extension module.
///
/// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)`
///
/// 1. `name`: The module name as a Rust identifier.
/// 2. A lambda of type `Fn(Python, &PyModule) -> PyResult<()>`.
///    This function will be called when the module is imported, and is responsible
///    for adding the module's members.
///
/// For backwards compatibilty with older versions of rust-cpython,
/// two additional name identifiers (for py2 and py3 initializer names)
/// can be provided, but they will be ignored.
///
/// # Example
/// ```
/// use cpython::{Python, PyResult, PyObject, py_module_initializer, py_fn};
///
/// py_module_initializer!(hello, |py, m| {
///     m.add(py, "__doc__", "Module documentation string")?;
///     m.add(py, "run", py_fn!(py, run()))?;
///     Ok(())
/// });
///
/// fn run(py: Python) -> PyResult<PyObject> {
///     println!("Rust says: Hello Python!");
///     Ok(py.None())
/// }
/// # fn main() {}
/// ```
///
/// In your `Cargo.toml`, use the `extension-module` feature for the `cpython` dependency:
/// ```cargo
/// [dependencies.cpython]
/// version = "*"
/// features = ["extension-module"]
/// ```
/// The full example project can be found at:
///   https://github.com/dgrunwald/rust-cpython/tree/master/extensions/hello
///
/// Rust will compile the code into a file named `libhello.so`, but we have to
/// rename the file in order to use it with Python:
///
/// ```bash
/// cp ./target/debug/libhello.so ./hello.so
/// ```
/// (Note: on Mac OS you will have to rename `libhello.dynlib` to `libhello.so`)
///
/// The extension module can then be imported into Python:
///
/// ```python
/// >>> import hello
/// >>> hello.run()
/// Rust says: Hello Python!
/// ```
///
#[macro_export]
#[cfg(feature = "python27-sys")]
macro_rules! py_module_initializer {
    ($name: ident, $( $_py2: ident, $_py3: ident, )? |$py_id: ident, $m_id: ident| $body: tt) => {
        $crate::_detail::paste::item! {
            #[no_mangle]
            #[allow(non_snake_case)]
            pub unsafe extern "C" fn [< init $name >]() {
                // Nest init function so that $body isn't in unsafe context
                fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                    $body
                }
                let name = concat!(stringify!($name), "\0").as_ptr() as *const _;
                $crate::py_module_initializer_impl(name, init)
            }
        }
    };
}

#[doc(hidden)]
#[cfg(feature = "python27-sys")]
pub unsafe fn py_module_initializer_impl(
    name: *const libc::c_char,
    init: fn(Python, &PyModule) -> PyResult<()>,
) {
    let guard = function::AbortOnDrop("py_module_initializer");
    let py = Python::assume_gil_acquired();
    ffi::PyEval_InitThreads();
    let module = ffi::Py_InitModule(name, ptr::null_mut());
    if module.is_null() {
        mem::forget(guard);
        return;
    }

    let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>(py) {
        Ok(m) => m,
        Err(e) => {
            PyErr::from(e).restore(py);
            mem::forget(guard);
            return;
        }
    };
    let ret = match init(py, &module) {
        Ok(()) => (),
        Err(e) => e.restore(py),
    };
    mem::forget(guard);
    ret
}

#[macro_export]
#[cfg(feature = "python3-sys")]
macro_rules! py_module_initializer {
    ($name: ident, $( $_py2: ident, $_py3: ident, )? |$py_id: ident, $m_id: ident| $body: tt) => {
        $crate::_detail::paste::item! {
            #[no_mangle]
            #[allow(non_snake_case)]
            pub unsafe extern "C" fn [< PyInit_ $name >]() -> *mut $crate::_detail::ffi::PyObject {
                // Nest init function so that $body isn't in unsafe context
                fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                    $body
                }
                static mut MODULE_DEF: $crate::_detail::ffi::PyModuleDef =
                    $crate::_detail::ffi::PyModuleDef_INIT;
                // We can't convert &'static str to *const c_char within a static initializer,
                // so we'll do it here in the module initialization:
                MODULE_DEF.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
                $crate::py_module_initializer_impl(&mut MODULE_DEF, init)
            }
        }
    };
}

#[doc(hidden)]
#[cfg(feature = "python3-sys")]
pub unsafe fn py_module_initializer_impl(
    def: *mut ffi::PyModuleDef,
    init: fn(Python, &PyModule) -> PyResult<()>,
) -> *mut ffi::PyObject {
    let guard = function::AbortOnDrop("py_module_initializer");
    let py = Python::assume_gil_acquired();
    ffi::PyEval_InitThreads();
    let module = ffi::PyModule_Create(def);
    if module.is_null() {
        mem::forget(guard);
        return module;
    }

    let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(py) {
        Ok(m) => m,
        Err(e) => {
            PyErr::from(e).restore(py);
            mem::forget(guard);
            return ptr::null_mut();
        }
    };
    let ret = match init(py, &module) {
        Ok(()) => module.into_object().steal_ptr(),
        Err(e) => {
            e.restore(py);
            ptr::null_mut()
        }
    };
    mem::forget(guard);
    ret
}

// Strip 'r#' prefix from stringified raw identifiers.
#[macro_export]
#[doc(hidden)]
macro_rules! strip_raw {
    ($s:expr) => {{
        let s = $s;
        if s.starts_with("r#") {
            &s[2..]
        } else {
            s
        }
    }};
}
<commit_msg>Fix macOS description of the example<commit_after>// Copyright (c) 2016 Daniel Grunwald
//
// 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.

#![cfg_attr(feature="nightly", allow(incomplete_features))]
#![cfg_attr(feature="nightly", feature(
    specialization, // for impl FromPyObject<'s> for Vec<...> (#31844)
))]
#![allow(
    unused_imports, // because some imports are only necessary with python 2.x or 3.x
    clippy::missing_safety_doc,
    clippy::manual_strip,
    clippy::match_like_matches_macro
)]

//! Rust bindings to the Python interpreter.
//!
//! # Ownership and Lifetimes
//! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
//!
//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional
//! references to the same Python object.
//!
//! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects.
//! As a result, this API will allow mutating Python objects even if they are not stored
//! in a mutable Rust variable.
//!
//! The Python interpreter uses a global interpreter lock (GIL)
//! to ensure thread-safety.
//! This API uses a zero-sized `struct Python<'p>` as a token to indicate
//! that a function can assume that the GIL is held.
//!
//! You obtain a `Python` instance by acquiring the GIL,
//! and have to pass it into all operations that call into the Python runtime.
//!
//! # Python 2.7
//! The library will use the python3 bindings by default. To use the python2 bindings
//! you must specific the `python27` feature explicitly in your `Cargo.toml`.
//!
//! ```ignore
//! [dependencies.cpython]
//! version = "*"
//! default-features = false
//! features = ["python27-sys"]
//! ```
//!
//! # Error Handling
//! The vast majority of operations in this library will return `PyResult<...>`.
//! This is an alias for the type `Result<..., PyErr>`.
//!
//! A `PyErr` represents a Python exception. Errors within the rust-cpython library are
//! also exposed as Python exceptions.
//!
//! # Example
//! ```
//! use cpython::{Python, PyDict, PyResult};
//!
//! fn main() {
//!     let gil = Python::acquire_gil();
//!     hello(gil.python()).unwrap();
//! }
//!
//! fn hello(py: Python) -> PyResult<()> {
//!     let sys = py.import("sys")?;
//!     let version: String = sys.get(py, "version")?.extract(py)?;
//!
//!     let locals = PyDict::new(py);
//!     locals.set_item(py, "os", py.import("os")?)?;
//!     let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?;
//!
//!     println!("Hello {}, I'm Python {}", user, version);
//!     Ok(())
//! }
//! ```

use std::{mem, ptr};

#[cfg(feature = "python27-sys")]
pub(crate) use python27_sys as ffi;

#[cfg(feature = "python3-sys")]
pub(crate) use python3_sys as ffi;

pub use ffi::Py_ssize_t;

pub use crate::conversion::{FromPyObject, RefFromPyObject, ToPyObject};
pub use crate::err::{PyErr, PyResult};
pub use crate::objectprotocol::{ObjectProtocol, NumberProtocol};
pub use crate::objects::*;
pub use crate::py_class::CompareOp;
pub use crate::python::{
    PyClone, PyDrop, Python, PythonObject, PythonObjectDowncastError,
    PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject,
};
pub use crate::pythonrun::{prepare_freethreaded_python, GILGuard, GILProtected};
pub use crate::sharedref::{
    PyLeakedRef, PyLeakedRefMut, PySharedRef, PySharedRefCell, UnsafePyLeaked,
};

#[cfg(feature = "python27-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = libc::c_long;

#[cfg(feature = "python3-sys")]
#[allow(non_camel_case_types)]
pub type Py_hash_t = ffi::Py_hash_t;

/// Constructs a `&'static CStr` literal.
macro_rules! cstr(
    ($s: tt) => (
        // TODO: verify that $s is a string literal without nuls
        unsafe {
            std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr() as *const _)
        }
    );
);

// AST coercion macros (https://danielkeep.github.io/tlborm/book/blk-ast-coercion.html)
#[macro_export]
#[doc(hidden)]
macro_rules! py_coerce_expr {
    ($s:expr) => {
        $s
    };
}
#[macro_export]
#[doc(hidden)]
macro_rules! py_coerce_item {
    ($s:item) => {
        $s
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_replace_expr {
    ($_t:tt $sub:expr) => {
        $sub
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_impl_to_py_object_for_python_object {
    ($T: ty) => {
        /// Identity conversion: allows using existing `PyObject` instances where
        /// `T: ToPyObject` is expected.
        impl $crate::ToPyObject for $T {
            type ObjectType = $T;

            #[inline]
            fn to_py_object(&self, py: $crate::Python) -> $T {
                $crate::PyClone::clone_ref(self, py)
            }

            #[inline]
            fn into_py_object(self, _py: $crate::Python) -> $T {
                self
            }

            #[inline]
            fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
            where
                F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R,
            {
                f($crate::PythonObject::as_object(self).as_ptr())
            }
        }
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_impl_from_py_object_for_python_object {
    ($T:ty) => {
        impl<'s> $crate::FromPyObject<'s> for $T {
            #[inline]
            fn extract(py: $crate::Python, obj: &'s $crate::PyObject) -> $crate::PyResult<$T> {
                use $crate::PyClone;
                Ok(obj.clone_ref(py).cast_into::<$T>(py)?)
            }
        }

        impl<'s> $crate::FromPyObject<'s> for &'s $T {
            #[inline]
            fn extract(py: $crate::Python, obj: &'s $crate::PyObject) -> $crate::PyResult<&'s $T> {
                Ok(obj.cast_as::<$T>(py)?)
            }
        }
    };
}

pub mod argparse;
pub mod buffer;
mod conversion;
mod err;
mod function;
mod objectprotocol;
mod objects;
mod python;
mod pythonrun;
//pub mod rustobject;
pub mod py_class;
mod sharedref;

#[cfg(feature = "serde-convert")]
pub mod serde;

/// Private re-exports for macros. Do not use.
#[doc(hidden)]
pub mod _detail {
    pub mod ffi {
        pub use crate::ffi::*;
    }
    pub mod libc {
        pub use libc::{c_char, c_int, c_void};
    }
    pub use crate::err::{from_owned_ptr_or_panic, result_from_owned_ptr};
    pub use crate::function::{
        handle_callback, py_fn_impl, AbortOnDrop, PyObjectCallbackConverter,
        PythonObjectCallbackConverter,
    };
    pub use paste;
}

/// Expands to an `extern "C"` function that allows Python to load
/// the rust code as a Python extension module.
///
/// Macro syntax: `py_module_initializer!($name, |$py, $m| $body)`
///
/// 1. `name`: The module name as a Rust identifier.
/// 2. A lambda of type `Fn(Python, &PyModule) -> PyResult<()>`.
///    This function will be called when the module is imported, and is responsible
///    for adding the module's members.
///
/// For backwards compatibilty with older versions of rust-cpython,
/// two additional name identifiers (for py2 and py3 initializer names)
/// can be provided, but they will be ignored.
///
/// # Example
/// ```
/// use cpython::{Python, PyResult, PyObject, py_module_initializer, py_fn};
///
/// py_module_initializer!(hello, |py, m| {
///     m.add(py, "__doc__", "Module documentation string")?;
///     m.add(py, "run", py_fn!(py, run()))?;
///     Ok(())
/// });
///
/// fn run(py: Python) -> PyResult<PyObject> {
///     println!("Rust says: Hello Python!");
///     Ok(py.None())
/// }
/// # fn main() {}
/// ```
///
/// In your `Cargo.toml`, use the `extension-module` feature for the `cpython` dependency:
/// ```cargo
/// [dependencies.cpython]
/// version = "*"
/// features = ["extension-module"]
/// ```
/// The full example project can be found at:
///   https://github.com/dgrunwald/rust-cpython/tree/master/extensions/hello
///
/// Rust will compile the code into a file named `libhello.so`, but we have to
/// rename the file in order to use it with Python:
///
/// ```bash
/// cp ./target/debug/libhello.so ./hello.so
/// ```
/// (Note: on Mac OS you will have to rename `libhello.dynlib` to `hello.so`)
///
/// The extension module can then be imported into Python:
///
/// ```python
/// >>> import hello
/// >>> hello.run()
/// Rust says: Hello Python!
/// ```
///
#[macro_export]
#[cfg(feature = "python27-sys")]
macro_rules! py_module_initializer {
    ($name: ident, $( $_py2: ident, $_py3: ident, )? |$py_id: ident, $m_id: ident| $body: tt) => {
        $crate::_detail::paste::item! {
            #[no_mangle]
            #[allow(non_snake_case)]
            pub unsafe extern "C" fn [< init $name >]() {
                // Nest init function so that $body isn't in unsafe context
                fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                    $body
                }
                let name = concat!(stringify!($name), "\0").as_ptr() as *const _;
                $crate::py_module_initializer_impl(name, init)
            }
        }
    };
}

#[doc(hidden)]
#[cfg(feature = "python27-sys")]
pub unsafe fn py_module_initializer_impl(
    name: *const libc::c_char,
    init: fn(Python, &PyModule) -> PyResult<()>,
) {
    let guard = function::AbortOnDrop("py_module_initializer");
    let py = Python::assume_gil_acquired();
    ffi::PyEval_InitThreads();
    let module = ffi::Py_InitModule(name, ptr::null_mut());
    if module.is_null() {
        mem::forget(guard);
        return;
    }

    let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>(py) {
        Ok(m) => m,
        Err(e) => {
            PyErr::from(e).restore(py);
            mem::forget(guard);
            return;
        }
    };
    let ret = match init(py, &module) {
        Ok(()) => (),
        Err(e) => e.restore(py),
    };
    mem::forget(guard);
    ret
}

#[macro_export]
#[cfg(feature = "python3-sys")]
macro_rules! py_module_initializer {
    ($name: ident, $( $_py2: ident, $_py3: ident, )? |$py_id: ident, $m_id: ident| $body: tt) => {
        $crate::_detail::paste::item! {
            #[no_mangle]
            #[allow(non_snake_case)]
            pub unsafe extern "C" fn [< PyInit_ $name >]() -> *mut $crate::_detail::ffi::PyObject {
                // Nest init function so that $body isn't in unsafe context
                fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> {
                    $body
                }
                static mut MODULE_DEF: $crate::_detail::ffi::PyModuleDef =
                    $crate::_detail::ffi::PyModuleDef_INIT;
                // We can't convert &'static str to *const c_char within a static initializer,
                // so we'll do it here in the module initialization:
                MODULE_DEF.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
                $crate::py_module_initializer_impl(&mut MODULE_DEF, init)
            }
        }
    };
}

#[doc(hidden)]
#[cfg(feature = "python3-sys")]
pub unsafe fn py_module_initializer_impl(
    def: *mut ffi::PyModuleDef,
    init: fn(Python, &PyModule) -> PyResult<()>,
) -> *mut ffi::PyObject {
    let guard = function::AbortOnDrop("py_module_initializer");
    let py = Python::assume_gil_acquired();
    ffi::PyEval_InitThreads();
    let module = ffi::PyModule_Create(def);
    if module.is_null() {
        mem::forget(guard);
        return module;
    }

    let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(py) {
        Ok(m) => m,
        Err(e) => {
            PyErr::from(e).restore(py);
            mem::forget(guard);
            return ptr::null_mut();
        }
    };
    let ret = match init(py, &module) {
        Ok(()) => module.into_object().steal_ptr(),
        Err(e) => {
            e.restore(py);
            ptr::null_mut()
        }
    };
    mem::forget(guard);
    ret
}

// Strip 'r#' prefix from stringified raw identifiers.
#[macro_export]
#[doc(hidden)]
macro_rules! strip_raw {
    ($s:expr) => {{
        let s = $s;
        if s.starts_with("r#") {
            &s[2..]
        } else {
            s
        }
    }};
}
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! BitReader is a helper type to extract strings of bits from a slice of bytes.
//!
//! Here is how you read first a single bit, then three bits and finally four bits from a byte
//! buffer:
//!
//! ```
//! use bitreader::BitReader;
//!
//! let slice_of_u8 = &[0b1000_1111];
//! let mut reader = BitReader::new(slice_of_u8);
//!
//! // You probably should use try! or some other error handling mechanism in real code if the
//! // length of the input is not known in advance.
//! let a_single_bit = reader.read_u8(1).unwrap(); // 1
//! let more_bits = reader.read_u8(3).unwrap(); // 0
//! let last_bits_of_byte = reader.read_u8(4).unwrap(); // 0b1111
//! ```
//! You can naturally read bits from longer buffer of data than just a single byte.
//!
//! As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little
//! endian format is assumed when reading the multi-byte values. BitReader supports reading maximum
//! of 64 bits at a time (with read_u64). Reading signed values directly is not supported at the
//! moment.
//!
//! The reads do not need to be aligned in any particular way.
//!
//! Reading zero bits is a no-op.
//!
//! You can also skip over a number of bits, in which case there is no arbitrary small limits like
//! when reading the values to a variable. However, you can not seek past the end of the slice,
//! either when reading or when skipping bits.
//!
//! Note that the code will likely not work correctly if the slice is longer than 2^61 bytes, but
//! exceeding that should be pretty unlikely. Let's get back to this when people read exabytes of
//! information one bit at a time.

use std::fmt;
use std::error::Error;
use std::result;

/// BitReader reads data from a byte slice at the granularity of a single bit.
pub struct BitReader<'a> {
    bytes: &'a [u8],
    /// Position from the start of the slice, counted as bits instead of bytes
    position: u64,
}

impl<'a> BitReader<'a> {
    /// Construct a new BitReader from a byte slice. The returned reader lives at most as long as
    /// the slice given to is valid.
    pub fn new(bytes: &'a [u8]) -> BitReader<'a> {
        BitReader {
            bytes: bytes,
            position: 0
        }
    }

    /// Read at most 8 bits into a u8.
    pub fn read_u8(&mut self, bit_count: u8) -> Result<u8> {
        let value = try!(self.read_value(bit_count, 8));
        Ok((value & 0xff) as u8)
    }

    /// Read at most 16 bits into a u16.
    pub fn read_u16(&mut self, bit_count: u8) -> Result<u16> {
        let value = try!(self.read_value(bit_count, 16));
        Ok((value & 0xffff) as u16)
    }

    /// Read at most 32 bits into a u32.
    pub fn read_u32(&mut self, bit_count: u8) -> Result<u32> {
        let value = try!(self.read_value(bit_count, 32));
        Ok((value & 0xffffffff) as u32)
    }

    /// Read at most 64 bits into a u64.
    pub fn read_u64(&mut self, bit_count: u8) -> Result<u64> {
        let value = try!(self.read_value(bit_count, 64));
        Ok(value)
    }

    /// Skip arbitrary number of bits. However, you can skip at most to the end of the byte slice.
    pub fn skip(&mut self, bit_count: u32) -> Result<()> {
        let end_position = self.position + bit_count as u64;
        if end_position > self.bytes.len() as u64 * 8 {
            return Err(BitReaderError::NotEnoughData);
        }
        self.position = end_position;
        Ok(())
    }

    fn read_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<u64> {
        if bit_count == 0 {
            return Ok(0);
        }
        if bit_count > maximum_count {
            return Err(BitReaderError::TooManyBitsForType);
        }
        let start_position = self.position;
        let end_position = self.position + bit_count as u64;
        if end_position > self.bytes.len() as u64 * 8 {
            return Err(BitReaderError::NotEnoughData);
        }

        let mut value: u64 = 0;

        for i in start_position..end_position {
            let byte_index = (i / 8) as usize;
            let byte = self.bytes[byte_index];
            let shift = 7 - (i % 8);
            let bit = (byte >> shift) as u64 & 1;
            value = (value << 1) | bit;
        }

        self.position = end_position;
        Ok(value)
    }
}

/// Result type for those BitReader operations that can fail.
pub type Result<T> = result::Result<T, BitReaderError>;

/// Error enumeration of BitReader errors.
#[derive(Debug,PartialEq)]
pub enum BitReaderError {
    /// Requested more bits than there are left in the byte slice at the current position.
    NotEnoughData,
    /// Requested more bits than the returned variable can hold, for example more than 8 bits when
    /// reading into a u8.
    TooManyBitsForType
}

impl Error for BitReaderError {
    fn description(&self) -> &str {
        match *self {
            BitReaderError::NotEnoughData => "Requested more bits than the byte slice has left",
            BitReaderError::TooManyBitsForType => "Requested more bits than the requested integer type can hold",
        }
    }
}

impl fmt::Display for BitReaderError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(fmt)
    }
}

#[test]
fn read_buffer() {
    let bytes = &[
        0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
        0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
    ];

    let mut reader = BitReader::new(bytes);

    assert_eq!(reader.read_u8(1).unwrap(), 0b1);
    assert_eq!(reader.read_u8(1).unwrap(), 0b0);
    assert_eq!(reader.read_u8(2).unwrap(), 0b11);

    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);

    assert_eq!(reader.read_u8(3).unwrap(), 0b11);
    assert_eq!(reader.read_u16(10).unwrap(), 0b01_0101_0101);
    assert_eq!(reader.read_u8(3).unwrap(), 0b100);

    assert_eq!(reader.read_u32(32).unwrap(), 0b1001_1001_1001_1001_1001_1001_1001_1001);

    assert_eq!(reader.read_u8(4).unwrap(), 0b1110);
    assert_eq!(reader.read_u8(3).unwrap(), 0b011);
    assert_eq!(reader.read_u8(1).unwrap(), 0b1);
}

#[test]
fn try_all_sizes() {
    let bytes = &[
        0x4a, 0x1e, 0x39, 0xbb, 0xd0, 0x07, 0xca, 0x9a,
        0xa6, 0xba, 0x25, 0x52, 0x6f, 0x0a, 0x6a, 0xba,
    ];

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u64(64).unwrap(), 0x4a1e39bbd007ca9a);
    assert_eq!(reader.read_u64(64).unwrap(), 0xa6ba25526f0a6aba);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u32(32).unwrap(), 0x4a1e39bb);
    assert_eq!(reader.read_u32(32).unwrap(), 0xd007ca9a);
    assert_eq!(reader.read_u32(32).unwrap(), 0xa6ba2552);
    assert_eq!(reader.read_u32(32).unwrap(), 0x6f0a6aba);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u16(16).unwrap(), 0x4a1e);
    assert_eq!(reader.read_u16(16).unwrap(), 0x39bb);
    assert_eq!(reader.read_u16(16).unwrap(), 0xd007);
    assert_eq!(reader.read_u16(16).unwrap(), 0xca9a);
    assert_eq!(reader.read_u16(16).unwrap(), 0xa6ba);
    assert_eq!(reader.read_u16(16).unwrap(), 0x2552);
    assert_eq!(reader.read_u16(16).unwrap(), 0x6f0a);
    assert_eq!(reader.read_u16(16).unwrap(), 0x6aba);

    let mut reader = BitReader::new(&bytes[..]);
    for byte in bytes {
        assert_eq!(reader.read_u8(8).unwrap(), *byte);
    }
}

#[test]
fn skipping_and_zero_reads() {
    let bytes = &[
        0b1011_0101, 0b1110_1010, 0b1010_1100,
    ];

    let mut reader = BitReader::new(bytes);

    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    // Reading zero bits should be a no-op
    assert_eq!(reader.read_u8(0).unwrap(), 0b0);
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
    reader.skip(3).unwrap(); // 0b111
    assert_eq!(reader.read_u16(10).unwrap(), 0b0101010101);
    assert_eq!(reader.read_u8(3).unwrap(), 0b100);
}

#[test]
fn errors() {
    let bytes = &[
        0b1011_0101, 0b1110_1010, 0b1010_1100,
    ];

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    assert_eq!(reader.read_u8(9).unwrap_err(), BitReaderError::TooManyBitsForType);
    // If an error happens, it should be possible to resume as if nothing had happened
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    // Same with this error
    assert_eq!(reader.read_u32(21).unwrap_err(), BitReaderError::NotEnoughData);
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
}
<commit_msg>Add a way to validate the reader state.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! BitReader is a helper type to extract strings of bits from a slice of bytes.
//!
//! Here is how you read first a single bit, then three bits and finally four bits from a byte
//! buffer:
//!
//! ```
//! use bitreader::BitReader;
//!
//! let slice_of_u8 = &[0b1000_1111];
//! let mut reader = BitReader::new(slice_of_u8);
//!
//! // You probably should use try! or some other error handling mechanism in real code if the
//! // length of the input is not known in advance.
//! let a_single_bit = reader.read_u8(1).unwrap(); // 1
//! let more_bits = reader.read_u8(3).unwrap(); // 0
//! let last_bits_of_byte = reader.read_u8(4).unwrap(); // 0b1111
//! ```
//! You can naturally read bits from longer buffer of data than just a single byte.
//!
//! As you read bits, the internal cursor of BitReader moves on along the stream of bits. Little
//! endian format is assumed when reading the multi-byte values. BitReader supports reading maximum
//! of 64 bits at a time (with read_u64). Reading signed values directly is not supported at the
//! moment.
//!
//! The reads do not need to be aligned in any particular way.
//!
//! Reading zero bits is a no-op.
//!
//! You can also skip over a number of bits, in which case there is no arbitrary small limits like
//! when reading the values to a variable. However, you can not seek past the end of the slice,
//! either when reading or when skipping bits.
//!
//! Note that the code will likely not work correctly if the slice is longer than 2^61 bytes, but
//! exceeding that should be pretty unlikely. Let's get back to this when people read exabytes of
//! information one bit at a time.

use std::fmt;
use std::error::Error;
use std::result;

/// BitReader reads data from a byte slice at the granularity of a single bit.
pub struct BitReader<'a> {
    bytes: &'a [u8],
    /// Position from the start of the slice, counted as bits instead of bytes
    position: u64,
}

impl<'a> BitReader<'a> {
    /// Construct a new BitReader from a byte slice. The returned reader lives at most as long as
    /// the slice given to is valid.
    pub fn new(bytes: &'a [u8]) -> BitReader<'a> {
        BitReader {
            bytes: bytes,
            position: 0
        }
    }

    /// Read at most 8 bits into a u8.
    pub fn read_u8(&mut self, bit_count: u8) -> Result<u8> {
        let value = try!(self.read_value(bit_count, 8));
        Ok((value & 0xff) as u8)
    }

    /// Read at most 16 bits into a u16.
    pub fn read_u16(&mut self, bit_count: u8) -> Result<u16> {
        let value = try!(self.read_value(bit_count, 16));
        Ok((value & 0xffff) as u16)
    }

    /// Read at most 32 bits into a u32.
    pub fn read_u32(&mut self, bit_count: u8) -> Result<u32> {
        let value = try!(self.read_value(bit_count, 32));
        Ok((value & 0xffffffff) as u32)
    }

    /// Read at most 64 bits into a u64.
    pub fn read_u64(&mut self, bit_count: u8) -> Result<u64> {
        let value = try!(self.read_value(bit_count, 64));
        Ok(value)
    }

    /// Skip arbitrary number of bits. However, you can skip at most to the end of the byte slice.
    pub fn skip(&mut self, bit_count: u32) -> Result<()> {
        let end_position = self.position + bit_count as u64;
        if end_position > self.bytes.len() as u64 * 8 {
            return Err(BitReaderError::NotEnoughData);
        }
        self.position = end_position;
        Ok(())
    }

    /// Helper to make sure the "bit cursor" is exactly at the beginning of a byte, or at specific
    /// multi-byte alignment position.
    ///
    /// For example `reader.is_aligned(1)` returns true if exactly n bytes, or n * 8 bits, has been
    /// read. Similarly, `reader.is_aligned(4)` returns true if exactly n * 32 bits, or n 4-byte
    /// sequences has been read.
    ///
    /// This function can be used to validate the data is being read properly, for example by
    /// adding invocations wrapped into `debug_assert!()` to places where it is known the data
    /// should be n-byte aligned.
    pub fn is_aligned(&self, alignment_bytes: u32) -> bool {
        self.position % (alignment_bytes as u64 * 8) == 0
    }

    fn read_value(&mut self, bit_count: u8, maximum_count: u8) -> Result<u64> {
        if bit_count == 0 {
            return Ok(0);
        }
        if bit_count > maximum_count {
            return Err(BitReaderError::TooManyBitsForType);
        }
        let start_position = self.position;
        let end_position = self.position + bit_count as u64;
        if end_position > self.bytes.len() as u64 * 8 {
            return Err(BitReaderError::NotEnoughData);
        }

        let mut value: u64 = 0;

        for i in start_position..end_position {
            let byte_index = (i / 8) as usize;
            let byte = self.bytes[byte_index];
            let shift = 7 - (i % 8);
            let bit = (byte >> shift) as u64 & 1;
            value = (value << 1) | bit;
        }

        self.position = end_position;
        Ok(value)
    }
}

/// Result type for those BitReader operations that can fail.
pub type Result<T> = result::Result<T, BitReaderError>;

/// Error enumeration of BitReader errors.
#[derive(Debug,PartialEq)]
pub enum BitReaderError {
    /// Requested more bits than there are left in the byte slice at the current position.
    NotEnoughData,
    /// Requested more bits than the returned variable can hold, for example more than 8 bits when
    /// reading into a u8.
    TooManyBitsForType
}

impl Error for BitReaderError {
    fn description(&self) -> &str {
        match *self {
            BitReaderError::NotEnoughData => "Requested more bits than the byte slice has left",
            BitReaderError::TooManyBitsForType => "Requested more bits than the requested integer type can hold",
        }
    }
}

impl fmt::Display for BitReaderError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(fmt)
    }
}

#[test]
fn read_buffer() {
    let bytes = &[
        0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
        0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
    ];

    let mut reader = BitReader::new(bytes);

    assert_eq!(reader.read_u8(1).unwrap(), 0b1);
    assert_eq!(reader.read_u8(1).unwrap(), 0b0);
    assert_eq!(reader.read_u8(2).unwrap(), 0b11);

    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);

    assert!(reader.is_aligned(1));

    assert_eq!(reader.read_u8(3).unwrap(), 0b11);
    assert_eq!(reader.read_u16(10).unwrap(), 0b01_0101_0101);
    assert_eq!(reader.read_u8(3).unwrap(), 0b100);

    assert!(reader.is_aligned(1));

    assert_eq!(reader.read_u32(32).unwrap(), 0b1001_1001_1001_1001_1001_1001_1001_1001);

    assert_eq!(reader.read_u8(4).unwrap(), 0b1110);
    assert_eq!(reader.read_u8(3).unwrap(), 0b011);
    assert_eq!(reader.read_u8(1).unwrap(), 0b1);

    // Could also be 8 at this point!
    assert!(reader.is_aligned(4));
}

#[test]
fn try_all_sizes() {
    let bytes = &[
        0x4a, 0x1e, 0x39, 0xbb, 0xd0, 0x07, 0xca, 0x9a,
        0xa6, 0xba, 0x25, 0x52, 0x6f, 0x0a, 0x6a, 0xba,
    ];

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u64(64).unwrap(), 0x4a1e39bbd007ca9a);
    assert_eq!(reader.read_u64(64).unwrap(), 0xa6ba25526f0a6aba);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u32(32).unwrap(), 0x4a1e39bb);
    assert_eq!(reader.read_u32(32).unwrap(), 0xd007ca9a);
    assert_eq!(reader.read_u32(32).unwrap(), 0xa6ba2552);
    assert_eq!(reader.read_u32(32).unwrap(), 0x6f0a6aba);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u16(16).unwrap(), 0x4a1e);
    assert_eq!(reader.read_u16(16).unwrap(), 0x39bb);
    assert_eq!(reader.read_u16(16).unwrap(), 0xd007);
    assert_eq!(reader.read_u16(16).unwrap(), 0xca9a);
    assert_eq!(reader.read_u16(16).unwrap(), 0xa6ba);
    assert_eq!(reader.read_u16(16).unwrap(), 0x2552);
    assert_eq!(reader.read_u16(16).unwrap(), 0x6f0a);
    assert_eq!(reader.read_u16(16).unwrap(), 0x6aba);

    let mut reader = BitReader::new(&bytes[..]);
    for byte in bytes {
        assert_eq!(reader.read_u8(8).unwrap(), *byte);
    }
}

#[test]
fn skipping_and_zero_reads() {
    let bytes = &[
        0b1011_0101, 0b1110_1010, 0b1010_1100,
    ];

    let mut reader = BitReader::new(bytes);

    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    // Reading zero bits should be a no-op
    assert_eq!(reader.read_u8(0).unwrap(), 0b0);
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
    reader.skip(3).unwrap(); // 0b111
    assert_eq!(reader.read_u16(10).unwrap(), 0b0101010101);
    assert_eq!(reader.read_u8(3).unwrap(), 0b100);
}

#[test]
fn errors() {
    let bytes = &[
        0b1011_0101, 0b1110_1010, 0b1010_1100,
    ];

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    assert_eq!(reader.read_u8(9).unwrap_err(), BitReaderError::TooManyBitsForType);
    // If an error happens, it should be possible to resume as if nothing had happened
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);

    let mut reader = BitReader::new(bytes);
    assert_eq!(reader.read_u8(4).unwrap(), 0b1011);
    // Same with this error
    assert_eq!(reader.read_u32(21).unwrap_err(), BitReaderError::NotEnoughData);
    assert_eq!(reader.read_u8(4).unwrap(), 0b0101);
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Logging macros for the fern library. This package stores a thread-local logger, and allows access to it via log!() and <level>!() macros.
//!
//! Note that in order for logging_macros to function correctly, you can't rename the fern crate (using 'as'), and `fern_macros` needs to be used as plugin and link. Shown here:
//!
//! ```
//! extern crate fern;
//! #[phase(plugin, link)]
//! extern crate fern_macros;
//! ```

extern crate fern;

use std::cell;
use std::sync;
use std::io::stdio;
use fern::Logger;
use fern::Level;
use fern::OutputConfig;

thread_local!(static DEFAULT_LOGGER: cell::RefCell<sync::Arc<Box<Logger + Sync + Send>>> = cell::RefCell::new(sync::Arc::new(OutputConfig::Stdout.into_logger().unwrap())));

#[experimental]
pub fn init_logger(logger: sync::Arc<Box<Logger + Sync + Send>>) {
    DEFAULT_LOGGER.with(move |log| {
        *log.borrow_mut() = logger;
    });
}

#[experimental]
pub fn log(level: &Level, msg: &str) {
    DEFAULT_LOGGER.with(|logger| {
        match logger.borrow().log(level, msg) {
            Ok(()) => (),
            // TODO: Should we store stderr_raw here, or does it not matter, since this is really totally backup.
            Err(e) => match write!(&mut stdio::stderr_raw(), "Error logging {{level: {}, msg: {}}}: {}", level, msg, e) {
                Ok(()) => (),
                Err(e2) => panic!(format!("Backup logging failed after regular logging failed. Original log: {{level: {}, msg: {}}}\nLogging error: {}\nBackup logging error: {}", level, msg, e, e2)),
            }
        };
    });
}

/// Logs a message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! log(
    ($level:expr, $($arg:tt)*) => (
        ::fern_macros::log($level, format!($($arg)*).as_slice())
    )
);

/// Logs a debug message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! debug(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Debug, $($arg)*)
    )
);

/// Logs an informational message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! info(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Info, $($arg)*)
    )
);

/// Logs a warning message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! warning(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Warning, $($arg)*)
    )
);

/// Logs a severe message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! severe(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Severe, $($arg)*)
    )
);

/// Logs an error message with the thread logger, if an error occurs.
///
/// This macro requires a Result<_, Show>, and will log as severe error message with the given argument format if the result happens to end up being Err(e)
#[macro_export]
#[experimental]
macro_rules! log_error(
    ($result:expr, $($arg:tt)*) => (
        match $result {
            Ok(_) => (),
            Err(e) => severe!(format!($($arg)*, e=e)),
        }
    )
);

/// Exactly the same as log_error!(), except also has an 'after' statement which will be run after logging the severe error message.
#[macro_export]
#[experimental]
macro_rules! log_error_then(
    ($result:expr, $after:expr, $($arg:tt)*) => (
        match $result {
            Ok(_) => (),
            Err(e) => {
                severe!($($arg)*, e=e);
                $after;
            },
        }
    )
);
<commit_msg>Didn't mean to change that<commit_after>#![feature(macro_rules)]

//! Logging macros for the fern library. This package stores a thread-local logger, and allows access to it via log!() and <level>!() macros.
//!
//! Note that in order for logging_macros to function correctly, you can't rename the fern crate (using 'as'), and `fern_macros` needs to be used as plugin and link. Shown here:
//!
//! ```
//! extern crate fern;
//! #[phase(plugin, link)]
//! extern crate fern_macros;
//! ```

extern crate fern;

use std::cell;
use std::sync;
use std::io::stdio;
use fern::Logger;
use fern::Level;
use fern::OutputConfig;

thread_local!(static DEFAULT_LOGGER: cell::RefCell<sync::Arc<Box<Logger + Sync + Send>>> = cell::RefCell::new(sync::Arc::new(OutputConfig::Stdout.into_logger().unwrap())));

#[experimental]
pub fn init_thread_logger(logger: sync::Arc<Box<Logger + Sync + Send>>) {
    DEFAULT_LOGGER.with(move |log| {
        *log.borrow_mut() = logger;
    });
}

#[experimental]
pub fn log(level: &Level, msg: &str) {
    DEFAULT_LOGGER.with(|logger| {
        match logger.borrow().log(level, msg) {
            Ok(()) => (),
            // TODO: Should we store stderr_raw here, or does it not matter, since this is really totally backup.
            Err(e) => match write!(&mut stdio::stderr_raw(), "Error logging {{level: {}, msg: {}}}: {}", level, msg, e) {
                Ok(()) => (),
                Err(e2) => panic!(format!("Backup logging failed after regular logging failed. Original log: {{level: {}, msg: {}}}\nLogging error: {}\nBackup logging error: {}", level, msg, e, e2)),
            }
        };
    });
}

/// Logs a message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! log(
    ($level:expr, $($arg:tt)*) => (
        ::fern_macros::log($level, format!($($arg)*).as_slice())
    )
);

/// Logs a debug message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! debug(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Debug, $($arg)*)
    )
);

/// Logs an informational message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! info(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Info, $($arg)*)
    )
);

/// Logs a warning message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! warning(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Warning, $($arg)*)
    )
);

/// Logs a severe message with the thread logger.
#[macro_export]
#[experimental]
macro_rules! severe(
    ($($arg:tt)*) => (
        log!(&::fern::Level::Severe, $($arg)*)
    )
);

/// Logs an error message with the thread logger, if an error occurs.
///
/// This macro requires a Result<_, Show>, and will log as severe error message with the given argument format if the result happens to end up being Err(e)
#[macro_export]
#[experimental]
macro_rules! log_error(
    ($result:expr, $($arg:tt)*) => (
        match $result {
            Ok(_) => (),
            Err(e) => severe!(format!($($arg)*, e=e)),
        }
    )
);

/// Exactly the same as log_error!(), except also has an 'after' statement which will be run after logging the severe error message.
#[macro_export]
#[experimental]
macro_rules! log_error_then(
    ($result:expr, $after:expr, $($arg:tt)*) => (
        match $result {
            Ok(_) => (),
            Err(e) => {
                severe!($($arg)*, e=e);
                $after;
            },
        }
    )
);
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop,
    EndLoop,
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32),
    EndIf,
}

pub fn parse(code: &str) -> Vec<Token> {
    let mut tokens = Vec::new();
    for i in code.chars() {
        match i {
            '+' => tokens.push(Token::Add(0, 1)),
            '-' => tokens.push(Token::Add(0, -1)),
            '>' => tokens.push(Token::Move(1)),
            '<' => tokens.push(Token::Move(-1)),
            '[' => tokens.push(Token::Loop),
            ']' => tokens.push(Token::EndLoop),
            ',' => tokens.push(Token::Input),
            '.' => {
                tokens.push(Token::LoadOut(0, 0));
                tokens.push(Token::Output);
            },
            _ => ()
        };
    }

    tokens
    }

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut newtokens: Vec<Token> = Vec::new();
    let mut shift = 0;
    let mut do_output = false;
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    let mut adds: BTreeMap<i32, i32> = BTreeMap::new();
    let mut sets: BTreeMap<i32, i32> = BTreeMap::new();
    let mut pre_loop_sets: BTreeMap<i32, i32> = BTreeMap::new();

    for token in tokens.iter() {
        let prev_token = match newtokens.last() {
            Some(tok) => Some(*tok),
            None => None
        };
        if *token == Token::EndLoop && prev_token == Some(Token::Loop) && shift == 0 && adds.contains_key(&0) {
            if adds.len() == 1 {
                newtokens.pop(); // Remove Loop
                if !sets.is_empty() {
                    newtokens.push(Token::If(0));
                    for (offset, value) in sets.iter() {
                        newtokens.push(Token::Set(*offset, *value));
                    }
                    sets.clear();
                    newtokens.push(Token::Set(0, 0));
                    newtokens.push(Token::EndIf);
                } else {
                    sets.insert(0, 0);
                }
                pre_loop_sets.clear();
                adds.clear();
                continue
            } else if adds.get(&0) == Some(&-1) {
                newtokens.pop(); // Remove Loop
                if !sets.is_empty() {
                    newtokens.push(Token::If(0));
                    for (offset, value) in sets.iter() {
                        newtokens.push(Token::Set(*offset, *value));
                    }
                }
                for (offset, value) in adds.iter() {
                    if *offset != 0 {
                        let src = 0;
                        let dest = *offset;
                        let mul = *value;
                        if pre_loop_sets.contains_key(&src) {
                            let val = pre_loop_sets.get(&src).unwrap() * mul;
                            newtokens.push(Token::Add(dest, val));
                        } else {
                            newtokens.push(Token::MulCopy(src, dest, mul));
                        }
                    }
                }
                if !sets.is_empty() {
                    newtokens.push(Token::EndIf);
                }
                pre_loop_sets.clear();
                adds.clear();
                sets.clear();
                sets.insert(0, 0);
                continue
            }
        }

        match *token {
            Token::Loop =>
                for (offset, value) in sets.iter() {
                    pre_loop_sets.insert(*offset+shift, *value);
                },
            Token::Set(_, _) | Token::Add(_, _) | Token::Move(_) => {},
            _ => pre_loop_sets.clear()
        }

        match *token {
            Token::Set(_, _) | Token::Add(_, _) | Token::Move(_) | Token::LoadOut(_, _) | Token::LoadOutSet(_) | Token::Output => {},
            _ => {
               if do_output {
                   newtokens.push(Token::Output);
                   do_output = false;
               }

               for (offset, value) in sets.iter() {
                  newtokens.push(Token::Set(*offset, *value));
               }
               for (offset, value) in adds.iter() {
                  newtokens.push(Token::Add(*offset, *value));
               }
               sets.clear();
               adds.clear();
            }
        }

        if shift != 0 {
           match *token {
               Token::Loop | Token::Input | Token::Scan(_) => {
                   newtokens.push(Token::Move(shift));
                   shift = 0;
               },
               _ => {}
           }
        }

        match *token {
            Token::Set(mut offset, val) => {
                offset += shift;
                // Add before Set does nothing; remove it
                if adds.contains_key(&offset) {
                    adds.remove(&offset);
                }
                sets.insert(offset, val);
            },
            Token::Add(mut offset, mut val) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    val = sets.get(&offset).unwrap() + val;
                    sets.insert(offset, val);
                } else {
                    val = adds.get(&offset).unwrap_or(&0) + val;
                    adds.insert(offset, val);
                }
            },
            Token::MulCopy(src, dest, mul) =>
                newtokens.push(Token::MulCopy(src+shift, dest+shift, mul)),
            // XXX Deal with shift in if, if those are ever generated
            Token::If(offset) =>
                newtokens.push(Token::If(offset+shift)),
            Token::Move(offset) =>
                shift += offset,
            Token::Output =>
                do_output = true,
            Token::LoadOut(mut offset, add) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    newtokens.push(Token::LoadOutSet(sets.get(&offset).unwrap() + add));
                } else {
                    newtokens.push(Token::LoadOut(offset, adds.get(&offset).unwrap_or(&0) + add));
                }
            },
            Token::EndLoop =>
                if prev_token == Some(Token::Loop) && shift != 0 && sets.is_empty() && adds.is_empty() {
                    newtokens.pop(); // Remove StartLoop
                    newtokens.push(Token::Scan(shift));
                } else {
                    if shift != 0 {
                        newtokens.push(Token::Move(shift));
                        shift = 0;
                    }
                    newtokens.push(Token::EndLoop);
                },
            Token::EndIf | Token::LoadOutSet(_) | Token::Loop | Token::Input | Token::Scan(_) =>
                newtokens.push(*token),
        }
    }

    // Any remaining add/set/shift is ignored, as it would have no effect
    if do_output {
        newtokens.push(Token::Output);
    }

    // Optimize recursively
    if newtokens != tokens {
        optimize(newtokens)
    } else {
        newtokens
    }
}
<commit_msg>Fix bug in rust optimizer<commit_after>use std::collections::BTreeMap;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Token {
    Output,
    Input,
    Loop,
    EndLoop,
    Move(i32),
    Add(i32, i32),
    Set(i32, i32),
    MulCopy(i32, i32, i32),
    Scan(i32),
    LoadOut(i32, i32),
    LoadOutSet(i32),
    If(i32),
    EndIf,
}

pub fn parse(code: &str) -> Vec<Token> {
    let mut tokens = Vec::new();
    for i in code.chars() {
        match i {
            '+' => tokens.push(Token::Add(0, 1)),
            '-' => tokens.push(Token::Add(0, -1)),
            '>' => tokens.push(Token::Move(1)),
            '<' => tokens.push(Token::Move(-1)),
            '[' => tokens.push(Token::Loop),
            ']' => tokens.push(Token::EndLoop),
            ',' => tokens.push(Token::Input),
            '.' => {
                tokens.push(Token::LoadOut(0, 0));
                tokens.push(Token::Output);
            },
            _ => ()
        };
    }

    tokens
    }

pub fn optimize(tokens: Vec<Token>) -> Vec<Token> {
    let mut newtokens: Vec<Token> = Vec::new();
    let mut shift = 0;
    let mut do_output = false;
    // With HashMap, the order sometimes switches
    // in recursion, and the optimizer never exits.
    let mut adds: BTreeMap<i32, i32> = BTreeMap::new();
    let mut sets: BTreeMap<i32, i32> = BTreeMap::new();
    let mut pre_loop_sets: BTreeMap<i32, i32> = BTreeMap::new();

    for token in tokens.iter() {
        let mut prev_token = match newtokens.last() {
            Some(tok) => Some(*tok),
            None => None
        };
        if *token == Token::EndLoop && prev_token == Some(Token::Loop) && shift == 0 && adds.contains_key(&0) {
            if adds.len() == 1 {
                newtokens.pop(); // Remove Loop
                if !sets.is_empty() {
                    newtokens.push(Token::If(0));
                    for (offset, value) in sets.iter() {
                        newtokens.push(Token::Set(*offset, *value));
                    }
                    sets.clear();
                    newtokens.push(Token::Set(0, 0));
                    newtokens.push(Token::EndIf);
                } else {
                    sets.insert(0, 0);
                }
                pre_loop_sets.clear();
                adds.clear();
                continue
            } else if adds.get(&0) == Some(&-1) {
                newtokens.pop(); // Remove Loop
                if !sets.is_empty() {
                    newtokens.push(Token::If(0));
                    for (offset, value) in sets.iter() {
                        newtokens.push(Token::Set(*offset, *value));
                    }
                }
                for (offset, value) in adds.iter() {
                    if *offset != 0 {
                        let src = 0;
                        let dest = *offset;
                        let mul = *value;
                        if pre_loop_sets.contains_key(&src) {
                            let val = pre_loop_sets.get(&src).unwrap() * mul;
                            newtokens.push(Token::Add(dest, val));
                        } else {
                            newtokens.push(Token::MulCopy(src, dest, mul));
                        }
                    }
                }
                if !sets.is_empty() {
                    newtokens.push(Token::EndIf);
                }
                pre_loop_sets.clear();
                adds.clear();
                sets.clear();
                sets.insert(0, 0);
                continue
            }
        }

        match *token {
            Token::Loop =>
                for (offset, value) in sets.iter() {
                    pre_loop_sets.insert(*offset+shift, *value);
                },
            Token::Set(_, _) | Token::Add(_, _) | Token::Move(_) => {},
            _ => pre_loop_sets.clear()
        }

        match *token {
            Token::Set(_, _) | Token::Add(_, _) | Token::Move(_) | Token::LoadOut(_, _) | Token::LoadOutSet(_) | Token::Output => {},
            _ => {
               if do_output {
                   newtokens.push(Token::Output);
                   do_output = false;
               }

               for (offset, value) in sets.iter() {
                  newtokens.push(Token::Set(*offset, *value));
               }
               for (offset, value) in adds.iter() {
                  newtokens.push(Token::Add(*offset, *value));
               }
               sets.clear();
               adds.clear();
            }
        }

        if shift != 0 {
           match *token {
               Token::Loop | Token::Input | Token::Scan(_) => {
                   newtokens.push(Token::Move(shift));
                   shift = 0;
               },
               _ => {}
           }
        }

        match *token {
            Token::Set(mut offset, val) => {
                offset += shift;
                // Add before Set does nothing; remove it
                if adds.contains_key(&offset) {
                    adds.remove(&offset);
                }
                sets.insert(offset, val);
            },
            Token::Add(mut offset, mut val) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    val = sets.get(&offset).unwrap() + val;
                    sets.insert(offset, val);
                } else {
                    val = adds.get(&offset).unwrap_or(&0) + val;
                    adds.insert(offset, val);
                }
            },
            Token::MulCopy(src, dest, mul) =>
                newtokens.push(Token::MulCopy(src+shift, dest+shift, mul)),
            // XXX Deal with shift in if, if those are ever generated
            Token::If(offset) =>
                newtokens.push(Token::If(offset+shift)),
            Token::Move(offset) =>
                shift += offset,
            Token::Output =>
                do_output = true,
            Token::LoadOut(mut offset, add) => {
                offset += shift;
                if sets.contains_key(&offset) {
                    newtokens.push(Token::LoadOutSet(sets.get(&offset).unwrap() + add));
                } else {
                    newtokens.push(Token::LoadOut(offset, adds.get(&offset).unwrap_or(&0) + add));
                }
            },
            Token::EndLoop => {
                prev_token = match newtokens.last() {
                            Some(tok) => Some(*tok),
                            None => None
                        };
                if prev_token == Some(Token::Loop) && shift != 0 && sets.is_empty() && adds.is_empty() {
                    newtokens.pop(); // Remove StartLoop
                    newtokens.push(Token::Scan(shift));
                } else {
                    if shift != 0 {
                        newtokens.push(Token::Move(shift));
                        shift = 0;
                    }
                    newtokens.push(Token::EndLoop);
                }
            },
            Token::EndIf | Token::LoadOutSet(_) | Token::Loop | Token::Input | Token::Scan(_) =>
                newtokens.push(*token),
        }
    }

    // Any remaining add/set/shift is ignored, as it would have no effect
    if do_output {
        newtokens.push(Token::Output);
    }

    // Optimize recursively
    if newtokens != tokens {
        optimize(newtokens)
    } else {
        newtokens
    }
}
<|endoftext|>