<commit_before>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::RwLock;

use capture;
use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    Sys_VID_FlipScreen: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,
    VideoMode_IsWindowed: Function<unsafe extern "C" fn() -> c_int>,

    window_rect: Option<*mut RECT>,
    s_BackBufferFBO: Option<*mut FBO_Container_t>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct RECT {
    left: c_int,
    right: c_int,
    top: c_int,
    bottom: c_int,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct FBO_Container_t {
    s_hBackBufferFBO: GLuint,
    s_hBackBufferCB: GLuint,
    s_hBackBufferDB: GLuint,
    s_hBackBufferTex: GLuint,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    encode::initialize();

    // Initialize the capturing.
    capture::initialize();

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::ReadPixels::is_loaded() {
        panic!("could not load glReadPixels()");
    }
}

/// Flips the screen.
#[export_name = "_Z18Sys_VID_FlipScreenv"]
pub unsafe extern "C" fn Sys_VID_FlipScreen() {
    if capture::is_capturing() {
        let (w, h) = get_resolution();
        let mut buf = capture::get_buffer((w, h));

        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGB, gl::UNSIGNED_BYTE,
                       buf.data.as_mut_ptr() as _);

        capture::capture(buf);
    }

    real!(Sys_VID_FlipScreen)();

    // TODO: check if we're called from SCR_UpdateScreen().

    // println!("s_BackBufferFBO: {:?}", *POINTERS.read().unwrap().s_BackBufferFBO.unwrap());
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, Sys_VID_FlipScreen, "_Z18Sys_VID_FlipScreenv");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");
        find!(pointers, hw, VideoMode_IsWindowed, "VideoMode_IsWindowed");

        pointers.window_rect = Some(hw.sym("window_rect")
                .chain_err(|| "couldn't find window_rect")? as _);
        pointers.s_BackBufferFBO = Some(hw.sym("s_BackBufferFBO")
                .chain_err(|| "couldn't find s_BackBufferFBO")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width;
    let mut height;

    if real!(VideoMode_IsWindowed)() != 0 {
        let window_rect = *POINTERS.read().unwrap().window_rect.unwrap();
        width = window_rect.right - window_rect.left;
        height = window_rect.bottom - window_rect.top;
    } else {
        width = mem::uninitialized();
        height = mem::uninitialized();
        real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());
    }

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<commit_msg>Fixed incorrect pixel output on weird resolutions<commit_after>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

use error_chain::ChainedError;
use libc::*;
use gl;
use gl::types::*;
use std::cmp;
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::sync::RwLock;

use capture;
use command;
use dl;
use encode;
use errors::*;
use function::Function;
use sdl;

lazy_static!{
    static ref POINTERS: RwLock<Pointers> = RwLock::new(Pointers::default());
}

#[derive(Debug, Default)]
pub struct Pointers {
    RunListenServer: Function<unsafe extern "C" fn(*mut c_void,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_char,
                                                   *mut c_void,
                                                   *mut c_void)
                                                   -> c_int>,

    Cmd_AddCommand: Function<unsafe extern "C" fn(*const c_char, *mut c_void)>,
    Cmd_Argc: Function<unsafe extern "C" fn() -> c_int>,
    Cmd_Argv: Function<unsafe extern "C" fn(c_int) -> *const c_char>,
    Con_Printf: Function<unsafe extern "C" fn(*const c_char)>,
    Memory_Init: Function<unsafe extern "C" fn(*mut c_void, c_int)>,
    Sys_VID_FlipScreen: Function<unsafe extern "C" fn()>,
    VideoMode_GetCurrentVideoMode: Function<unsafe extern "C" fn(*mut c_int,
                                                                 *mut c_int,
                                                                 *mut c_int)>,
    VideoMode_IsWindowed: Function<unsafe extern "C" fn() -> c_int>,

    window_rect: Option<*mut RECT>,
    s_BackBufferFBO: Option<*mut FBO_Container_t>,
}

// TODO: think about how to deal with unsafety here.
// The compiler complaining about *mut not being Send/Sync is perfectly valid here.
// Our safe RwLock cannot guarantee there isn't some game thread accessing the values
// at the same time. Although reading/writing to a pointer is already unsafe?
unsafe impl Send for Pointers {}
unsafe impl Sync for Pointers {}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct RECT {
    left: c_int,
    right: c_int,
    top: c_int,
    bottom: c_int,
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct FBO_Container_t {
    s_hBackBufferFBO: GLuint,
    s_hBackBufferCB: GLuint,
    s_hBackBufferDB: GLuint,
    s_hBackBufferTex: GLuint,
}

/// The "main" function of hw.so, called inside `CEngineAPI::Run()`.
///
/// The game runs within this function and shortly after it exits hw.so is unloaded.
/// Note: `_restart` also causes this function to exit, in this case the launcher
/// unloads and reloads hw.so and this function is called again as if it was a fresh start.
#[export_name = "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_"]
pub unsafe extern "C" fn RunListenServer(instance: *mut c_void,
                                         basedir: *mut c_char,
                                         cmdline: *mut c_char,
                                         postRestartCmdLineArgs: *mut c_char,
                                         launcherFactory: *mut c_void,
                                         filesystemFactory: *mut c_void)
                                         -> c_int {
    // hw.so just loaded, either for the first time or potentially at a different address.
    // Refresh all pointers.
    if let Err(ref e) = refresh_pointers().chain_err(|| "error refreshing pointers") {
        panic!("{}", e.display());
    }

    // Initialize the encoding.
    encode::initialize();

    // Initialize the capturing.
    capture::initialize();

    let rv = real!(RunListenServer)(instance,
                                    basedir,
                                    cmdline,
                                    postRestartCmdLineArgs,
                                    launcherFactory,
                                    filesystemFactory);

    // Since hw.so is getting unloaded, reset all pointers.
    reset_pointers();

    rv
}

/// Initializes the hunk memory.
///
/// After the hunk memory has been initialized we can register console commands and variables.
/// It's also a good place to get OpenGL function pointers.
#[no_mangle]
pub unsafe extern "C" fn Memory_Init(buf: *mut c_void, size: c_int) {
    real!(Memory_Init)(buf, size);

    register_cvars_and_commands();

    gl::ReadPixels::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::ReadPixels::is_loaded() {
        panic!("could not load glReadPixels()");
    }
    gl::PixelStorei::load_with(|s| sdl::get_proc_address(s) as _);
    if !gl::PixelStorei::is_loaded() {
        panic!("could not load glPixelStorei()");
    }
}

/// Flips the screen.
#[export_name = "_Z18Sys_VID_FlipScreenv"]
pub unsafe extern "C" fn Sys_VID_FlipScreen() {
    if capture::is_capturing() {
        let (w, h) = get_resolution();
        let mut buf = capture::get_buffer((w, h));

        // Our buffer expects 1-byte alignment.
        gl::PixelStorei(gl::PACK_ALIGNMENT, 1);

        // Get the pixels!
        gl::ReadPixels(0, 0, w as GLsizei, h as GLsizei,
                       gl::RGB, gl::UNSIGNED_BYTE,
                       buf.data.as_mut_ptr() as _);

        capture::capture(buf);
    }

    real!(Sys_VID_FlipScreen)();

    // TODO: check if we're called from SCR_UpdateScreen().

    // println!("s_BackBufferFBO: {:?}", *POINTERS.read().unwrap().s_BackBufferFBO.unwrap());
}

/// Obtains and stores all necessary function and variable addresses.
fn refresh_pointers() -> Result<()> {
    let hw = dl::open("hw.so", RTLD_NOW | RTLD_NOLOAD)
        .chain_err(|| "couldn't load hw.so")?;

    let mut pointers = POINTERS.write().unwrap();

    unsafe {
        find!(pointers,
              hw,
              RunListenServer,
              "_Z15RunListenServerPvPcS0_S0_PFP14IBaseInterfacePKcPiES7_");
        find!(pointers, hw, Cmd_AddCommand, "Cmd_AddCommand");
        find!(pointers, hw, Cmd_Argc, "Cmd_Argc");
        find!(pointers, hw, Cmd_Argv, "Cmd_Argv");
        find!(pointers, hw, Con_Printf, "Con_Printf");
        find!(pointers, hw, Memory_Init, "Memory_Init");
        find!(pointers, hw, Sys_VID_FlipScreen, "_Z18Sys_VID_FlipScreenv");
        find!(pointers, hw, VideoMode_GetCurrentVideoMode, "VideoMode_GetCurrentVideoMode");
        find!(pointers, hw, VideoMode_IsWindowed, "VideoMode_IsWindowed");

        pointers.window_rect = Some(hw.sym("window_rect")
                .chain_err(|| "couldn't find window_rect")? as _);
        pointers.s_BackBufferFBO = Some(hw.sym("s_BackBufferFBO")
                .chain_err(|| "couldn't find s_BackBufferFBO")? as _);
    }

    Ok(())
}

/// Resets all pointers to their default values.
fn reset_pointers() {
    *POINTERS.write().unwrap() = Pointers::default();
}

/// Registers console commands and variables.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_cvars_and_commands() {
    for cmd in command::COMMANDS.iter() {
        register_command(cmd.name(), cmd.callback());
    }
}

/// Registers a console command.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
unsafe fn register_command(name: &'static [u8], callback: unsafe extern "C" fn()) {
    real!(Cmd_AddCommand)(name as *const _ as *const _, callback as *mut c_void);
}

/// Prints the given string to the game console.
///
/// `string` must not contain null bytes.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn con_print(string: &str) {
    real!(Con_Printf)(CString::new(string.replace('%', "%%"))
                          .expect("string cannot contain null bytes")
                          .as_ptr())
}

/// Gets the console command argument count.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argc() -> u32 {
    let argc = real!(Cmd_Argc)();
    cmp::max(0, argc) as u32
}

/// Gets a console command argument.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn cmd_argv(index: u32) -> String {
    let index = cmp::min(index, i32::max_value() as u32) as i32;
    let arg = real!(Cmd_Argv)(index);
    CStr::from_ptr(arg).to_string_lossy().into_owned()
}

/// Returns the current game resolution.
///
/// # Safety
/// Unsafe because this function should only be called from the main game thread.
pub unsafe fn get_resolution() -> (u32, u32) {
    let mut width;
    let mut height;

    if real!(VideoMode_IsWindowed)() != 0 {
        let window_rect = *POINTERS.read().unwrap().window_rect.unwrap();
        width = window_rect.right - window_rect.left;
        height = window_rect.bottom - window_rect.top;
    } else {
        width = mem::uninitialized();
        height = mem::uninitialized();
        real!(VideoMode_GetCurrentVideoMode)(&mut width, &mut height, ptr::null_mut());
    }

    width = cmp::max(0, width);
    height = cmp::max(0, height);

    (width as u32, height as u32)
}

command!(cap_test, |engine| {
    let args = engine.args();

    let mut buf = String::new();
    buf.push_str(&format!("Args len: {}\n", args.len()));

    for arg in args {
        buf.push_str(&arg);
        buf.push('\n');
    }

    engine.con_print(&buf);
});

command!(cap_another_test, |engine| {
    engine.con_print("Hello! %s %d %\n");
});
<|endoftext|>


<commit_before>use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::path::Path;

/// Build configuration. See [CFG].
pub struct Cfg<'a> {
    pub include_prefix: &'a str,
    // Not implemented yet. https://github.com/dtolnay/cxx/issues/417
    #[doc(hidden)]
    pub exported_header_dirs: Vec<&'a Path>,
    #[doc(hidden)]
    pub exported_header_prefixes: Vec<&'a str>,
    #[doc(hidden)]
    pub exported_header_links: Vec<&'a str>,
    marker: PhantomData<*const ()>, // !Send + !Sync
}

/// Global configuration of the current build.
///
///

///
/// ## **`CFG.include_prefix`**
///
/// The prefix at which C++ code from your crate as well as directly dependent
/// crates can access the code generated during this build.
///
/// By default, the `include_prefix` is equal to the name of the current crate.
/// That means if your crate is called `demo` and has Rust source files in a
/// *src/* directory and maybe some handwritten C++ header files in an
/// *include/* directory, then the current crate as well as downstream crates
/// might include them as follows:
///
/// ```
/// # const _: &str = stringify! {
///   // include one of the handwritten headers:
/// #include "demo/include/wow.h"
///
///   // include a header generated from Rust cxx::bridge:
/// #include "demo/src/lib.rs.h"
/// # };
/// ```
///
/// By modifying `CFG.include_prefix` we can substitute a prefix that is
/// different from the crate name if desired. Here we'll change it to
/// `"path/to"` which will make import paths take the form
/// `"path/to/include/wow.h"` and `"path/to/src/lib.rs.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.include_prefix = "path/to";
///
///     cxx_build::bridge("src/lib.rs")
///         .file("src/demo.cc") // probably contains `#include "path/to/src/lib.rs.h"`
///         /* ... */
///         .compile("demo");
/// }
/// ```
///
/// Note that cross-crate imports are only made available between **direct
/// dependencies**. Another crate must directly depend on your crate in order to
/// #include its headers; a transitive dependency is not sufficient.
/// Additionally, headers from a direct dependency are only importable if the
/// dependency's Cargo.toml manifest contains a `links` key. If not, its headers
/// will not be importable from outside of the same crate.
///
///

///
/// ## **`CFG.exported_header_dirs`**
///
/// A vector of absolute paths. The current crate, directly dependent crates,
/// and further crates to which this crate's headers are exported (see below)
/// will be able to `#include` headers from these directories.
///
/// Adding a directory to `exported_header_dirs` is similar to adding it to the
/// current build via the `cc` crate's [`Build::include`][cc::Build::include],
/// but *also* makes the directory available to downstream crates that want to
/// `#include` one of the headers from your crate. If the dir were added only
/// using `Build::include`, the downstream crate including your header would
/// need to manually add the same directory to their own build as well.
///
/// When using `exported_header_dirs`, your crate must also set a `links` key
/// for itself in Cargo.toml. See [*the `links` manifest key*][links]. The
/// reason is that Cargo imposes no ordering on the execution of build scripts
/// without a `links` key, which means the downstream crate's build script might
/// execute before yours decides what to put into `exported_header_dirs`.
///
/// [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
///
/// ### Example
///
/// One of your crate's headers wants to include a system library, such as
/// `#include "Python.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
/// use std::path::PathBuf;
///
/// fn main() {
///     let python3 = pkg_config::probe_library("python3").unwrap();
///     let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path);
///     CFG.exported_header_dirs.extend(python_include_paths);
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
///
/// ### Example
///
/// Your crate wants to rearrange the headers that it exports vs how they're
/// laid out locally inside the crate's source directory.
///
/// Suppose the crate as published contains a file at `./include/myheader.h` but
/// wants it available to downstream crates as `#include "foo/v1/public.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
/// use std::path::Path;
/// use std::{env, fs};
///
/// fn main() {
///     let out_dir = env::var_os("OUT_DIR").unwrap();
///     let headers = Path::new(&out_dir).join("headers");
///     CFG.exported_header_dirs.push(&headers);
///
///     // We contain `include/myheader.h` locally, but
///     // downstream will use `#include "foo/v1/public.h"`
///     let foo = headers.join("foo").join("v1");
///     fs::create_dir_all(&foo).unwrap();
///     fs::copy("include/myheader.h", foo.join("public.h")).unwrap();
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
///
///

///
/// ## **`CFG.exported_header_prefixes`**
///
/// Vector of strings. These each refer to the `include_prefix` of one of your
/// direct dependencies, or a prefix thereof. They describe which of your
/// dependencies participate in your crate's C++ public API, as opposed to
/// private use by your crate's implementation.
///
/// As a general rule, if one of your headers `#include`s something from one of
/// your dependencies, you need to put that dependency's `include_prefix` into
/// `CFG.exported_header_prefixes` (*or* their `links` key into
/// `CFG.exported_header_links`; see below). On the other hand if only your C++
/// implementation files and *not* your headers are importing from the
/// dependency, you do not export that dependency.
///
/// The significance of exported headers is that if downstream code (crate 𝒜)
/// contains an `#include` of a header from your crate (ℬ) and your header
/// contains an `#include` of something from your dependency (𝒞), the exported
/// dependency 𝒞 becomes available during the downstream crate 𝒜's build.
/// Otherwise the downstream crate 𝒜 doesn't know about 𝒞 and wouldn't be able
/// to find what header your header is referring to, and would fail to build.
///
/// When using `exported_header_prefixes`, your crate must also set a `links`
/// key for itself in Cargo.toml.
///
/// ### Example
///
/// Suppose you have a crate with 5 direct dependencies and the `include_prefix`
/// for each one are:
///
/// - "crate0"
/// - "group/api/crate1"
/// - "group/api/crate2"
/// - "group/api/contrib/crate3"
/// - "detail/crate4"
///
/// Your header involves types from the first four so we re-export those as part
/// of your public API, while crate4 is only used internally by your cc file not
/// your header, so we do not export:
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.exported_header_prefixes = vec!["crate0", "group/api"];
///
///     cxx_build::bridge("src/bridge.rs")
///         .file("src/impl.cc")
///         .compile("demo");
/// }
/// ```
///
///

///
/// ## **`CFG.exported_header_links`**
///
/// Vector of strings. These each refer to the `links` attribute ([*the `links`
/// manifest key*][links]) of one of your crate's direct dependencies.
///
/// This achieves an equivalent result to `CFG.exported_header_prefixes` by
/// re-exporting a dependency as part of your crate's public API, except with
/// finer grained control for cases when multiple crates might be sharing the
/// same `include_prefix` and you'd like to export some but not others. Links
/// attributes are guaranteed to be unique identifiers by Cargo.
///
/// When using `exported_header_links`, your crate must also set a `links` key
/// for itself in Cargo.toml.
///
/// ### Example
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.exported_header_links.push("git2");
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
#[cfg(doc)]
pub static mut CFG: Cfg = Cfg {
    include_prefix: "",
    exported_header_dirs: Vec::new(),
    exported_header_prefixes: Vec::new(),
    exported_header_links: Vec::new(),
    marker: PhantomData,
};

impl<'a> Debug for Cfg<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter
            .debug_struct("Cfg")
            .field("include_prefix", &self.include_prefix)
            .finish()
    }
}

#[cfg(not(doc))]
pub use self::r#impl::Cfg::CFG;

#[cfg(not(doc))]
mod r#impl {
    use crate::intern::{intern, InternedString};
    use crate::vec::{self, InternedVec as _};
    use lazy_static::lazy_static;
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::fmt::{self, Debug};
    use std::marker::PhantomData;
    use std::ops::{Deref, DerefMut};
    use std::sync::{PoisonError, RwLock};

    struct CurrentCfg {
        include_prefix: InternedString,
        exported_header_dirs: Vec<InternedString>,
        exported_header_prefixes: Vec<InternedString>,
        exported_header_links: Vec<InternedString>,
    }

    impl CurrentCfg {
        fn default() -> Self {
            let include_prefix = crate::env_os("CARGO_PKG_NAME")
                .map(|pkg| intern(&pkg.to_string_lossy()))
                .unwrap_or_default();
            let exported_header_dirs = Vec::new();
            let exported_header_prefixes = Vec::new();
            let exported_header_links = Vec::new();
            CurrentCfg {
                include_prefix,
                exported_header_dirs,
                exported_header_prefixes,
                exported_header_links,
            }
        }
    }

    lazy_static! {
        static ref CURRENT: RwLock<CurrentCfg> = RwLock::new(CurrentCfg::default());
    }

    thread_local! {
        // FIXME: If https://github.com/rust-lang/rust/issues/77425 is resolved,
        // we can delete this thread local side table and instead make each CFG
        // instance directly own the associated super::Cfg.
        //
        //     #[allow(const_item_mutation)]
        //     pub const CFG: Cfg = Cfg {
        //         cfg: AtomicPtr::new(ptr::null_mut()),
        //     };
        //     pub struct Cfg {
        //         cfg: AtomicPtr<super::Cfg>,
        //     }
        //
        static CONST_DEREFS: RefCell<HashMap<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
    }

    #[derive(Eq, PartialEq, Hash)]
    struct Handle(*const Cfg<'static>);

    impl<'a> Cfg<'a> {
        fn current() -> super::Cfg<'a> {
            let current = CURRENT.read().unwrap_or_else(PoisonError::into_inner);
            let include_prefix = current.include_prefix.str();
            let exported_header_dirs = current.exported_header_dirs.vec();
            let exported_header_prefixes = current.exported_header_prefixes.vec();
            let exported_header_links = current.exported_header_links.vec();
            super::Cfg {
                include_prefix,
                exported_header_dirs,
                exported_header_prefixes,
                exported_header_links,
                marker: PhantomData,
            }
        }

        const fn handle(self: &Cfg<'a>) -> Handle {
            Handle(<*const Cfg>::cast(self))
        }
    }

    // Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
    // drop on the same thread where they were created.
    pub enum Cfg<'a> {
        Mut(super::Cfg<'a>),
        CFG,
    }

    impl<'a> Debug for Cfg<'a> {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            if let Cfg::Mut(cfg) = self {
                Debug::fmt(cfg, formatter)
            } else {
                Debug::fmt(&Cfg::current(), formatter)
            }
        }
    }

    impl<'a> Deref for Cfg<'a> {
        type Target = super::Cfg<'a>;

        fn deref(&self) -> &Self::Target {
            if let Cfg::Mut(cfg) = self {
                cfg
            } else {
                let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
                    &mut **derefs
                        .borrow_mut()
                        .entry(self.handle())
                        .or_insert_with(|| Box::new(Cfg::current()))
                });
                unsafe { &mut *cfg }
            }
        }
    }

    impl<'a> DerefMut for Cfg<'a> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            if let Cfg::CFG = self {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
                *self = Cfg::Mut(Cfg::current());
            }
            match self {
                Cfg::Mut(cfg) => cfg,
                Cfg::CFG => unreachable!(),
            }
        }
    }

    impl<'a> Drop for Cfg<'a> {
        fn drop(&mut self) {
            if let Cfg::Mut(cfg) = self {
                let mut current = CURRENT.write().unwrap_or_else(PoisonError::into_inner);
                current.include_prefix = intern(cfg.include_prefix);
                current.exported_header_dirs = vec::intern(&cfg.exported_header_dirs);
                current.exported_header_prefixes = vec::intern(&cfg.exported_header_prefixes);
                current.exported_header_links = vec::intern(&cfg.exported_header_links);
            } else {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
            }
        }
    }
}
<commit_msg>Display field types in CFG documentation<commit_after>use std::fmt::{self, Debug};
use std::marker::PhantomData;
use std::path::Path;

/// Build configuration. See [CFG].
pub struct Cfg<'a> {
    pub include_prefix: &'a str,
    // Not implemented yet. https://github.com/dtolnay/cxx/issues/417
    #[doc(hidden)]
    pub exported_header_dirs: Vec<&'a Path>,
    #[doc(hidden)]
    pub exported_header_prefixes: Vec<&'a str>,
    #[doc(hidden)]
    pub exported_header_links: Vec<&'a str>,
    marker: PhantomData<*const ()>, // !Send + !Sync
}

/// Global configuration of the current build.
///
///

///
///
&str

///
/// ## **`CFG.include_prefix`**
///
/// The prefix at which C++ code from your crate as well as directly dependent
/// crates can access the code generated during this build.
///
/// By default, the `include_prefix` is equal to the name of the current crate.
/// That means if your crate is called `demo` and has Rust source files in a
/// *src/* directory and maybe some handwritten C++ header files in an
/// *include/* directory, then the current crate as well as downstream crates
/// might include them as follows:
///
/// ```
/// # const _: &str = stringify! {
///   // include one of the handwritten headers:
/// #include "demo/include/wow.h"
///
///   // include a header generated from Rust cxx::bridge:
/// #include "demo/src/lib.rs.h"
/// # };
/// ```
///
/// By modifying `CFG.include_prefix` we can substitute a prefix that is
/// different from the crate name if desired. Here we'll change it to
/// `"path/to"` which will make import paths take the form
/// `"path/to/include/wow.h"` and `"path/to/src/lib.rs.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.include_prefix = "path/to";
///
///     cxx_build::bridge("src/lib.rs")
///         .file("src/demo.cc") // probably contains `#include "path/to/src/lib.rs.h"`
///         /* ... */
///         .compile("demo");
/// }
/// ```
///
/// Note that cross-crate imports are only made available between **direct
/// dependencies**. Another crate must directly depend on your crate in order to
/// #include its headers; a transitive dependency is not sufficient.
/// Additionally, headers from a direct dependency are only importable if the
/// dependency's Cargo.toml manifest contains a `links` key. If not, its headers
/// will not be importable from outside of the same crate.
///
///

///
///
Vec<&Path>

///
/// ## **`CFG.exported_header_dirs`**
///
/// A vector of absolute paths. The current crate, directly dependent crates,
/// and further crates to which this crate's headers are exported (see below)
/// will be able to `#include` headers from these directories.
///
/// Adding a directory to `exported_header_dirs` is similar to adding it to the
/// current build via the `cc` crate's [`Build::include`][cc::Build::include],
/// but *also* makes the directory available to downstream crates that want to
/// `#include` one of the headers from your crate. If the dir were added only
/// using `Build::include`, the downstream crate including your header would
/// need to manually add the same directory to their own build as well.
///
/// When using `exported_header_dirs`, your crate must also set a `links` key
/// for itself in Cargo.toml. See [*the `links` manifest key*][links]. The
/// reason is that Cargo imposes no ordering on the execution of build scripts
/// without a `links` key, which means the downstream crate's build script might
/// execute before yours decides what to put into `exported_header_dirs`.
///
/// [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
///
/// ### Example
///
/// One of your crate's headers wants to include a system library, such as
/// `#include "Python.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
/// use std::path::PathBuf;
///
/// fn main() {
///     let python3 = pkg_config::probe_library("python3").unwrap();
///     let python_include_paths = python3.include_paths.iter().map(PathBuf::as_path);
///     CFG.exported_header_dirs.extend(python_include_paths);
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
///
/// ### Example
///
/// Your crate wants to rearrange the headers that it exports vs how they're
/// laid out locally inside the crate's source directory.
///
/// Suppose the crate as published contains a file at `./include/myheader.h` but
/// wants it available to downstream crates as `#include "foo/v1/public.h"`.
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
/// use std::path::Path;
/// use std::{env, fs};
///
/// fn main() {
///     let out_dir = env::var_os("OUT_DIR").unwrap();
///     let headers = Path::new(&out_dir).join("headers");
///     CFG.exported_header_dirs.push(&headers);
///
///     // We contain `include/myheader.h` locally, but
///     // downstream will use `#include "foo/v1/public.h"`
///     let foo = headers.join("foo").join("v1");
///     fs::create_dir_all(&foo).unwrap();
///     fs::copy("include/myheader.h", foo.join("public.h")).unwrap();
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
///
///

///
///
Vec<&str>

///
/// ## **`CFG.exported_header_prefixes`**
///
/// Vector of strings. These each refer to the `include_prefix` of one of your
/// direct dependencies, or a prefix thereof. They describe which of your
/// dependencies participate in your crate's C++ public API, as opposed to
/// private use by your crate's implementation.
///
/// As a general rule, if one of your headers `#include`s something from one of
/// your dependencies, you need to put that dependency's `include_prefix` into
/// `CFG.exported_header_prefixes` (*or* their `links` key into
/// `CFG.exported_header_links`; see below). On the other hand if only your C++
/// implementation files and *not* your headers are importing from the
/// dependency, you do not export that dependency.
///
/// The significance of exported headers is that if downstream code (crate 𝒜)
/// contains an `#include` of a header from your crate (ℬ) and your header
/// contains an `#include` of something from your dependency (𝒞), the exported
/// dependency 𝒞 becomes available during the downstream crate 𝒜's build.
/// Otherwise the downstream crate 𝒜 doesn't know about 𝒞 and wouldn't be able
/// to find what header your header is referring to, and would fail to build.
///
/// When using `exported_header_prefixes`, your crate must also set a `links`
/// key for itself in Cargo.toml.
///
/// ### Example
///
/// Suppose you have a crate with 5 direct dependencies and the `include_prefix`
/// for each one are:
///
/// - "crate0"
/// - "group/api/crate1"
/// - "group/api/crate2"
/// - "group/api/contrib/crate3"
/// - "detail/crate4"
///
/// Your header involves types from the first four so we re-export those as part
/// of your public API, while crate4 is only used internally by your cc file not
/// your header, so we do not export:
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.exported_header_prefixes = vec!["crate0", "group/api"];
///
///     cxx_build::bridge("src/bridge.rs")
///         .file("src/impl.cc")
///         .compile("demo");
/// }
/// ```
///
///

///
///
Vec<&str>

///
/// ## **`CFG.exported_header_links`**
///
/// Vector of strings. These each refer to the `links` attribute ([*the `links`
/// manifest key*][links]) of one of your crate's direct dependencies.
///
/// This achieves an equivalent result to `CFG.exported_header_prefixes` by
/// re-exporting a dependency as part of your crate's public API, except with
/// finer grained control for cases when multiple crates might be sharing the
/// same `include_prefix` and you'd like to export some but not others. Links
/// attributes are guaranteed to be unique identifiers by Cargo.
///
/// When using `exported_header_links`, your crate must also set a `links` key
/// for itself in Cargo.toml.
///
/// ### Example
///
/// ```no_run
/// // build.rs
///
/// use cxx_build::CFG;
///
/// fn main() {
///     CFG.exported_header_links.push("git2");
///
///     cxx_build::bridge("src/bridge.rs").compile("demo");
/// }
/// ```
#[cfg(doc)]
pub static mut CFG: Cfg = Cfg {
    include_prefix: "",
    exported_header_dirs: Vec::new(),
    exported_header_prefixes: Vec::new(),
    exported_header_links: Vec::new(),
    marker: PhantomData,
};

impl<'a> Debug for Cfg<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter
            .debug_struct("Cfg")
            .field("include_prefix", &self.include_prefix)
            .finish()
    }
}

#[cfg(not(doc))]
pub use self::r#impl::Cfg::CFG;

#[cfg(not(doc))]
mod r#impl {
    use crate::intern::{intern, InternedString};
    use crate::vec::{self, InternedVec as _};
    use lazy_static::lazy_static;
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::fmt::{self, Debug};
    use std::marker::PhantomData;
    use std::ops::{Deref, DerefMut};
    use std::sync::{PoisonError, RwLock};

    struct CurrentCfg {
        include_prefix: InternedString,
        exported_header_dirs: Vec<InternedString>,
        exported_header_prefixes: Vec<InternedString>,
        exported_header_links: Vec<InternedString>,
    }

    impl CurrentCfg {
        fn default() -> Self {
            let include_prefix = crate::env_os("CARGO_PKG_NAME")
                .map(|pkg| intern(&pkg.to_string_lossy()))
                .unwrap_or_default();
            let exported_header_dirs = Vec::new();
            let exported_header_prefixes = Vec::new();
            let exported_header_links = Vec::new();
            CurrentCfg {
                include_prefix,
                exported_header_dirs,
                exported_header_prefixes,
                exported_header_links,
            }
        }
    }

    lazy_static! {
        static ref CURRENT: RwLock<CurrentCfg> = RwLock::new(CurrentCfg::default());
    }

    thread_local! {
        // FIXME: If https://github.com/rust-lang/rust/issues/77425 is resolved,
        // we can delete this thread local side table and instead make each CFG
        // instance directly own the associated super::Cfg.
        //
        //     #[allow(const_item_mutation)]
        //     pub const CFG: Cfg = Cfg {
        //         cfg: AtomicPtr::new(ptr::null_mut()),
        //     };
        //     pub struct Cfg {
        //         cfg: AtomicPtr<super::Cfg>,
        //     }
        //
        static CONST_DEREFS: RefCell<HashMap<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
    }

    #[derive(Eq, PartialEq, Hash)]
    struct Handle(*const Cfg<'static>);

    impl<'a> Cfg<'a> {
        fn current() -> super::Cfg<'a> {
            let current = CURRENT.read().unwrap_or_else(PoisonError::into_inner);
            let include_prefix = current.include_prefix.str();
            let exported_header_dirs = current.exported_header_dirs.vec();
            let exported_header_prefixes = current.exported_header_prefixes.vec();
            let exported_header_links = current.exported_header_links.vec();
            super::Cfg {
                include_prefix,
                exported_header_dirs,
                exported_header_prefixes,
                exported_header_links,
                marker: PhantomData,
            }
        }

        const fn handle(self: &Cfg<'a>) -> Handle {
            Handle(<*const Cfg>::cast(self))
        }
    }

    // Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
    // drop on the same thread where they were created.
    pub enum Cfg<'a> {
        Mut(super::Cfg<'a>),
        CFG,
    }

    impl<'a> Debug for Cfg<'a> {
        fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            if let Cfg::Mut(cfg) = self {
                Debug::fmt(cfg, formatter)
            } else {
                Debug::fmt(&Cfg::current(), formatter)
            }
        }
    }

    impl<'a> Deref for Cfg<'a> {
        type Target = super::Cfg<'a>;

        fn deref(&self) -> &Self::Target {
            if let Cfg::Mut(cfg) = self {
                cfg
            } else {
                let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
                    &mut **derefs
                        .borrow_mut()
                        .entry(self.handle())
                        .or_insert_with(|| Box::new(Cfg::current()))
                });
                unsafe { &mut *cfg }
            }
        }
    }

    impl<'a> DerefMut for Cfg<'a> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            if let Cfg::CFG = self {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
                *self = Cfg::Mut(Cfg::current());
            }
            match self {
                Cfg::Mut(cfg) => cfg,
                Cfg::CFG => unreachable!(),
            }
        }
    }

    impl<'a> Drop for Cfg<'a> {
        fn drop(&mut self) {
            if let Cfg::Mut(cfg) = self {
                let mut current = CURRENT.write().unwrap_or_else(PoisonError::into_inner);
                current.include_prefix = intern(cfg.include_prefix);
                current.exported_header_dirs = vec::intern(&cfg.exported_header_dirs);
                current.exported_header_prefixes = vec::intern(&cfg.exported_header_prefixes);
                current.exported_header_links = vec::intern(&cfg.exported_header_links);
            } else {
                CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[macro_escape];

macro_rules! impl_dimensional(
    ($Self:ident, $T:ty, $n:expr) => (
        impl<T> Dimensional<$T,[$T,..$n]> for $Self<T> {
            #[inline]
            pub fn index<'a>(&'a self, i: uint) -> &'a $T {
                &'a self.as_slice()[i]
            }

            #[inline]
            pub fn index_mut<'a>(&'a mut self, i: uint) -> &'a mut $T {
                &'a mut self.as_mut_slice()[i]
            }

            #[inline]
            pub fn as_slice<'a>(&'a self) -> &'a [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }

            #[inline]
            pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }
        }
    )
)

macro_rules! impl_dimensional_fns(
    ($Self:ident, $T:ty, 2) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..2]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..2] {
                [f(self.index(0)),
                 f(self.index(1))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..2]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..2] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..2]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), init))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(1), &f(self.index(0), init))
            }
        }
    );
    ($Self:ident, $T:ty, 3) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..3]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..3] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..3]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..3] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..3]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), init)))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(2), &f(self.index(1), &f(self.index(0), init)))
            }
        }
    );
    ($Self:ident, $T:ty, 4) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..4]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..4] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2)),
                 f(self.index(3))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
                f(self.index_mut(3));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..4]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..4] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2)),
                 f(self.index(3), other.index(3))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..4]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
                f(self.index_mut(3), other.index(3));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), &f(self.index(3), init))))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(3), &f(self.index(2), &f(self.index(1), &f(self.index(0), init))))
            }
        }
    )
)

macro_rules! impl_swap(
    ($Self:ident) => (
        impl<T:Clone> $Self<T> {
            #[inline]
            pub fn swap(&mut self, a: uint, b: uint) {
                let tmp = self.index(a).clone();
                *self.index_mut(a) = self.index(b).clone();
                *self.index_mut(b) = tmp;
            }
        }
    )
)

macro_rules! impl_approx(
    ($Self:ident) => (
        impl<T:Clone + Eq + ApproxEq<T>> ApproxEq<T> for $Self<T> {
            #[inline]
            pub fn approx_epsilon() -> T {
                ApproxEq::approx_epsilon::<T,T>()
            }

            #[inline]
            pub fn approx_eq(&self, other: &$Self<T>) -> bool {
                self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
            }

            #[inline]
            pub fn approx_eq_eps(&self, other: &$Self<T>, epsilon: &T) -> bool {
                self.zip(other, |a, b| a.approx_eq_eps(b, epsilon)).iter().all(|&x| x)
            }
        }
    )
)
<commit_msg>Fix lifetime error<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[macro_escape];

macro_rules! impl_dimensional(
    ($Self:ident, $T:ty, $n:expr) => (
        impl<T> Dimensional<$T,[$T,..$n]> for $Self<T> {
            #[inline]
            pub fn index<'a>(&'a self, i: uint) -> &'a $T {
                &'a self.as_slice()[i]
            }

            #[inline]
            pub fn index_mut<'a>(&'a mut self, i: uint) -> &'a mut $T {
                &'a mut self.as_mut_slice()[i]
            }

            #[inline]
            pub fn as_slice<'a>(&'a self) -> &'a [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }

            #[inline]
            pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [$T,..$n] {
                use std::cast::transmute;
                unsafe { transmute(self) }
            }
        }
    )
)

macro_rules! impl_dimensional_fns(
    ($Self:ident, $T:ty, 2) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..2]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..2] {
                [f(self.index(0)),
                 f(self.index(1))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..2]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..2] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..2]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), init))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(1), &f(self.index(0), init))
            }
        }
    );
    ($Self:ident, $T:ty, 3) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..3]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..3] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..3]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..3] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..3]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), init)))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(2), &f(self.index(1), &f(self.index(0), init)))
            }
        }
    );
    ($Self:ident, $T:ty, 4) => (
        impl<T> $Self<T> {
            #[inline]
            pub fn from_slice<'a>(slice: [$T,..4]) -> $Self<T> {
                use std::cast::transmute;
                unsafe { transmute(slice) }
            }

            #[inline(always)]
            pub fn map<U>(&self, f: &fn(&$T) -> U) -> [U,..4] {
                [f(self.index(0)),
                 f(self.index(1)),
                 f(self.index(2)),
                 f(self.index(3))]
            }

            #[inline(always)]
            pub fn map_mut(&mut self, f: &fn(&mut $T)) {
                f(self.index_mut(0));
                f(self.index_mut(1));
                f(self.index_mut(2));
                f(self.index_mut(3));
            }

            #[inline(always)]
            pub fn zip<U, SU: Dimensional<U,[U,..4]>, V>(&self, other: &SU, f: &fn(&$T, &U) -> V) -> [V,..4] {
                [f(self.index(0), other.index(0)),
                 f(self.index(1), other.index(1)),
                 f(self.index(2), other.index(2)),
                 f(self.index(3), other.index(3))]
            }

            #[inline(always)]
            pub fn zip_mut<U, SU: Dimensional<U,[U,..4]>>(&mut self, other: &SU, f: &fn(&mut $T, &U)) {
                f(self.index_mut(0), other.index(0));
                f(self.index_mut(1), other.index(1));
                f(self.index_mut(2), other.index(2));
                f(self.index_mut(3), other.index(3));
            }

            #[inline(always)]
            pub fn foldl<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(0), &f(self.index(1), &f(self.index(2), &f(self.index(3), init))))
            }

            #[inline(always)]
            pub fn foldr<U>(&self, init: &U, f: &fn(&$T, &U) -> U) -> U {
                f(self.index(3), &f(self.index(2), &f(self.index(1), &f(self.index(0), init))))
            }
        }
    )
)

macro_rules! impl_swap(
    ($Self:ident) => (
        impl<T:Clone> $Self<T> {
            #[inline]
            pub fn swap(&mut self, a: uint, b: uint) {
                let tmp = self.index(a).clone();
                *self.index_mut(a) = self.index(b).clone();
                *self.index_mut(b) = tmp;
            }
        }
    )
)

macro_rules! impl_approx(
    ($Self:ident) => (
        impl<T:Clone + Eq + ApproxEq<T>> ApproxEq<T> for $Self<T> {
            #[inline]
            pub fn approx_epsilon() -> T {
                ApproxEq::approx_epsilon::<T,T>()
            }

            #[inline]
            pub fn approx_eq(&self, other: &$Self<T>) -> bool {
                self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
            }

            #[inline]
            pub fn approx_eq_eps(&self, other: &$Self<T>, epsilon: &T) -> bool {
                let tmp = self.zip(other, |a, b| a.approx_eq_eps(b, epsilon));
                tmp.iter().all(|&x| x)
            }
        }
    )
)
<|endoftext|>


<commit_before>use std::sync::mpsc::{Receiver, Sender};
use std::rc::Rc;

use action::ExecResult;
use super::{config, Condition, Context, Message, TimerEvent};
use reactor::{self, Event, EventDemultiplexer, EventHandler, Reactor};

#[derive(Debug)]
pub enum Request {
    Event(super::Event),
    Exit
}

#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum RequestHandler {
    Event,
    Exit
}

impl reactor::Event for Request {
    type Handler = RequestHandler;
    fn handler(&self) -> Self::Handler {
        match *self {
            Request::Event(_) => RequestHandler::Event,
            Request::Exit => RequestHandler::Exit,
        }
    }
}

#[derive(Debug)]
pub enum Response {
    Event(ExecResult),
    Exit
}

pub struct Dispatcher {
    contexts: Vec<Context>,
    output_channel: Sender<Response>,
    exits_received: u32
}

impl Dispatcher {
    pub fn new(contexts: Vec<config::Context>, action_output_channel: Sender<Response>) -> Dispatcher {
        let contexts = contexts.into_iter().map(|ctx| Context::from(ctx)).collect::<Vec<Context>>();
        Dispatcher {
            contexts: contexts,
            output_channel: action_output_channel,
            exits_received: 0
        }
    }

    pub fn start_loop(&mut self, channel: Receiver<Request>) {
        for i in channel.iter() {
            match i {
                Request::Event(event) => self.dispatch(event),
                Request::Exit => {
                    if self.on_exit() {
                        break;
                    }
                }
            }
        }
    }

    fn on_exit(&mut self) -> bool {
        self.exits_received += 1;
        let _ = self.output_channel.send(Response::Exit);
        self.exits_received >= 2
    }

    pub fn dispatch(&mut self, event: super::Event) {
        match event {
            super::Event::Message(event) => {
                let event = Rc::new(event);
                self.on_message(event);
            },
            super::Event::Timer(ref event) => {
                self.on_timer(event);
            }
        };
    }

    fn on_message(&mut self, event: Rc<Message>) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_message(event.clone()) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }

    fn on_timer(&mut self, event: &TimerEvent) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_timer(event) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }
}

use std::collections::BTreeMap;

pub struct RequestReactor {
    handlers: BTreeMap<RequestHandler, Box<reactor::EventHandler<Request, Handler=RequestHandler>>>,
    demultiplexer: Demultiplexer<Request>,
    exit_condition: Condition
}

impl RequestReactor {
    fn new(demultiplexer: Demultiplexer<Request>) -> RequestReactor {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(handlers::exit::ExitHandler::new(exit_condition.clone()));
        let event_handler = Box::new(handlers::event::Handler::new());

        let mut reactor = RequestReactor {
            demultiplexer: demultiplexer,
            exit_condition: exit_condition,
            handlers: BTreeMap::new()
        };

        reactor.register_handler(exit_handler);
        reactor.register_handler(event_handler);
        reactor
    }
}

impl Reactor for RequestReactor {
    type Event = Request;
    type Handler = RequestHandler;
    fn handle_events(&mut self) {
        while !self.exit_condition.is_active() {
            if let Some(request) = self.demultiplexer.select() {
                let mut handler = self.handlers.get_mut(&request.handler()).unwrap();
                handler.handle_event(request);
            } else {
                break;
            }
        }
    }
    fn register_handler(&mut self, handler: Box<reactor::EventHandler<Self::Event, Handler=RequestHandler>>) {
        self.handlers.insert(handler.handler(), handler);
    }
    fn remove_handler(&mut self, handler: &reactor::EventHandler<Self::Event, Handler=RequestHandler>){}
}

struct Demultiplexer<T>(Receiver<T>);

impl reactor::EventDemultiplexer for Demultiplexer<Request> {
    type Event = Request;
    fn select(&mut self) -> Option<Self::Event> {
        self.0.recv().ok()
    }
}

mod handlers {
    pub mod exit {
        use dispatcher::{Request, RequestHandler};
        use condition::Condition;
        use reactor::EventHandler;

        pub struct ExitHandler{
            condition: Condition,
            stops: u32
        }

        impl ExitHandler {
            pub fn new(condition: Condition) -> ExitHandler {
                ExitHandler {
                    condition: condition,
                    stops: 0
                }
            }
        }

        impl EventHandler<Request> for ExitHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Exit = event {
                    self.stops += 1;

                    if self.stops >= 2 {
                        self.condition.activate();
                    }
                } else {
                    unreachable!("An ExitHandler should only receive Exit events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Exit
            }
        }
    }

    pub mod event {
        use std::collections::BTreeMap;

        use dispatcher::{Request, RequestHandler};
        use reactor::{self, EventHandler, Event};

        use super::linear::LinearHandler;
        use self::message::MessageHandler;

        pub struct Handler{
            handlers: BTreeMap<::EventHandler, Box<reactor::EventHandler<::Event, Handler=::EventHandler>>>,
        }

        impl Handler {
            pub fn new() -> Handler {
                let timer_handler = Box::new(LinearHandler::new());
                let message_handler = Box::new(MessageHandler::new());
                let mut handler = Handler{
                    handlers: BTreeMap::new()
                };
                handler.register_handler(timer_handler);
                handler.register_handler(message_handler);
                handler
            }

            fn register_handler(&mut self, handler: Box<reactor::EventHandler<::Event, Handler=::EventHandler>>) {
                self.handlers.insert(handler.handler(), handler);
            }
        }

        impl reactor::EventHandler<Request> for Handler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Event(event) = event {
                    println!("Event recvd");
                    if let Some(handler) = self.handlers.get_mut(&event.handler()) {
                        handler.handle_event(event);
                    }
                } else {
                    unreachable!("An Handler should only receive Event events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Event
            }
        }

        pub mod message {
            use std::collections::BTreeMap;

            use dispatcher::{Request, RequestHandler};
            use reactor::{self, EventHandler, Event};

            pub struct MessageHandler {
                handlers: BTreeMap<::EventHandler, Box<reactor::EventHandler<::Event, Handler=::EventHandler>>>,
            }

            impl MessageHandler {
                pub fn new() -> MessageHandler {
                    let mut handler = MessageHandler{
                        handlers: BTreeMap::new()
                    };
                    handler
                }

                fn register_handler(&mut self, handler: Box<reactor::EventHandler<::Event, Handler=::EventHandler>>) {
                    self.handlers.insert(handler.handler(), handler);
                }
            }

            impl reactor::EventHandler<::Event> for MessageHandler {
                type Handler = ::EventHandler;
                fn handle_event(&mut self, event: ::Event) {
                    println!("message event");
                }
                fn handler(&self) -> Self::Handler {
                    ::EventHandler::Message
                }
            }
        }
    }

    mod linear {
        use context::Context;
        use dispatcher::{Request, RequestHandler};
        use EventHandler;
        use Event;
        use reactor;

        pub struct LinearHandler {
            contexts: Vec<Context>
        }

        impl LinearHandler {
            pub fn new() -> LinearHandler {
                LinearHandler {
                    contexts: Vec::new()
                }
            }
        }

        impl reactor::EventHandler<Event> for LinearHandler {
            type Handler = EventHandler;
            fn handle_event(&mut self, event: Event) {
                println!("timer event");
            }
            fn handler(&self) -> Self::Handler {
                EventHandler::Timer
            }
        }
    }
}
<commit_msg>dispatcher: renamme LinearHandler to TimerEventHandler<commit_after>use std::sync::mpsc::{Receiver, Sender};
use std::rc::Rc;

use action::ExecResult;
use super::{config, Condition, Context, Message, TimerEvent};
use reactor::{self, Event, EventDemultiplexer, EventHandler, Reactor};

#[derive(Debug)]
pub enum Request {
    Event(super::Event),
    Exit
}

#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum RequestHandler {
    Event,
    Exit
}

impl reactor::Event for Request {
    type Handler = RequestHandler;
    fn handler(&self) -> Self::Handler {
        match *self {
            Request::Event(_) => RequestHandler::Event,
            Request::Exit => RequestHandler::Exit,
        }
    }
}

#[derive(Debug)]
pub enum Response {
    Event(ExecResult),
    Exit
}

pub struct Dispatcher {
    contexts: Vec<Context>,
    output_channel: Sender<Response>,
    exits_received: u32
}

impl Dispatcher {
    pub fn new(contexts: Vec<config::Context>, action_output_channel: Sender<Response>) -> Dispatcher {
        let contexts = contexts.into_iter().map(|ctx| Context::from(ctx)).collect::<Vec<Context>>();
        Dispatcher {
            contexts: contexts,
            output_channel: action_output_channel,
            exits_received: 0
        }
    }

    pub fn start_loop(&mut self, channel: Receiver<Request>) {
        for i in channel.iter() {
            match i {
                Request::Event(event) => self.dispatch(event),
                Request::Exit => {
                    if self.on_exit() {
                        break;
                    }
                }
            }
        }
    }

    fn on_exit(&mut self) -> bool {
        self.exits_received += 1;
        let _ = self.output_channel.send(Response::Exit);
        self.exits_received >= 2
    }

    pub fn dispatch(&mut self, event: super::Event) {
        match event {
            super::Event::Message(event) => {
                let event = Rc::new(event);
                self.on_message(event);
            },
            super::Event::Timer(ref event) => {
                self.on_timer(event);
            }
        };
    }

    fn on_message(&mut self, event: Rc<Message>) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_message(event.clone()) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }

    fn on_timer(&mut self, event: &TimerEvent) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_timer(event) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }
}

use std::collections::BTreeMap;

pub struct RequestReactor {
    handlers: BTreeMap<RequestHandler, Box<reactor::EventHandler<Request, Handler=RequestHandler>>>,
    demultiplexer: Demultiplexer<Request>,
    exit_condition: Condition
}

impl RequestReactor {
    fn new(demultiplexer: Demultiplexer<Request>) -> RequestReactor {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(handlers::exit::ExitHandler::new(exit_condition.clone()));
        let event_handler = Box::new(handlers::event::Handler::new());

        let mut reactor = RequestReactor {
            demultiplexer: demultiplexer,
            exit_condition: exit_condition,
            handlers: BTreeMap::new()
        };

        reactor.register_handler(exit_handler);
        reactor.register_handler(event_handler);
        reactor
    }
}

impl Reactor for RequestReactor {
    type Event = Request;
    type Handler = RequestHandler;
    fn handle_events(&mut self) {
        while !self.exit_condition.is_active() {
            if let Some(request) = self.demultiplexer.select() {
                let mut handler = self.handlers.get_mut(&request.handler()).unwrap();
                handler.handle_event(request);
            } else {
                break;
            }
        }
    }
    fn register_handler(&mut self, handler: Box<reactor::EventHandler<Self::Event, Handler=RequestHandler>>) {
        self.handlers.insert(handler.handler(), handler);
    }
    fn remove_handler(&mut self, handler: &reactor::EventHandler<Self::Event, Handler=RequestHandler>){}
}

struct Demultiplexer<T>(Receiver<T>);

impl reactor::EventDemultiplexer for Demultiplexer<Request> {
    type Event = Request;
    fn select(&mut self) -> Option<Self::Event> {
        self.0.recv().ok()
    }
}

mod handlers {
    pub mod exit {
        use dispatcher::{Request, RequestHandler};
        use condition::Condition;
        use reactor::EventHandler;

        pub struct ExitHandler{
            condition: Condition,
            stops: u32
        }

        impl ExitHandler {
            pub fn new(condition: Condition) -> ExitHandler {
                ExitHandler {
                    condition: condition,
                    stops: 0
                }
            }
        }

        impl EventHandler<Request> for ExitHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Exit = event {
                    self.stops += 1;

                    if self.stops >= 2 {
                        self.condition.activate();
                    }
                } else {
                    unreachable!("An ExitHandler should only receive Exit events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Exit
            }
        }
    }

    pub mod event {
        use std::collections::BTreeMap;

        use dispatcher::{Request, RequestHandler};
        use reactor::{self, EventHandler, Event};

        use super::timer::TimerEventHandler;
        use self::message::MessageHandler;

        pub struct Handler{
            handlers: BTreeMap<::EventHandler, Box<reactor::EventHandler<::Event, Handler=::EventHandler>>>,
        }

        impl Handler {
            pub fn new() -> Handler {
                let timer_handler = Box::new(TimerEventHandler::new());
                let message_handler = Box::new(MessageHandler::new());
                let mut handler = Handler{
                    handlers: BTreeMap::new()
                };
                handler.register_handler(timer_handler);
                handler.register_handler(message_handler);
                handler
            }

            fn register_handler(&mut self, handler: Box<reactor::EventHandler<::Event, Handler=::EventHandler>>) {
                self.handlers.insert(handler.handler(), handler);
            }
        }

        impl reactor::EventHandler<Request> for Handler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Event(event) = event {
                    println!("Event recvd");
                    if let Some(handler) = self.handlers.get_mut(&event.handler()) {
                        handler.handle_event(event);
                    }
                } else {
                    unreachable!("An Handler should only receive Event events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Event
            }
        }

        pub mod message {
            use std::collections::BTreeMap;

            use dispatcher::{Request, RequestHandler};
            use reactor::{self, EventHandler, Event};

            pub struct MessageHandler {
                handlers: BTreeMap<::EventHandler, Box<reactor::EventHandler<::Event, Handler=::EventHandler>>>,
            }

            impl MessageHandler {
                pub fn new() -> MessageHandler {
                    let mut handler = MessageHandler{
                        handlers: BTreeMap::new()
                    };
                    handler
                }

                fn register_handler(&mut self, handler: Box<reactor::EventHandler<::Event, Handler=::EventHandler>>) {
                    self.handlers.insert(handler.handler(), handler);
                }
            }

            impl reactor::EventHandler<::Event> for MessageHandler {
                type Handler = ::EventHandler;
                fn handle_event(&mut self, event: ::Event) {
                    println!("message event");
                }
                fn handler(&self) -> Self::Handler {
                    ::EventHandler::Message
                }
            }
        }
    }

    mod timer {
        use context::Context;
        use dispatcher::{Request, RequestHandler};
        use EventHandler;
        use Event;
        use reactor;

        pub struct TimerEventHandler {
            contexts: Vec<Context>
        }

        impl TimerEventHandler {
            pub fn new() -> TimerEventHandler {
                TimerEventHandler {
                    contexts: Vec::new()
                }
            }
        }

        impl reactor::EventHandler<Event> for TimerEventHandler {
            type Handler = EventHandler;
            fn handle_event(&mut self, event: Event) {
                println!("timer event");
            }
            fn handler(&self) -> Self::Handler {
                EventHandler::Timer
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate crusty_chip;
extern crate getopts;
extern crate sfml;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use sfml::window::{ContextSettings, Event, Style, VideoMode};
    use std::fs::File;
    use std::io::Read;

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    // TODO: Dunno if this always reads the whole file
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::BLACK);
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<u8> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => if let Some(key) = key_mapping(code) {
                    ch8.release_key(key);
                },
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale((scale as f32, scale as f32));
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<commit_msg>Remove leftover TODO comment<commit_after>extern crate crusty_chip;
extern crate getopts;
extern crate sfml;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use crusty_chip::{decode, VirtualMachine, DISPLAY_HEIGHT, DISPLAY_WIDTH};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use sfml::window::{ContextSettings, Event, Style, VideoMode};
    use std::fs::File;
    use std::io::Read;

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!(
            "File \"{}\" is too big to be a proper CHIP-8 ROM.",
            filename
        );
        return 1;
    }

    let mut data = Vec::new();
    file.read_to_end(&mut data)
        .unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(
        VideoMode::new(
            DISPLAY_WIDTH as u32 * scale,
            DISPLAY_HEIGHT as u32 * scale,
            32,
        ),
        "CrustyChip",
        Style::CLOSE,
        &ctx,
    );

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::BLACK);
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        while let Some(event) = win.poll_event() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<u8> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed {
                    code, ctrl, shift, ..
                } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => if let Some(key) = key_mapping(code) {
                    ch8.release_key(key);
                },
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!(
                "Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                cycles_made,
                ch8.pc(),
                decode(raw_ins),
                raw_ins
            );
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale((scale as f32, scale as f32));
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<|endoftext|>


<commit_before>const VOWELS: [char; 12] = ['a','e','i','o','u','y','A','E','I','O','U','Y'];

// Fairly lax check, which allows initial or trailing periods, or neither,
// and allows double periods (as likely to be typos as to indicate something
// other than initials), but forbids two neighboring non-periods.
fn is_period_separated(word: &str) -> bool {
    let mut chars = word.chars().peekable();
    let mut any_alphabetic = false;

    loop {
        match chars.next() {
            Some(c) => {
                if !any_alphabetic {
                    any_alphabetic = c.is_alphabetic();
                }

                match chars.peek() {
                    Some(nc) => {
                        if (c != '.') && (*nc != '.') {
                            return false;
                        }
                    }
                    None => { break }
                }
            }
            None => { break }
        }
    }

    any_alphabetic
}

pub fn is_initials(word: &str, use_capitalization: bool) -> bool {
    if word.len() == 1 {
        return word.chars().nth(0).unwrap().is_alphabetic();
    }
    else if is_period_separated(word) {
        return true;
    }

    if use_capitalization {
        // The context tells us that capitalization is meaningful in this name,
        // so assume short all-caps strings are initials, and others aren't
        word.len() < 5 && word.chars().all(|c| c.is_uppercase())
    }
    else {
        // The context tells us capitalization isn't meaningful here, so do our
        // best to distinguish initials from short given-names by checking for vowels
        // and non-alphabetic characters
        word.len() < 4 && word.chars().all(|c| !c.is_alphabetic() || !VOWELS.contains(&c))
    }
}
<commit_msg>Minor simplification of is_initials check given earlier check that all words have alphabetical char<commit_after>const VOWELS: [char; 12] = ['a','e','i','o','u','y','A','E','I','O','U','Y'];

// Fairly lax check, which allows initial or trailing periods, or neither,
// and allows double periods (as likely to be typos as to indicate something
// other than initials), but forbids two neighboring non-periods.
fn is_period_separated(word: &str) -> bool {
    let mut chars = word.chars().peekable();

    loop {
        match chars.next() {
            Some(c) => {
                match chars.peek() {
                    Some(nc) => {
                        if (c != '.') && (*nc != '.') {
                            return false;
                        }
                    }
                    None => { break }
                }
            }
            None => { break }
        }
    }

    true
}

pub fn is_initials(word: &str, use_capitalization: bool) -> bool {
    if word.len() == 1 {
        return true;
    }
    else if is_period_separated(word) {
        return true;
    }

    if use_capitalization {
        // The context tells us that capitalization is meaningful in this name,
        // so assume short all-caps strings are initials, and others aren't
        word.len() < 5 && word.chars().all(|c| c.is_uppercase())
    }
    else {
        // The context tells us capitalization isn't meaningful here, so do our
        // best to distinguish initials from short given-names by checking for vowels
        // and non-alphabetic characters
        //
        // TODO We should de-accent before the vowel-check, and/or determine
        // that the string is all-ASCII
        word.len() < 4 && word.chars().all(|c| !c.is_alphabetic() || !VOWELS.contains(&c))
    }
}
<|endoftext|>