<commit_before>//! Awesome compatibility modules

#![cfg_attr(test, deny(bad_style,
       const_err,
       dead_code,
       improper_ctypes,
       legacy_directory_ownership,
       non_shorthand_field_patterns,
       no_mangle_generic_items,
       overflowing_literals,
       path_statements ,
       patterns_in_fns_without_body,
       plugin_as_library,
       private_in_public,
       private_no_mangle_fns,
       private_no_mangle_statics,
       safe_extern_statics,
       unconditional_recursion,
       unions_with_drop_fields,
       unused,
       unused_allocation,
       unused_comparisons,
       unused_parens,
       while_true))]

// Allowed by default
#![cfg_attr(test, deny(missing_docs,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces,
       unused_qualifications))]

#[macro_use]
extern crate bitflags;
extern crate cairo;
extern crate cairo_sys;
extern crate env_logger;
extern crate exec;
#[macro_use]
extern crate clap;
extern crate gdk_pixbuf;
extern crate glib;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate nix;
extern crate libc;
extern crate rlua;
extern crate tempfile;
extern crate xcb;
#[macro_use]
extern crate wayland_client;
extern crate wayland_sys;
extern crate dbus as dbus_rs;

// TODO remove
extern crate wlroots;

#[macro_use]
mod macros;
mod objects;
mod common;
mod wayland_obj;
mod awesome;
mod keygrabber;
mod mousegrabber;
mod root;
mod lua;
mod wayland_protocols;
mod dbus;

use std::{env, mem, path::PathBuf, process::exit, io::{self, Write},
          os::unix::io::RawFd};

use clap::{App, Arg};
use exec::Command;
use rlua::{LightUserData, Lua, Table};
use log::Level;
use nix::sys::signal::{self, SaFlags, SigAction, SigHandler, SigSet};
use xcb::xkb;
use wayland_client::{Display, GlobalManager, EventQueue, GlobalError, ConnectError};
use wayland_client::protocol::{wl_compositor, wl_shm, wl_output, wl_display::RequestsTrait};
use wayland_client::sys::client::wl_display;

// So the C code can link to these Rust functions.
pub use dbus::{dbus_session_refresh, dbus_system_refresh};

use lua::{LUA, NEXT_LUA};
use wayland_protocols::xdg_shell::xdg_wm_base;

const GIT_VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/git-version.txt"));
pub const GLOBAL_SIGNALS: &'static str = "__awesome_global_signals";
pub const XCB_CONNECTION_HANDLE: &'static str = "__xcb_connection";

#[link(name = "wayland_glib_interface", kind = "static")]
extern "C" {
    pub fn wayland_glib_interface_init(display: *mut wl_display,
                                   session_fd: RawFd,
                                   system_fd: RawFd,
                                   wayland_state: *mut libc::c_void);
    pub fn remove_dbus_from_glib();
}

/// The state passed into C to store it during the glib loop.
///
/// It's passed back to us when Awesome needs a refresh so we can
/// construct any Wayland objects.
#[repr(C)]
struct WaylandState {
    pub display: Display,
    pub event_queue: EventQueue
}

/// Called from `wayland_glib_interface.c` after every call back into the
/// wayland event loop.
///
/// This restarts the Lua thread if there is a new one pending
#[no_mangle]
pub extern "C" fn awesome_refresh(wayland_state: *mut libc::c_void) {
    // NOTE
    // This is safe because it's way back up the stack where we can't access it.
    //
    // The moment that stack is accessible this pointer will be lost.
    //
    // The only way it's unsafe is if we destructure `WaylandState`,
    // which we can't do because it's borrowed.
    let _wayland_state = unsafe { &mut *(wayland_state as *mut WaylandState) };
    NEXT_LUA.with(|new_lua_check| {
        if new_lua_check.get() {
            new_lua_check.set(false);
            let awesome = env::args().next().unwrap();
            let args: Vec<_> = env::args().skip(1).collect();
            let err = Command::new(awesome)
                .args(args.as_slice())
                .exec();
            error!("error: {:?}", err);
            panic!("Could not restart Awesome");
        }
    });
}

struct AwesomeVersion;

impl <'a> Into<&'a str> for AwesomeVersion {
    fn into(self) -> &'a str {
        if !GIT_VERSION.is_empty() {
            concat!("Awesome ",
                    env!("CARGO_PKG_VERSION"),
                    " @ ",
                    include_str!(concat!(env!("OUT_DIR"), "/git-version.txt")))
        } else {
            concat!("Awesome ", env!("CARGO_PKG_VERSION"))
        }
    }
}

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(AwesomeVersion)
        .version_short("v")
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("config")
             .short("c")
             .long("config")
             .value_name("FILE")
             .help("configuration file to use")
             .takes_value(true))
        .arg(Arg::with_name("lua lib search")
             .long("search")
             .value_name("DIR")
             .help("add a directory to the library search path")
             .takes_value(true)
             .multiple(true))
        .arg(Arg::with_name("lua syntax check")
             .short("k")
             .long("check")
             .help("check configure file syntax"))
        .arg(Arg::with_name("client transparency")
             .short("a")
             .long("no-argb")
             .help("disable client transparency support"))
        .arg(Arg::with_name("replace wm")
             .short("r")
             .long("replace")
             .help("replace an existing window manager"))
        .get_matches();
    init_logs();
    let sig_action = SigAction::new(SigHandler::Handler(sig_handle),
                                    SaFlags::empty(),
                                    SigSet::empty());
    unsafe {
        signal::sigaction(signal::SIGINT, &sig_action)
            .expect("Could not set SIGINT catcher");
    }
    if matches.is_present("client transparency") {
        unimplemented!()
    }
    if matches.is_present("replace wm") {
        unimplemented!()
    }
    if matches.is_present("lua syntax check") {
        let config = matches.value_of("config");
        match lua::syntax_check(config) {
            Err(Err(err)) => {
                error!("Could not read configuration files");
                error!("{}", err);
                exit(1)
            }
            Err(Ok(lua_error)) => {
                error!("✘ Configuration file syntax error.");
                error!("{}", lua_error);
                exit(1)
            }
            Ok(_) => {
                info!("✔ Configuration file syntax OK.");
                exit(0)
            }
        }
    }
    {
        let lib_paths = matches.values_of("lua lib search")
            .unwrap_or_default()
            .collect::<Vec<_>>();
        lua::init_awesome_libraries(lib_paths.as_slice());
    }
    let (display, event_queue, _globals) = init_wayland();
    let (session_fd, system_fd) = dbus::connect()
        .expect("Could not set up dbus connection");
    init_glib(display, event_queue, session_fd, system_fd);
    lua::run_awesome(matches);
}

fn init_wayland() -> (Display, EventQueue, GlobalManager) {
    let (display, mut event_queue) = match Display::connect_to_env() {
        Ok(res) => res,
        Err(err) => {
            match err {
                ConnectError::NoWaylandLib =>
                    error!("Could not find Wayland library, is it installed and in PATH?"),
                ConnectError::NoCompositorListening => {
                    error!("Could not connect to Wayland server. Is it running?");
                    error!("WAYLAND_DISPLAY={}", env::var("WAYLAND_DISPLAY")
                           .unwrap_or_else(|_| "".into()));
                },
                ConnectError::InvalidName =>
                    error!("Invalid socket name provided")
            }
            exit(1);
        }
    };
    let globals = GlobalManager::new_with_cb(
        display.get_registry().unwrap(),
        global_filter!(
            [
                wl_output::WlOutput,
                wayland_obj::WL_OUTPUT_VERSION,
                wayland_obj::Output::new
            ],
            [
                wl_compositor::WlCompositor,
                wayland_obj::WL_COMPOSITOR_VERSION,
                wayland_obj::wl_compositor_init
            ],
            [
                wl_shm::WlShm,
                wayland_obj::WL_SHM_VERSION,
                wayland_obj::wl_shm_init
            ]
        ),
    );
    event_queue.sync_roundtrip().unwrap();
    let xwm_base_proxy = match globals.instantiate_exact::
    <xdg_wm_base::XdgWmBase>(wayland_obj::XDG_WM_BASE_VERSION) {
        Err(GlobalError::Missing) => {
            error!("Missing xdg_wm_base global (version {})",
                   wayland_obj::XDG_WM_BASE_VERSION);
            error!("Your compositor doesn't support the xdg shell protocol");
            error!("This protocol is necessary for Awesome to function");
            exit(1);
        },
        Err(GlobalError::VersionTooLow(version)) => {
            error!("Got xdg_wm_base version {}, expected version {}",
                   version, wayland_obj::XDG_WM_BASE_VERSION);
            error!("Your compositor doesn't support version {} \
                    of the xdg shell protocol", wayland_obj::XDG_WM_BASE_VERSION);
            error!("Ensure your compositor is up to date");
            exit(1);
        },
        Ok(proxy) => Ok(proxy)
    };
    wayland_obj::xdg_shell_init(xwm_base_proxy, ());
    event_queue.sync_roundtrip().unwrap();
    (display, event_queue, globals)
}

/// Sets up the glib main loop to call back into Rust whenever the
/// Wayland triggers an event.
///
/// Note this doesn't actually start it yet, see `lua::run_awesome` for that.
fn init_glib(display: Display,
             event_queue: EventQueue,
             session_fd: RawFd,
             system_fd: RawFd) {
    let mut wayland_state = WaylandState { display, event_queue };
    let display_ptr = wayland_state.display.c_ptr() as *mut wl_display;
    unsafe {
        wayland_glib_interface_init(display_ptr,
                                    session_fd,
                                    system_fd,
                                    &mut wayland_state as *mut _ as _);
        ::std::mem::forget(wayland_state);
    }
}

fn setup_awesome_path(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    let globals = lua.globals();
    let package: Table = globals.get("package")?;
    let mut path = package.get::<_, String>("path")?;
    let mut cpath = package.get::<_, String>("cpath")?;

    for lib_path in lib_paths {
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua", lib_path));
        cpath.push_str(&format!(";{}/?.so", lib_path));
    }

    for mut xdg_data_path in
        env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".into())
                                 .split(':')
                                 .map(PathBuf::from)
    {
        xdg_data_path.push("awesome/lib");
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua",
                               xdg_data_path.as_os_str().to_string_lossy()));
        cpath.push_str(&format!(";{}/?.so", xdg_data_path.into_os_string().to_string_lossy()));
    }

    for mut xdg_config_path in env::var("XDG_CONFIG_DIRS").unwrap_or("/etc/xdg".into())
                                                          .split(':')
                                                          .map(PathBuf::from)
    {
        xdg_config_path.push("awesome");
        cpath.push_str(&format!(";{}/?.so",
                                xdg_config_path.into_os_string().to_string_lossy()));
    }

    package.set("path", path)?;
    package.set("cpath", cpath)?;

    Ok(())
}

/// Set up global signals value
///
/// We need to store this in Lua, because this make it safer to use.
fn setup_global_signals(lua: &Lua) -> rlua::Result<()> {
    lua.set_named_registry_value(GLOBAL_SIGNALS, lua.create_table()?)
}

/// Sets up the xcb connection and stores it in Lua (for us to access it later)
fn setup_xcb_connection(lua: &Lua) -> rlua::Result<()> {
    let con = match xcb::Connection::connect(None) {
        Err(err) => {
            error!("Way Cooler requires XWayland in order to function");
            error!("However, xcb could not connect to it. Is it running?");
            error!("{:?}", err);
            panic!("Could not connect to XWayland instance");
        }
        Ok(con) => con.0
    };
    // Tell xcb we are using the xkb extension
    match xkb::use_extension(&con, 1, 0).get_reply() {
        Ok(r) => {
            if !r.supported() {
                panic!("xkb-1.0 is not supported");
            }
        }
        Err(err) => {
            panic!("Could not get xkb extension supported version {:?}", err);
        }
    }
    lua.set_named_registry_value(XCB_CONNECTION_HANDLE,
                                  LightUserData(con.get_raw_conn() as _))?;
    mem::forget(con);
    Ok(())
}

/// Formats the log strings properly
fn log_format(buf: &mut env_logger::fmt::Formatter, record: &log::Record) -> Result<(), io::Error> {
    let color = match record.level() {
        Level::Info => "",
        Level::Trace => "\x1B[37m",
        Level::Debug => "\x1B[44m",
        Level::Warn => "\x1B[33m",
        Level::Error => "\x1B[31m"
    };
    let mut module_path = record.module_path().unwrap_or("?");
    if let Some(index) = module_path.find("way_cooler::") {
        let index = index + "way_cooler::".len();
        module_path = &module_path[index..];
    }
    writeln!(buf, "{} {} [{}] \x1B[37m{}:{}\x1B[0m{0} {} \x1B[0m",
            color,
            record.level(),
            module_path,
            record.file().unwrap_or("?"),
            record.line().unwrap_or(0),
            record.args())
}

fn init_logs() {
    let env = env_logger::Env::default()
        .filter_or("WAY_COOLER_LOG", "trace");
    env_logger::Builder::from_env(env)
        .format(log_format)
        .init();
    info!("Logger initialized");
}

/// Handler for SIGINT signal
extern "C" fn sig_handle(_: nix::libc::c_int) {
    lua::terminate();
    exit(130);
}
<commit_msg>Removed unused_qualifications<commit_after>//! Awesome compatibility modules

#![cfg_attr(test, deny(bad_style,
       const_err,
       dead_code,
       improper_ctypes,
       legacy_directory_ownership,
       non_shorthand_field_patterns,
       no_mangle_generic_items,
       overflowing_literals,
       path_statements ,
       patterns_in_fns_without_body,
       plugin_as_library,
       private_in_public,
       private_no_mangle_fns,
       private_no_mangle_statics,
       safe_extern_statics,
       unconditional_recursion,
       unions_with_drop_fields,
       unused,
       unused_allocation,
       unused_comparisons,
       unused_parens,
       while_true))]

// Allowed by default
#![cfg_attr(test, deny(missing_docs,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces))]

#[macro_use]
extern crate bitflags;
extern crate cairo;
extern crate cairo_sys;
extern crate env_logger;
extern crate exec;
#[macro_use]
extern crate clap;
extern crate gdk_pixbuf;
extern crate glib;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate nix;
extern crate libc;
extern crate rlua;
extern crate tempfile;
extern crate xcb;
#[macro_use]
extern crate wayland_client;
extern crate wayland_sys;
extern crate dbus as dbus_rs;

// TODO remove
extern crate wlroots;

#[macro_use]
mod macros;
mod objects;
mod common;
mod wayland_obj;
mod awesome;
mod keygrabber;
mod mousegrabber;
mod root;
mod lua;
mod wayland_protocols;
mod dbus;

use std::{env, mem, path::PathBuf, process::exit, io::{self, Write},
          os::unix::io::RawFd};

use clap::{App, Arg};
use exec::Command;
use rlua::{LightUserData, Lua, Table};
use log::Level;
use nix::sys::signal::{self, SaFlags, SigAction, SigHandler, SigSet};
use xcb::xkb;
use wayland_client::{Display, GlobalManager, EventQueue, GlobalError, ConnectError};
use wayland_client::protocol::{wl_compositor, wl_shm, wl_output, wl_display::RequestsTrait};
use wayland_client::sys::client::wl_display;

// So the C code can link to these Rust functions.
pub use dbus::{dbus_session_refresh, dbus_system_refresh};

use lua::{LUA, NEXT_LUA};
use wayland_protocols::xdg_shell::xdg_wm_base;

const GIT_VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/git-version.txt"));
pub const GLOBAL_SIGNALS: &'static str = "__awesome_global_signals";
pub const XCB_CONNECTION_HANDLE: &'static str = "__xcb_connection";

#[link(name = "wayland_glib_interface", kind = "static")]
extern "C" {
    pub fn wayland_glib_interface_init(display: *mut wl_display,
                                   session_fd: RawFd,
                                   system_fd: RawFd,
                                   wayland_state: *mut libc::c_void);
    pub fn remove_dbus_from_glib();
}

/// The state passed into C to store it during the glib loop.
///
/// It's passed back to us when Awesome needs a refresh so we can
/// construct any Wayland objects.
#[repr(C)]
struct WaylandState {
    pub display: Display,
    pub event_queue: EventQueue
}

/// Called from `wayland_glib_interface.c` after every call back into the
/// wayland event loop.
///
/// This restarts the Lua thread if there is a new one pending
#[no_mangle]
pub extern "C" fn awesome_refresh(wayland_state: *mut libc::c_void) {
    // NOTE
    // This is safe because it's way back up the stack where we can't access it.
    //
    // The moment that stack is accessible this pointer will be lost.
    //
    // The only way it's unsafe is if we destructure `WaylandState`,
    // which we can't do because it's borrowed.
    let _wayland_state = unsafe { &mut *(wayland_state as *mut WaylandState) };
    NEXT_LUA.with(|new_lua_check| {
        if new_lua_check.get() {
            new_lua_check.set(false);
            let awesome = env::args().next().unwrap();
            let args: Vec<_> = env::args().skip(1).collect();
            let err = Command::new(awesome)
                .args(args.as_slice())
                .exec();
            error!("error: {:?}", err);
            panic!("Could not restart Awesome");
        }
    });
}

struct AwesomeVersion;

impl <'a> Into<&'a str> for AwesomeVersion {
    fn into(self) -> &'a str {
        if !GIT_VERSION.is_empty() {
            concat!("Awesome ",
                    env!("CARGO_PKG_VERSION"),
                    " @ ",
                    include_str!(concat!(env!("OUT_DIR"), "/git-version.txt")))
        } else {
            concat!("Awesome ", env!("CARGO_PKG_VERSION"))
        }
    }
}

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(AwesomeVersion)
        .version_short("v")
        .author(crate_authors!("\n"))
        .arg(Arg::with_name("config")
             .short("c")
             .long("config")
             .value_name("FILE")
             .help("configuration file to use")
             .takes_value(true))
        .arg(Arg::with_name("lua lib search")
             .long("search")
             .value_name("DIR")
             .help("add a directory to the library search path")
             .takes_value(true)
             .multiple(true))
        .arg(Arg::with_name("lua syntax check")
             .short("k")
             .long("check")
             .help("check configure file syntax"))
        .arg(Arg::with_name("client transparency")
             .short("a")
             .long("no-argb")
             .help("disable client transparency support"))
        .arg(Arg::with_name("replace wm")
             .short("r")
             .long("replace")
             .help("replace an existing window manager"))
        .get_matches();
    init_logs();
    let sig_action = SigAction::new(SigHandler::Handler(sig_handle),
                                    SaFlags::empty(),
                                    SigSet::empty());
    unsafe {
        signal::sigaction(signal::SIGINT, &sig_action)
            .expect("Could not set SIGINT catcher");
    }
    if matches.is_present("client transparency") {
        unimplemented!()
    }
    if matches.is_present("replace wm") {
        unimplemented!()
    }
    if matches.is_present("lua syntax check") {
        let config = matches.value_of("config");
        match lua::syntax_check(config) {
            Err(Err(err)) => {
                error!("Could not read configuration files");
                error!("{}", err);
                exit(1)
            }
            Err(Ok(lua_error)) => {
                error!("✘ Configuration file syntax error.");
                error!("{}", lua_error);
                exit(1)
            }
            Ok(_) => {
                info!("✔ Configuration file syntax OK.");
                exit(0)
            }
        }
    }
    {
        let lib_paths = matches.values_of("lua lib search")
            .unwrap_or_default()
            .collect::<Vec<_>>();
        lua::init_awesome_libraries(lib_paths.as_slice());
    }
    let (display, event_queue, _globals) = init_wayland();
    let (session_fd, system_fd) = dbus::connect()
        .expect("Could not set up dbus connection");
    init_glib(display, event_queue, session_fd, system_fd);
    lua::run_awesome(matches);
}

fn init_wayland() -> (Display, EventQueue, GlobalManager) {
    let (display, mut event_queue) = match Display::connect_to_env() {
        Ok(res) => res,
        Err(err) => {
            match err {
                ConnectError::NoWaylandLib =>
                    error!("Could not find Wayland library, is it installed and in PATH?"),
                ConnectError::NoCompositorListening => {
                    error!("Could not connect to Wayland server. Is it running?");
                    error!("WAYLAND_DISPLAY={}", env::var("WAYLAND_DISPLAY")
                           .unwrap_or_else(|_| "".into()));
                },
                ConnectError::InvalidName =>
                    error!("Invalid socket name provided")
            }
            exit(1);
        }
    };
    let globals = GlobalManager::new_with_cb(
        display.get_registry().unwrap(),
        global_filter!(
            [
                wl_output::WlOutput,
                wayland_obj::WL_OUTPUT_VERSION,
                wayland_obj::Output::new
            ],
            [
                wl_compositor::WlCompositor,
                wayland_obj::WL_COMPOSITOR_VERSION,
                wayland_obj::wl_compositor_init
            ],
            [
                wl_shm::WlShm,
                wayland_obj::WL_SHM_VERSION,
                wayland_obj::wl_shm_init
            ]
        ),
    );
    event_queue.sync_roundtrip().unwrap();
    let xwm_base_proxy = match globals.instantiate_exact::
    <xdg_wm_base::XdgWmBase>(wayland_obj::XDG_WM_BASE_VERSION) {
        Err(GlobalError::Missing) => {
            error!("Missing xdg_wm_base global (version {})",
                   wayland_obj::XDG_WM_BASE_VERSION);
            error!("Your compositor doesn't support the xdg shell protocol");
            error!("This protocol is necessary for Awesome to function");
            exit(1);
        },
        Err(GlobalError::VersionTooLow(version)) => {
            error!("Got xdg_wm_base version {}, expected version {}",
                   version, wayland_obj::XDG_WM_BASE_VERSION);
            error!("Your compositor doesn't support version {} \
                    of the xdg shell protocol", wayland_obj::XDG_WM_BASE_VERSION);
            error!("Ensure your compositor is up to date");
            exit(1);
        },
        Ok(proxy) => Ok(proxy)
    };
    wayland_obj::xdg_shell_init(xwm_base_proxy, ());
    event_queue.sync_roundtrip().unwrap();
    (display, event_queue, globals)
}

/// Sets up the glib main loop to call back into Rust whenever the
/// Wayland triggers an event.
///
/// Note this doesn't actually start it yet, see `lua::run_awesome` for that.
fn init_glib(display: Display,
             event_queue: EventQueue,
             session_fd: RawFd,
             system_fd: RawFd) {
    let mut wayland_state = WaylandState { display, event_queue };
    let display_ptr = wayland_state.display.c_ptr() as *mut wl_display;
    unsafe {
        wayland_glib_interface_init(display_ptr,
                                    session_fd,
                                    system_fd,
                                    &mut wayland_state as *mut _ as _);
        ::std::mem::forget(wayland_state);
    }
}

fn setup_awesome_path(lua: &Lua, lib_paths: &[&str]) -> rlua::Result<()> {
    let globals = lua.globals();
    let package: Table = globals.get("package")?;
    let mut path = package.get::<_, String>("path")?;
    let mut cpath = package.get::<_, String>("cpath")?;

    for lib_path in lib_paths {
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua", lib_path));
        cpath.push_str(&format!(";{}/?.so", lib_path));
    }

    for mut xdg_data_path in
        env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share:/usr/share".into())
                                 .split(':')
                                 .map(PathBuf::from)
    {
        xdg_data_path.push("awesome/lib");
        path.push_str(&format!(";{0}/?.lua;{0}/?/init.lua",
                               xdg_data_path.as_os_str().to_string_lossy()));
        cpath.push_str(&format!(";{}/?.so", xdg_data_path.into_os_string().to_string_lossy()));
    }

    for mut xdg_config_path in env::var("XDG_CONFIG_DIRS").unwrap_or("/etc/xdg".into())
                                                          .split(':')
                                                          .map(PathBuf::from)
    {
        xdg_config_path.push("awesome");
        cpath.push_str(&format!(";{}/?.so",
                                xdg_config_path.into_os_string().to_string_lossy()));
    }

    package.set("path", path)?;
    package.set("cpath", cpath)?;

    Ok(())
}

/// Set up global signals value
///
/// We need to store this in Lua, because this make it safer to use.
fn setup_global_signals(lua: &Lua) -> rlua::Result<()> {
    lua.set_named_registry_value(GLOBAL_SIGNALS, lua.create_table()?)
}

/// Sets up the xcb connection and stores it in Lua (for us to access it later)
fn setup_xcb_connection(lua: &Lua) -> rlua::Result<()> {
    let con = match xcb::Connection::connect(None) {
        Err(err) => {
            error!("Way Cooler requires XWayland in order to function");
            error!("However, xcb could not connect to it. Is it running?");
            error!("{:?}", err);
            panic!("Could not connect to XWayland instance");
        }
        Ok(con) => con.0
    };
    // Tell xcb we are using the xkb extension
    match xkb::use_extension(&con, 1, 0).get_reply() {
        Ok(r) => {
            if !r.supported() {
                panic!("xkb-1.0 is not supported");
            }
        }
        Err(err) => {
            panic!("Could not get xkb extension supported version {:?}", err);
        }
    }
    lua.set_named_registry_value(XCB_CONNECTION_HANDLE,
                                  LightUserData(con.get_raw_conn() as _))?;
    mem::forget(con);
    Ok(())
}

/// Formats the log strings properly
fn log_format(buf: &mut env_logger::fmt::Formatter, record: &log::Record) -> Result<(), io::Error> {
    let color = match record.level() {
        Level::Info => "",
        Level::Trace => "\x1B[37m",
        Level::Debug => "\x1B[44m",
        Level::Warn => "\x1B[33m",
        Level::Error => "\x1B[31m"
    };
    let mut module_path = record.module_path().unwrap_or("?");
    if let Some(index) = module_path.find("way_cooler::") {
        let index = index + "way_cooler::".len();
        module_path = &module_path[index..];
    }
    writeln!(buf, "{} {} [{}] \x1B[37m{}:{}\x1B[0m{0} {} \x1B[0m",
            color,
            record.level(),
            module_path,
            record.file().unwrap_or("?"),
            record.line().unwrap_or(0),
            record.args())
}

fn init_logs() {
    let env = env_logger::Env::default()
        .filter_or("WAY_COOLER_LOG", "trace");
    env_logger::Builder::from_env(env)
        .format(log_format)
        .init();
    info!("Logger initialized");
}

/// Handler for SIGINT signal
extern "C" fn sig_handle(_: nix::libc::c_int) {
    lua::terminate();
    exit(130);
}
<|endoftext|>


<commit_before>
/// Implemented by contexts who can add color.
pub trait AddColor<'a, T> {
    /// Add color with alpha channel.
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> T;

    /// Adds color with alpha channel set to 1.0.
    #[inline(always)]
    fn rgb(&'a self, r: f32, g: f32, b: f32) -> T {
        self.rgba(r, g, b, 1.0)
    }

    /// Add color [r, g, b, a].
    #[inline(always)]
    fn color(&'a self, color: [f32, ..4]) -> T {
        self.rgba(color[0], color[1], color[2], color[3])
    }

    /// Adds a gray color.
    ///
    /// `0.0` is black and `1.0` is white.
    #[inline(always)]
    fn grey(&'a self, f: f32) -> T {
        self.rgba(f, f, f, 1.0)
    }
}

<commit_msg>Added `alpha` to `AddColor`<commit_after>
/// Implemented by contexts who can add color.
pub trait AddColor<'a, T> {
    /// Add color with alpha channel.
    fn rgba(&'a self, r: f32, g: f32, b: f32, a: f32) -> T;

    /// Adds color with alpha channel set to 1.0.
    #[inline(always)]
    fn rgb(&'a self, r: f32, g: f32, b: f32) -> T {
        self.rgba(r, g, b, 1.0)
    }

    /// Add color [r, g, b, a].
    #[inline(always)]
    fn color(&'a self, color: [f32, ..4]) -> T {
        self.rgba(color[0], color[1], color[2], color[3])
    }

    /// Adds a gray color.
    ///
    /// `0.0` is black and `1.0` is white.
    #[inline(always)]
    fn grey(&'a self, f: f32) -> T {
        self.rgba(f, f, f, 1.0)
    }

    /// Adds a white semi-transparent color.
    ///
    /// `0.0` is fully transparent and `1.0` is fully opaque.
    #[inline(always)]
    fn alpha(&'a self, f: f32) -> T {
        self.rgba(1.0, 1.0, 1.0, f)
    }
}

<|endoftext|>


<commit_before>//! Blocks are the subunits of each ship in PSO. Chances are, if you're running a
//! private server, you don't need more than one block per ship. But we'll
//! support having as many as you want.

use std::sync::mpsc::Receiver;
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use mio::Sender;
use mio::tcp::TcpListener;

use rand::random;

use psomsg::bb::*;

use psodata::battleparam::BattleParamTables;

use ::shipgate::client::SgSender;
use ::services::message::NetMsg;
use ::shipgate::client::callbacks::SgCbMgr;
use ::services::{ServiceMsg, Service, ServiceType};
use ::loop_handler::LoopMsg;

pub mod client;
pub mod handler;
pub mod lobbyhandler;
pub mod partyhandler;

use self::handler::BlockHandler;
use self::client::ClientState;
use self::lobbyhandler::Lobby;
use self::partyhandler::Party;

pub struct BlockService {
    receiver: Receiver<ServiceMsg>,
    sender: Sender<LoopMsg>,
    sg_sender: SgCbMgr<BlockHandler>,
    clients: Rc<RefCell<HashMap<usize, Rc<RefCell<ClientState>>>>>,
    lobbies: Rc<RefCell<Vec<Lobby>>>,
    parties: Rc<RefCell<Vec<Party>>>,
    block_num: u16,
    event: u16,
    battle_params: Arc<BattleParamTables>
}

impl BlockService {
    pub fn spawn(bind: &SocketAddr,
                 sender: Sender<LoopMsg>,
                 sg_sender: &SgSender,
                 key_table: Arc<Vec<u32>>,
                 block_num: u16,
                 event: u16,
                 battle_params: Arc<BattleParamTables>) -> Service {
        let (tx, rx) = channel();

        let listener = TcpListener::bind(bind).expect("Couldn't create tcplistener");

        let sg_sender = sg_sender.clone_with(tx.clone());

        thread::spawn(move|| {
            let d = BlockService {
                receiver: rx,
                sender: sender,
                sg_sender: sg_sender.into(),
                clients: Default::default(),
                lobbies: Default::default(),
                parties: Default::default(),
                block_num: block_num,
                event: event,
                battle_params: battle_params
            };
            d.run();
        });

        Service::new(listener, tx, ServiceType::Bb(key_table))
    }

    fn make_handler(&self, client_id: usize) -> BlockHandler {
        BlockHandler::new(
            self.sender.clone(),
            self.sg_sender.clone(),
            client_id,
            self.clients.clone(),
            self.lobbies.clone(),
            self.parties.clone(),
            self.battle_params.clone()
        )
    }

    fn init_lobbies(&mut self) {
        let ref mut l = self.lobbies.borrow_mut();
        for i in 0..15 {
            let lobby = Lobby::new(i, self.block_num, self.event);
            l.push(lobby);
        }
        info!("Initialized 15 lobbies with event {}", self.event);
    }

    pub fn run(mut self) {
        // Initialize lobbies
        self.init_lobbies();

        info!("Block service running");
        loop {
            let msg = match self.receiver.recv() {
                Ok(m) => m,
                Err(_) => return
            };

            match msg {
                ServiceMsg::ClientConnected((_addr, id)) => {
                    info!("Client {} connected to block", id);
                    let sk = vec![random(); 48];
                    let ck = vec![random(); 48];
                    self.sender.send((id, Message::BbWelcome(0, BbWelcome(sk, ck))).into()).unwrap();

                    // Add to clients table
                    let cs = Rc::new(RefCell::new(ClientState::default()));
                    {
                        let ref mut borrow = cs.borrow_mut();
                        borrow.connection_id = id;
                    }
                    {self.clients.borrow_mut().insert(id, cs);}
                },
                ServiceMsg::ClientDisconnected(id) => {
                    info!("Client {} disconnected from block", id);

                    let mut h = self.make_handler(id);

                    // First, we need to check if they're in a lobby or party.
                    {
                        let lr = self.lobbies.clone();
                        let ref mut lobbies = lr.borrow_mut();
                        for l in lobbies.iter_mut() {
                            if l.has_player(id) {
                                l.remove_player(&mut h, id).unwrap();
                                break
                            }
                        }
                    }

                    drop(h);

                    {self.clients.borrow_mut().remove(&id);}
                },
                ServiceMsg::ClientSaid(id, NetMsg::Bb(m)) => {
                    let mut h = self.make_handler(id);
                    match m {
                        Message::BbLogin(_, m) => { h.bb_login(m) },
                        Message::BbCharDat(_, m) => { h.bb_char_dat(m) },
                        Message::BbChat(_, m) => { h.bb_chat(m) },
                        Message::BbCreateGame(_, m) => { h.bb_create_game(m) },
                        Message::BbSubCmd60(_, m) => { h.bb_subcmd_60(m) },
                        Message::BbSubCmd62(_, m) => { h.bb_subcmd_62(m) },
                        Message::BbSubCmd6C(_, m) => { h.bb_subcmd_6c(m) },
                        Message::BbSubCmd6D(_, m) => { h.bb_subcmd_6d(m) },
                        Message::LobbyChange(_, m) => { h.bb_lobby_change(m) },
                        Message::BbGameName(_, _) => { h.bb_game_name() },
                        Message::BbGameList(_, _) => { h.bb_game_list() },
                        Message::BbPlayerLeaveGame(_, m) => { h.bb_player_leave_game(m) },
                        a => {
                            info!("{:?}", a);
                        }
                    }
                },
                ServiceMsg::ShipGateMsg(m) => {
                    let req = m.get_response_key();
                    debug!("Shipgate Request {}: Response received", req);
                    let cb;
                    {
                        cb = self.sg_sender.cb_for_req(req)
                    }

                    match cb {
                        Some((client, mut c)) => c(self.make_handler(client), m),
                        None => warn!("Got a SG request response for an unexpected request ID {}.", req)
                    }
                }
                _ => unreachable!()
            }
        }
    }
}
<commit_msg>Remove player from party if they disconnect.<commit_after>//! Blocks are the subunits of each ship in PSO. Chances are, if you're running a
//! private server, you don't need more than one block per ship. But we'll
//! support having as many as you want.

use std::sync::mpsc::Receiver;
use std::sync::mpsc::channel;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::sync::Arc;
use std::thread;

use mio::Sender;
use mio::tcp::TcpListener;

use rand::random;

use psomsg::bb::*;

use psodata::battleparam::BattleParamTables;

use ::shipgate::client::SgSender;
use ::services::message::NetMsg;
use ::shipgate::client::callbacks::SgCbMgr;
use ::services::{ServiceMsg, Service, ServiceType};
use ::loop_handler::LoopMsg;

pub mod client;
pub mod handler;
pub mod lobbyhandler;
pub mod partyhandler;

use self::handler::BlockHandler;
use self::client::ClientState;
use self::lobbyhandler::Lobby;
use self::partyhandler::Party;

pub struct BlockService {
    receiver: Receiver<ServiceMsg>,
    sender: Sender<LoopMsg>,
    sg_sender: SgCbMgr<BlockHandler>,
    clients: Rc<RefCell<HashMap<usize, Rc<RefCell<ClientState>>>>>,
    lobbies: Rc<RefCell<Vec<Lobby>>>,
    parties: Rc<RefCell<Vec<Party>>>,
    block_num: u16,
    event: u16,
    battle_params: Arc<BattleParamTables>
}

impl BlockService {
    pub fn spawn(bind: &SocketAddr,
                 sender: Sender<LoopMsg>,
                 sg_sender: &SgSender,
                 key_table: Arc<Vec<u32>>,
                 block_num: u16,
                 event: u16,
                 battle_params: Arc<BattleParamTables>) -> Service {
        let (tx, rx) = channel();

        let listener = TcpListener::bind(bind).expect("Couldn't create tcplistener");

        let sg_sender = sg_sender.clone_with(tx.clone());

        thread::spawn(move|| {
            let d = BlockService {
                receiver: rx,
                sender: sender,
                sg_sender: sg_sender.into(),
                clients: Default::default(),
                lobbies: Default::default(),
                parties: Default::default(),
                block_num: block_num,
                event: event,
                battle_params: battle_params
            };
            d.run();
        });

        Service::new(listener, tx, ServiceType::Bb(key_table))
    }

    fn make_handler(&self, client_id: usize) -> BlockHandler {
        BlockHandler::new(
            self.sender.clone(),
            self.sg_sender.clone(),
            client_id,
            self.clients.clone(),
            self.lobbies.clone(),
            self.parties.clone(),
            self.battle_params.clone()
        )
    }

    fn init_lobbies(&mut self) {
        let ref mut l = self.lobbies.borrow_mut();
        for i in 0..15 {
            let lobby = Lobby::new(i, self.block_num, self.event);
            l.push(lobby);
        }
        info!("Initialized 15 lobbies with event {}", self.event);
    }

    pub fn run(mut self) {
        // Initialize lobbies
        self.init_lobbies();

        info!("Block service running");
        loop {
            let msg = match self.receiver.recv() {
                Ok(m) => m,
                Err(_) => return
            };

            match msg {
                ServiceMsg::ClientConnected((_addr, id)) => {
                    info!("Client {} connected to block", id);
                    let sk = vec![random(); 48];
                    let ck = vec![random(); 48];
                    self.sender.send((id, Message::BbWelcome(0, BbWelcome(sk, ck))).into()).unwrap();

                    // Add to clients table
                    let cs = Rc::new(RefCell::new(ClientState::default()));
                    {
                        let ref mut borrow = cs.borrow_mut();
                        borrow.connection_id = id;
                    }
                    {self.clients.borrow_mut().insert(id, cs);}
                },
                ServiceMsg::ClientDisconnected(id) => {
                    info!("Client {} disconnected from block", id);

                    let mut h = self.make_handler(id);

                    // First, we need to check if they're in a lobby or party.
                    {
                        let lr = self.lobbies.clone();
                        let ref mut lobbies = lr.borrow_mut();
                        for l in lobbies.iter_mut() {
                            if l.has_player(id) {
                                l.remove_player(&mut h, id).unwrap();
                                break
                            }
                        }
                    }
                    {
                        let pr = self.parties.clone();
                        let ref mut parties = pr.borrow_mut();
                        let mut party_index = 0;
                        let mut remove = false;
                        for (i, p) in parties.iter_mut().enumerate() {
                            if p.has_player(id) {
                                remove = p.remove_player(&mut h, id).unwrap();
                                party_index = i;
                                break
                            }
                        }
                        if remove {
                            parties.remove(party_index);
                        }
                    }

                    drop(h);

                    {self.clients.borrow_mut().remove(&id);}
                },
                ServiceMsg::ClientSaid(id, NetMsg::Bb(m)) => {
                    let mut h = self.make_handler(id);
                    match m {
                        Message::BbLogin(_, m) => { h.bb_login(m) },
                        Message::BbCharDat(_, m) => { h.bb_char_dat(m) },
                        Message::BbChat(_, m) => { h.bb_chat(m) },
                        Message::BbCreateGame(_, m) => { h.bb_create_game(m) },
                        Message::BbSubCmd60(_, m) => { h.bb_subcmd_60(m) },
                        Message::BbSubCmd62(_, m) => { h.bb_subcmd_62(m) },
                        Message::BbSubCmd6C(_, m) => { h.bb_subcmd_6c(m) },
                        Message::BbSubCmd6D(_, m) => { h.bb_subcmd_6d(m) },
                        Message::LobbyChange(_, m) => { h.bb_lobby_change(m) },
                        Message::BbGameName(_, _) => { h.bb_game_name() },
                        Message::BbGameList(_, _) => { h.bb_game_list() },
                        Message::BbPlayerLeaveGame(_, m) => { h.bb_player_leave_game(m) },
                        a => {
                            info!("{:?}", a);
                        }
                    }
                },
                ServiceMsg::ShipGateMsg(m) => {
                    let req = m.get_response_key();
                    debug!("Shipgate Request {}: Response received", req);
                    let cb;
                    {
                        cb = self.sg_sender.cb_for_req(req)
                    }

                    match cb {
                        Some((client, mut c)) => c(self.make_handler(client), m),
                        None => warn!("Got a SG request response for an unexpected request ID {}.", req)
                    }
                }
                _ => unreachable!()
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt;

use bytes::Bytes;
use futures::sync::{mpsc, oneshot};
use futures::{Async, Future, Poll, Stream, Sink, AsyncSink, StartSend};
use h2;
use http::HeaderMap;

use common::Never;
use super::internal::{FullDataArg, FullDataRet};
use super::{Chunk, Payload};
use upgrade::OnUpgrade;

type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;

/// A stream of `Chunk`s, used when receiving bodies.
///
/// A good default `Payload` to use in many applications.
///
/// Also implements `futures::Stream`, so stream combinators may be used.
#[must_use = "streams do nothing unless polled"]
pub struct Body {
    kind: Kind,
    /// Keep the extra bits in an `Option<Box<Extra>>`, so that
    /// Body stays small in the common case (no extras needed).
    extra: Option<Box<Extra>>,
}

enum Kind {
    Once(Option<Chunk>),
    Chan {
        content_length: Option<u64>,
        abort_rx: oneshot::Receiver<()>,
        rx: mpsc::Receiver<Result<Chunk, ::Error>>,
    },
    H2 {
        content_length: Option<u64>,
        recv: h2::RecvStream,
    },
    Wrapped(Box<Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send>),
}

struct Extra {
    /// Allow the client to pass a future to delay the `Body` from returning
    /// EOF. This allows the `Client` to try to put the idle connection
    /// back into the pool before the body is "finished".
    ///
    /// The reason for this is so that creating a new request after finishing
    /// streaming the body of a response could sometimes result in creating
    /// a brand new connection, since the pool didn't know about the idle
    /// connection yet.
    delayed_eof: Option<DelayEof>,
    on_upgrade: OnUpgrade,
}

type DelayEofUntil = oneshot::Receiver<Never>;

enum DelayEof {
    /// Initial state, stream hasn't seen EOF yet.
    NotEof(DelayEofUntil),
    /// Transitions to this state once we've seen `poll` try to
    /// return EOF (`None`). This future is then polled, and
    /// when it completes, the Body finally returns EOF (`None`).
    Eof(DelayEofUntil),
}

/// A sender half used with `Body::channel()`.
///
/// Useful when wanting to stream chunks from another thread. See
/// [`Body::channel`](Body::channel) for more.
#[must_use = "Sender does nothing unless sent on"]
#[derive(Debug)]
pub struct Sender {
    abort_tx: oneshot::Sender<()>,
    tx: BodySender,
}

impl Body {
    /// Create an empty `Body` stream.
    ///
    /// # Example
    ///
    /// ```
    /// use hyper::{Body, Request};
    ///
    /// // create a `GET /` request
    /// let get = Request::new(Body::empty());
    /// ```
    #[inline]
    pub fn empty() -> Body {
        Body::new(Kind::Once(None))
    }

    /// Create a `Body` stream with an associated sender half.
    ///
    /// Useful when wanting to stream chunks from another thread.
    #[inline]
    pub fn channel() -> (Sender, Body) {
        Self::new_channel(None)
    }

    pub(crate) fn new_channel(content_length: Option<u64>) -> (Sender, Body) {
        let (tx, rx) = mpsc::channel(0);
        let (abort_tx, abort_rx) = oneshot::channel();

        let tx = Sender {
            abort_tx: abort_tx,
            tx: tx,
        };
        let rx = Body::new(Kind::Chan {
            content_length,
            abort_rx,
            rx,
        });

        (tx, rx)
    }

    /// Wrap a futures `Stream` in a box inside `Body`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate futures;
    /// # extern crate hyper;
    /// # use hyper::Body;
    /// # fn main() {
    /// let chunks = vec![
    ///     "hello",
    ///     " ",
    ///     "world",
    /// ];
    ///
    /// let stream = futures::stream::iter_ok::<_, ::std::io::Error>(chunks);
    ///
    /// let body = Body::wrap_stream(stream);
    /// # }
    /// ```
    pub fn wrap_stream<S>(stream: S) -> Body
    where
        S: Stream + Send + 'static,
        S::Error: Into<Box<::std::error::Error + Send + Sync>>,
        Chunk: From<S::Item>,
    {
        let mapped = stream.map(Chunk::from).map_err(Into::into);
        Body::new(Kind::Wrapped(Box::new(mapped)))
    }

    /// Converts this `Body` into a `Future` of a pending HTTP upgrade.
    ///
    /// See [the `upgrade` module](::upgrade) for more.
    pub fn on_upgrade(self) -> OnUpgrade {
        self
            .extra
            .map(|ex| ex.on_upgrade)
            .unwrap_or_else(OnUpgrade::none)
    }

    fn new(kind: Kind) -> Body {
        Body {
            kind: kind,
            extra: None,
        }
    }

    pub(crate) fn h2(recv: h2::RecvStream, content_length: Option<u64>) -> Self {
        Body::new(Kind::H2 {
            content_length,
            recv,
        })
    }

    pub(crate) fn set_on_upgrade(&mut self, upgrade: OnUpgrade) {
        debug_assert!(!upgrade.is_none(), "set_on_upgrade with empty upgrade");
        let extra = self.extra_mut();
        debug_assert!(extra.on_upgrade.is_none(), "set_on_upgrade twice");
        extra.on_upgrade = upgrade;
    }

    pub(crate) fn delayed_eof(&mut self, fut: DelayEofUntil) {
        self.extra_mut().delayed_eof = Some(DelayEof::NotEof(fut));
    }

    fn take_delayed_eof(&mut self) -> Option<DelayEof> {
        self
            .extra
            .as_mut()
            .and_then(|extra| extra.delayed_eof.take())
    }

    fn extra_mut(&mut self) -> &mut Extra {
        self
            .extra
            .get_or_insert_with(|| Box::new(Extra {
                delayed_eof: None,
                on_upgrade: OnUpgrade::none(),
            }))
    }

    fn poll_eof(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.take_delayed_eof() {
            Some(DelayEof::NotEof(mut delay)) => {
                match self.poll_inner() {
                    ok @ Ok(Async::Ready(Some(..))) |
                    ok @ Ok(Async::NotReady) => {
                        self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay));
                        ok
                    },
                    Ok(Async::Ready(None)) => match delay.poll() {
                        Ok(Async::Ready(never)) => match never {},
                        Ok(Async::NotReady) => {
                            self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
                            Ok(Async::NotReady)
                        },
                        Err(_done) => {
                            Ok(Async::Ready(None))
                        },
                    },
                    Err(e) => Err(e),
                }
            },
            Some(DelayEof::Eof(mut delay)) => {
                match delay.poll() {
                    Ok(Async::Ready(never)) => match never {},
                    Ok(Async::NotReady) => {
                        self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
                        Ok(Async::NotReady)
                    },
                    Err(_done) => {
                        Ok(Async::Ready(None))
                    },
                }
            },
            None => self.poll_inner(),
        }
    }

    fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.kind {
            Kind::Once(ref mut val) => Ok(Async::Ready(val.take())),
            Kind::Chan {
                content_length: ref mut len,
                ref mut rx,
                ref mut abort_rx,
            } => {
                if let Ok(Async::Ready(())) = abort_rx.poll() {
                    return Err(::Error::new_body_write("body write aborted"));
                }

                match rx.poll().expect("mpsc cannot error") {
                    Async::Ready(Some(Ok(chunk))) => {
                        if let Some(ref mut len) = *len {
                            debug_assert!(*len >= chunk.len() as u64);
                            *len = *len - chunk.len() as u64;
                        }
                        Ok(Async::Ready(Some(chunk)))
                    }
                    Async::Ready(Some(Err(err))) => Err(err),
                    Async::Ready(None) => Ok(Async::Ready(None)),
                    Async::NotReady => Ok(Async::NotReady),
                }
            }
            Kind::H2 {
                recv: ref mut h2, ..
            } => h2
                .poll()
                .map(|async| {
                    async.map(|opt| {
                        opt.map(|bytes| {
                            let _ = h2.release_capacity().release_capacity(bytes.len());
                            Chunk::from(bytes)
                        })
                    })
                })
                .map_err(::Error::new_body),
            Kind::Wrapped(ref mut s) => s.poll().map_err(::Error::new_body),
        }
    }
}

impl Default for Body {
    /// Returns [`Body::empty()`](Body::empty).
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Payload for Body {
    type Data = Chunk;
    type Error = ::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        self.poll_eof()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        match self.kind {
            Kind::H2 {
                recv: ref mut h2, ..
            } => h2.poll_trailers().map_err(::Error::new_h2),
            _ => Ok(Async::Ready(None)),
        }
    }

    fn is_end_stream(&self) -> bool {
        match self.kind {
            Kind::Once(ref val) => val.is_none(),
            Kind::Chan { content_length, .. } => content_length == Some(0),
            Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),
            Kind::Wrapped(..) => false,
        }
    }

    fn content_length(&self) -> Option<u64> {
        match self.kind {
            Kind::Once(Some(ref val)) => Some(val.len() as u64),
            Kind::Once(None) => Some(0),
            Kind::Wrapped(..) => None,
            Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => content_length,
        }
    }

    // We can improve the performance of `Body` when we know it is a Once kind.
    #[doc(hidden)]
    fn __hyper_full_data(&mut self, _: FullDataArg) -> FullDataRet<Self::Data> {
        match self.kind {
            Kind::Once(ref mut val) => FullDataRet(val.take()),
            _ => FullDataRet(None),
        }
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_data()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Body").finish()
    }
}

impl Sender {
    /// Check to see if this `Sender` can send more data.
    pub fn poll_ready(&mut self) -> Poll<(), ::Error> {
        match self.abort_tx.poll_cancel() {
            Ok(Async::Ready(())) | Err(_) => return Err(::Error::new_closed()),
            Ok(Async::NotReady) => (),
        }

        self.tx.poll_ready().map_err(|_| ::Error::new_closed())
    }

    /// Sends data on this channel.
    ///
    /// This should be called after `poll_ready` indicated the channel
    /// could accept another `Chunk`.
    ///
    /// Returns `Err(Chunk)` if the channel could not (currently) accept
    /// another `Chunk`.
    pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
        self.tx
            .try_send(Ok(chunk))
            .map_err(|err| err.into_inner().expect("just sent Ok"))
    }

    /// Aborts the body in an abnormal fashion.
    pub fn abort(self) {
        let _ = self.abort_tx.send(());
    }

    pub(crate) fn send_error(&mut self, err: ::Error) {
        let _ = self.tx.try_send(Err(err));
    }
}

impl Sink for Sender {
    type SinkItem = Chunk;
    type SinkError = ::Error;

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        Ok(Async::Ready(()))
    }

    fn start_send(&mut self, msg: Chunk) -> StartSend<Self::SinkItem, Self::SinkError> {
        match self.poll_ready()? {
            Async::Ready(_) => {
                self.send_data(msg).map_err(|_| ::Error::new_closed())?;
                Ok(AsyncSink::Ready)
            }
            Async::NotReady => Ok(AsyncSink::NotReady(msg)),
        }
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from(chunk: Chunk) -> Body {
        if chunk.is_empty() {
            Body::empty()
        } else {
            Body::new(Kind::Once(Some(chunk)))
        }
    }
}

impl
    From<Box<Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send + 'static>>
    for Body
{
    #[inline]
    fn from(
        stream: Box<
            Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send + 'static,
        >,
    ) -> Body {
        Body::new(Kind::Wrapped(stream))
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from(bytes: Bytes) -> Body {
        Body::from(Chunk::from(bytes))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from(vec: Vec<u8>) -> Body {
        Body::from(Chunk::from(vec))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from(slice: &'static [u8]) -> Body {
        Body::from(Chunk::from(slice))
    }
}

impl From<Cow<'static, [u8]>> for Body {
    #[inline]
    fn from(cow: Cow<'static, [u8]>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o),
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from(s: String) -> Body {
        Body::from(Chunk::from(s.into_bytes()))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(slice: &'static str) -> Body {
        Body::from(Chunk::from(slice.as_bytes()))
    }
}

impl From<Cow<'static, str>> for Body {
    #[inline]
    fn from(cow: Cow<'static, str>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o),
        }
    }
}

#[test]
fn test_body_stream_concat() {
    let body = Body::from("hello world");

    let total = body.concat2().wait().unwrap();
    assert_eq!(total.as_ref(), b"hello world");
}
<commit_msg>refactor(body): improve Debug format of Body<commit_after>use std::borrow::Cow;
use std::fmt;

use bytes::Bytes;
use futures::sync::{mpsc, oneshot};
use futures::{Async, Future, Poll, Stream, Sink, AsyncSink, StartSend};
use h2;
use http::HeaderMap;

use common::Never;
use super::internal::{FullDataArg, FullDataRet};
use super::{Chunk, Payload};
use upgrade::OnUpgrade;

type BodySender = mpsc::Sender<Result<Chunk, ::Error>>;

/// A stream of `Chunk`s, used when receiving bodies.
///
/// A good default `Payload` to use in many applications.
///
/// Also implements `futures::Stream`, so stream combinators may be used.
#[must_use = "streams do nothing unless polled"]
pub struct Body {
    kind: Kind,
    /// Keep the extra bits in an `Option<Box<Extra>>`, so that
    /// Body stays small in the common case (no extras needed).
    extra: Option<Box<Extra>>,
}

enum Kind {
    Once(Option<Chunk>),
    Chan {
        content_length: Option<u64>,
        abort_rx: oneshot::Receiver<()>,
        rx: mpsc::Receiver<Result<Chunk, ::Error>>,
    },
    H2 {
        content_length: Option<u64>,
        recv: h2::RecvStream,
    },
    Wrapped(Box<Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send>),
}

struct Extra {
    /// Allow the client to pass a future to delay the `Body` from returning
    /// EOF. This allows the `Client` to try to put the idle connection
    /// back into the pool before the body is "finished".
    ///
    /// The reason for this is so that creating a new request after finishing
    /// streaming the body of a response could sometimes result in creating
    /// a brand new connection, since the pool didn't know about the idle
    /// connection yet.
    delayed_eof: Option<DelayEof>,
    on_upgrade: OnUpgrade,
}

type DelayEofUntil = oneshot::Receiver<Never>;

enum DelayEof {
    /// Initial state, stream hasn't seen EOF yet.
    NotEof(DelayEofUntil),
    /// Transitions to this state once we've seen `poll` try to
    /// return EOF (`None`). This future is then polled, and
    /// when it completes, the Body finally returns EOF (`None`).
    Eof(DelayEofUntil),
}

/// A sender half used with `Body::channel()`.
///
/// Useful when wanting to stream chunks from another thread. See
/// [`Body::channel`](Body::channel) for more.
#[must_use = "Sender does nothing unless sent on"]
#[derive(Debug)]
pub struct Sender {
    abort_tx: oneshot::Sender<()>,
    tx: BodySender,
}

impl Body {
    /// Create an empty `Body` stream.
    ///
    /// # Example
    ///
    /// ```
    /// use hyper::{Body, Request};
    ///
    /// // create a `GET /` request
    /// let get = Request::new(Body::empty());
    /// ```
    #[inline]
    pub fn empty() -> Body {
        Body::new(Kind::Once(None))
    }

    /// Create a `Body` stream with an associated sender half.
    ///
    /// Useful when wanting to stream chunks from another thread.
    #[inline]
    pub fn channel() -> (Sender, Body) {
        Self::new_channel(None)
    }

    pub(crate) fn new_channel(content_length: Option<u64>) -> (Sender, Body) {
        let (tx, rx) = mpsc::channel(0);
        let (abort_tx, abort_rx) = oneshot::channel();

        let tx = Sender {
            abort_tx: abort_tx,
            tx: tx,
        };
        let rx = Body::new(Kind::Chan {
            content_length,
            abort_rx,
            rx,
        });

        (tx, rx)
    }

    /// Wrap a futures `Stream` in a box inside `Body`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate futures;
    /// # extern crate hyper;
    /// # use hyper::Body;
    /// # fn main() {
    /// let chunks = vec![
    ///     "hello",
    ///     " ",
    ///     "world",
    /// ];
    ///
    /// let stream = futures::stream::iter_ok::<_, ::std::io::Error>(chunks);
    ///
    /// let body = Body::wrap_stream(stream);
    /// # }
    /// ```
    pub fn wrap_stream<S>(stream: S) -> Body
    where
        S: Stream + Send + 'static,
        S::Error: Into<Box<::std::error::Error + Send + Sync>>,
        Chunk: From<S::Item>,
    {
        let mapped = stream.map(Chunk::from).map_err(Into::into);
        Body::new(Kind::Wrapped(Box::new(mapped)))
    }

    /// Converts this `Body` into a `Future` of a pending HTTP upgrade.
    ///
    /// See [the `upgrade` module](::upgrade) for more.
    pub fn on_upgrade(self) -> OnUpgrade {
        self
            .extra
            .map(|ex| ex.on_upgrade)
            .unwrap_or_else(OnUpgrade::none)
    }

    fn new(kind: Kind) -> Body {
        Body {
            kind: kind,
            extra: None,
        }
    }

    pub(crate) fn h2(recv: h2::RecvStream, content_length: Option<u64>) -> Self {
        Body::new(Kind::H2 {
            content_length,
            recv,
        })
    }

    pub(crate) fn set_on_upgrade(&mut self, upgrade: OnUpgrade) {
        debug_assert!(!upgrade.is_none(), "set_on_upgrade with empty upgrade");
        let extra = self.extra_mut();
        debug_assert!(extra.on_upgrade.is_none(), "set_on_upgrade twice");
        extra.on_upgrade = upgrade;
    }

    pub(crate) fn delayed_eof(&mut self, fut: DelayEofUntil) {
        self.extra_mut().delayed_eof = Some(DelayEof::NotEof(fut));
    }

    fn take_delayed_eof(&mut self) -> Option<DelayEof> {
        self
            .extra
            .as_mut()
            .and_then(|extra| extra.delayed_eof.take())
    }

    fn extra_mut(&mut self) -> &mut Extra {
        self
            .extra
            .get_or_insert_with(|| Box::new(Extra {
                delayed_eof: None,
                on_upgrade: OnUpgrade::none(),
            }))
    }

    fn poll_eof(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.take_delayed_eof() {
            Some(DelayEof::NotEof(mut delay)) => {
                match self.poll_inner() {
                    ok @ Ok(Async::Ready(Some(..))) |
                    ok @ Ok(Async::NotReady) => {
                        self.extra_mut().delayed_eof = Some(DelayEof::NotEof(delay));
                        ok
                    },
                    Ok(Async::Ready(None)) => match delay.poll() {
                        Ok(Async::Ready(never)) => match never {},
                        Ok(Async::NotReady) => {
                            self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
                            Ok(Async::NotReady)
                        },
                        Err(_done) => {
                            Ok(Async::Ready(None))
                        },
                    },
                    Err(e) => Err(e),
                }
            },
            Some(DelayEof::Eof(mut delay)) => {
                match delay.poll() {
                    Ok(Async::Ready(never)) => match never {},
                    Ok(Async::NotReady) => {
                        self.extra_mut().delayed_eof = Some(DelayEof::Eof(delay));
                        Ok(Async::NotReady)
                    },
                    Err(_done) => {
                        Ok(Async::Ready(None))
                    },
                }
            },
            None => self.poll_inner(),
        }
    }

    fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> {
        match self.kind {
            Kind::Once(ref mut val) => Ok(Async::Ready(val.take())),
            Kind::Chan {
                content_length: ref mut len,
                ref mut rx,
                ref mut abort_rx,
            } => {
                if let Ok(Async::Ready(())) = abort_rx.poll() {
                    return Err(::Error::new_body_write("body write aborted"));
                }

                match rx.poll().expect("mpsc cannot error") {
                    Async::Ready(Some(Ok(chunk))) => {
                        if let Some(ref mut len) = *len {
                            debug_assert!(*len >= chunk.len() as u64);
                            *len = *len - chunk.len() as u64;
                        }
                        Ok(Async::Ready(Some(chunk)))
                    }
                    Async::Ready(Some(Err(err))) => Err(err),
                    Async::Ready(None) => Ok(Async::Ready(None)),
                    Async::NotReady => Ok(Async::NotReady),
                }
            }
            Kind::H2 {
                recv: ref mut h2, ..
            } => h2
                .poll()
                .map(|async| {
                    async.map(|opt| {
                        opt.map(|bytes| {
                            let _ = h2.release_capacity().release_capacity(bytes.len());
                            Chunk::from(bytes)
                        })
                    })
                })
                .map_err(::Error::new_body),
            Kind::Wrapped(ref mut s) => s.poll().map_err(::Error::new_body),
        }
    }
}

impl Default for Body {
    /// Returns [`Body::empty()`](Body::empty).
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Payload for Body {
    type Data = Chunk;
    type Error = ::Error;

    fn poll_data(&mut self) -> Poll<Option<Self::Data>, Self::Error> {
        self.poll_eof()
    }

    fn poll_trailers(&mut self) -> Poll<Option<HeaderMap>, Self::Error> {
        match self.kind {
            Kind::H2 {
                recv: ref mut h2, ..
            } => h2.poll_trailers().map_err(::Error::new_h2),
            _ => Ok(Async::Ready(None)),
        }
    }

    fn is_end_stream(&self) -> bool {
        match self.kind {
            Kind::Once(ref val) => val.is_none(),
            Kind::Chan { content_length, .. } => content_length == Some(0),
            Kind::H2 { recv: ref h2, .. } => h2.is_end_stream(),
            Kind::Wrapped(..) => false,
        }
    }

    fn content_length(&self) -> Option<u64> {
        match self.kind {
            Kind::Once(Some(ref val)) => Some(val.len() as u64),
            Kind::Once(None) => Some(0),
            Kind::Wrapped(..) => None,
            Kind::Chan { content_length, .. } | Kind::H2 { content_length, .. } => content_length,
        }
    }

    // We can improve the performance of `Body` when we know it is a Once kind.
    #[doc(hidden)]
    fn __hyper_full_data(&mut self, _: FullDataArg) -> FullDataRet<Self::Data> {
        match self.kind {
            Kind::Once(ref mut val) => FullDataRet(val.take()),
            _ => FullDataRet(None),
        }
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        self.poll_data()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        #[derive(Debug)]
        struct Streaming;
        #[derive(Debug)]
        struct Empty;
        #[derive(Debug)]
        struct Once<'a>(&'a Chunk);

        let mut builder = f.debug_tuple("Body");
        match self.kind {
            Kind::Once(None) => builder.field(&Empty),
            Kind::Once(Some(ref chunk)) => builder.field(&Once(chunk)),
            _ => builder.field(&Streaming),
        };

        builder.finish()
    }
}

impl Sender {
    /// Check to see if this `Sender` can send more data.
    pub fn poll_ready(&mut self) -> Poll<(), ::Error> {
        match self.abort_tx.poll_cancel() {
            Ok(Async::Ready(())) | Err(_) => return Err(::Error::new_closed()),
            Ok(Async::NotReady) => (),
        }

        self.tx.poll_ready().map_err(|_| ::Error::new_closed())
    }

    /// Sends data on this channel.
    ///
    /// This should be called after `poll_ready` indicated the channel
    /// could accept another `Chunk`.
    ///
    /// Returns `Err(Chunk)` if the channel could not (currently) accept
    /// another `Chunk`.
    pub fn send_data(&mut self, chunk: Chunk) -> Result<(), Chunk> {
        self.tx
            .try_send(Ok(chunk))
            .map_err(|err| err.into_inner().expect("just sent Ok"))
    }

    /// Aborts the body in an abnormal fashion.
    pub fn abort(self) {
        let _ = self.abort_tx.send(());
    }

    pub(crate) fn send_error(&mut self, err: ::Error) {
        let _ = self.tx.try_send(Err(err));
    }
}

impl Sink for Sender {
    type SinkItem = Chunk;
    type SinkError = ::Error;

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        Ok(Async::Ready(()))
    }

    fn start_send(&mut self, msg: Chunk) -> StartSend<Self::SinkItem, Self::SinkError> {
        match self.poll_ready()? {
            Async::Ready(_) => {
                self.send_data(msg).map_err(|_| ::Error::new_closed())?;
                Ok(AsyncSink::Ready)
            }
            Async::NotReady => Ok(AsyncSink::NotReady(msg)),
        }
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from(chunk: Chunk) -> Body {
        if chunk.is_empty() {
            Body::empty()
        } else {
            Body::new(Kind::Once(Some(chunk)))
        }
    }
}

impl
    From<Box<Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send + 'static>>
    for Body
{
    #[inline]
    fn from(
        stream: Box<
            Stream<Item = Chunk, Error = Box<::std::error::Error + Send + Sync>> + Send + 'static,
        >,
    ) -> Body {
        Body::new(Kind::Wrapped(stream))
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from(bytes: Bytes) -> Body {
        Body::from(Chunk::from(bytes))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from(vec: Vec<u8>) -> Body {
        Body::from(Chunk::from(vec))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from(slice: &'static [u8]) -> Body {
        Body::from(Chunk::from(slice))
    }
}

impl From<Cow<'static, [u8]>> for Body {
    #[inline]
    fn from(cow: Cow<'static, [u8]>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o),
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from(s: String) -> Body {
        Body::from(Chunk::from(s.into_bytes()))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(slice: &'static str) -> Body {
        Body::from(Chunk::from(slice.as_bytes()))
    }
}

impl From<Cow<'static, str>> for Body {
    #[inline]
    fn from(cow: Cow<'static, str>) -> Body {
        match cow {
            Cow::Borrowed(b) => Body::from(b),
            Cow::Owned(o) => Body::from(o),
        }
    }
}

#[test]
fn test_body_stream_concat() {
    let body = Body::from("hello world");

    let total = body.concat2().wait().unwrap();
    assert_eq!(total.as_ref(), b"hello world");
}
<|endoftext|>


<commit_before>use gl;
use std::default::Default;
use std::os::raw::c_void;
use std::sync::mpsc;
use std::thread;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton, Window};

#[derive(Clone, Copy, Debug)]
pub enum LuminanceBackend {
  GL33
}

impl Default for LuminanceBackend {
  fn default() -> Self {
    LuminanceBackend::GL33
  }
}

#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn bootstrap<App: FnOnce(u32, u32, Keyboard, Mouse, MouseMove, Scroll, Window)>(dim: WindowDim, title: &'static str, backend: LuminanceBackend, app: App) {
  info!("{} starting\nwindow mode: {:?}\nluminance backend: {:?}", title, dim, backend);

  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  match backend {
    LuminanceBackend::GL33 => {
      // OpenGL hints; implements luminance-gl’s core contexts creation
      glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
      glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
      glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));
    }
  }

  // open a window in windowed or fullscreen mode
  let (mut window, events, w, h) = match dim {
    WindowDim::Windowed(w, h) => {
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
      (window, events, w, h)
    },
    WindowDim::FullScreen => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();
        let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
        let (w, h) = (vmode.width, vmode.height);

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    },
    WindowDim::FullScreenRestricted(w, h) => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    }
  };

  deb!("window opened");

  window.make_current();

  if cfg!(feature = "release") {
    deb!("hiding cursor");
    window.set_cursor_mode(CursorMode::Disabled);
  }

  window.set_key_polling(true);
  window.set_cursor_pos_polling(true);
  window.set_mouse_button_polling(true);
  window.set_scroll_polling(true);

  deb!("initializing OpenGL pointers");

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  deb!("spawing the event thread");
  let _ = thread::spawn(move || {
    loop {
      glfw.wait_events();

      for (_, event) in glfw::flush_messages(&events) {
        match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = mouse_move_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
        }
      }
    }
  });

  deb!("bootstrapping finished");
  app(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv, window);
}
<commit_msg>Fixed output.<commit_after>use gl;
use std::default::Default;
use std::os::raw::c_void;
use std::sync::mpsc;
use std::thread;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton, Window};

#[derive(Clone, Copy, Debug)]
pub enum LuminanceBackend {
  GL33
}

impl Default for LuminanceBackend {
  fn default() -> Self {
    LuminanceBackend::GL33
  }
}

#[derive(Clone, Copy, Debug)]
pub enum WindowDim {
  Windowed(u32, u32),
  FullScreen,
  FullScreenRestricted(u32, u32)
}

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn bootstrap<App: FnOnce(u32, u32, Keyboard, Mouse, MouseMove, Scroll, Window)>(dim: WindowDim, title: &'static str, backend: LuminanceBackend, app: App) {
  info!("{} starting", title);
  info!("{} window mode: {:?}", dim);
  info!("luminance backend: {:?}", backend);

  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  match backend {
    LuminanceBackend::GL33 => {
      // OpenGL hints; implements luminance-gl’s core contexts creation
      glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
      glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
      glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));
    }
  }

  // open a window in windowed or fullscreen mode
  let (mut window, events, w, h) = match dim {
    WindowDim::Windowed(w, h) => {
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed).expect("Failed to create GLFW window.");
      (window, events, w, h)
    },
    WindowDim::FullScreen => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();
        let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
        let (w, h) = (vmode.width, vmode.height);

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    },
    WindowDim::FullScreenRestricted(w, h) => {
      glfw.with_primary_monitor(|glfw, monitor| {
        let monitor = monitor.unwrap();

        let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");
        (window, events, w, h)
      })
    }
  };

  deb!("window opened");

  window.make_current();

  if cfg!(feature = "release") {
    deb!("hiding cursor");
    window.set_cursor_mode(CursorMode::Disabled);
  }

  window.set_key_polling(true);
  window.set_cursor_pos_polling(true);
  window.set_mouse_button_polling(true);
  window.set_scroll_polling(true);

  deb!("initializing OpenGL pointers");

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  deb!("spawing the event thread");
  let _ = thread::spawn(move || {
    loop {
      glfw.wait_events();

      for (_, event) in glfw::flush_messages(&events) {
        match event {
            glfw::WindowEvent::Key(key, _, action, _) => {
              let _ = kbd_snd.send((key, action));
            },
            glfw::WindowEvent::MouseButton(button, action, _) => {
              let _ = mouse_snd.send((button, action));
            },
            glfw::WindowEvent::CursorPos(x, y) => {
              let _ = mouse_move_snd.send([x, y]);
            },
            glfw::WindowEvent::Scroll(x, y) => {
              let _ = scroll_snd.send([x, y]);
            },
            _ => {},
        }
      }
    }
  });

  deb!("bootstrapping finished");
  app(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv, window);
}
<|endoftext|>