<commit_before>/**
 * Mid-level wrapper functions that provide rust-style funtion names. Includes public exports of
 * core types and constants.
 */

use core::libc::*;

pub use support::consts::*;
pub use support::types::*;

pub fn init() -> c_int {
    unsafe { ::ll::glfwInit() }
}

pub fn terminate() {
    unsafe { ::ll::glfwTerminate(); }
}

pub fn get_version() -> (c_int, c_int, c_int) {
    unsafe {
        let mut major = 0,
                minor = 0,
                rev   = 0;
        ::ll::glfwGetVersion(&major, &minor, &rev);
        (major, minor, rev)
    }
}

pub fn get_version_string() -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetVersionString()) }
}

pub fn set_error_callback(cbfun: GLFWerrorfun) -> GLFWerrorfun {
    unsafe { ::ll::glfwSetErrorCallback(cbfun) }
}

pub fn get_monitors() -> ~[*GLFWmonitor] {
    unsafe {
        let mut count = 0;
        let ptr = ::ll::glfwGetMonitors(&count);
        vec::from_buf(ptr, count as uint)
    }
}

pub fn get_primary_monitor() -> *GLFWmonitor {
    unsafe { ::ll::glfwGetPrimaryMonitor() }
}

pub fn get_monitor_pos(monitor: *GLFWmonitor) -> (c_int, c_int) {
    unsafe {
        let mut xpos = 0, ypos = 0;
        ::ll::glfwGetMonitorPos(monitor, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn get_monitor_physical_size(monitor: *GLFWmonitor) -> (c_int, c_int) {
    unsafe {
        let mut width = 0, height = 0;
        ::ll::glfwGetMonitorPhysicalSize(monitor, &width, &height);
        (width, height)
    }
}

pub fn get_monitor_name(monitor: *GLFWmonitor) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetMonitorName(monitor)) }
}

pub fn get_video_modes(monitor: *GLFWmonitor) -> ~[GLFWvidmode] {
    unsafe {
        let mut count = 0;
        let ptr = ::ll::glfwGetVideoModes(monitor, &count);
        vec::from_buf(ptr, count as uint)
    }
}

pub fn get_video_mode(monitor: *GLFWmonitor) -> GLFWvidmode {
    unsafe { ::ll::glfwGetVideoMode(monitor) }
}

pub fn set_gamma(monitor: *GLFWmonitor, gamma: c_float) {
    unsafe { ::ll::glfwSetGamma(monitor, gamma); }
}

pub fn get_gamma_ramp(monitor: *GLFWmonitor) -> GLFWgammaramp {
    let mut ramp = ::GammaRamp {
        red:   [0, ..GAMMA_RAMP_SIZE],
        green: [0, ..GAMMA_RAMP_SIZE],
        blue:  [0, ..GAMMA_RAMP_SIZE],
    };
    unsafe { ::ll::glfwGetGammaRamp(monitor, &ramp); }
    return ramp;
}

pub fn set_gamma_ramp(monitor: *GLFWmonitor, ramp: &GLFWgammaramp) {
    unsafe { ::ll::glfwSetGammaRamp(monitor, ramp); }
}

pub fn set_monitor_callback(cbfun: GLFWmonitorfun) -> GLFWmonitorfun {
    unsafe { ::ll::glfwSetMonitorCallback(cbfun) }
}

pub fn default_window_hints() {
    unsafe { ::ll::glfwDefaultWindowHints(); }
}

pub fn window_hint(target: c_int, hint: c_int) {
    unsafe { ::ll::glfwWindowHint(target, hint); }
}

pub fn create_window(width: c_int, height: c_int, title: &str, monitor: *GLFWmonitor, share: *GLFWwindow) -> *GLFWwindow {
    unsafe { ::ll::glfwCreateWindow(width, height, str::as_c_str(title, |a| a), monitor, share) }
}

pub fn destroy_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwDestroyWindow(window); }
}

pub fn window_should_close(window: *GLFWwindow) -> c_int {
    unsafe { ::ll::glfwWindowShouldClose(window) }
}

pub fn set_window_should_close(window: *GLFWwindow, value: c_int) {
    unsafe { ::ll::glfwSetWindowShouldClose(window, value) }
}

pub fn set_window_title(window: *GLFWwindow, title: &str) {
    unsafe { ::ll::glfwSetWindowTitle(window, str::as_c_str(title, |a| a)) }
}

pub fn get_window_pos(window: *GLFWwindow) -> (c_int, c_int) {
    unsafe {
        let mut xpos = 0, ypos = 0;
        ::ll::glfwGetWindowPos(window, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn set_window_pos(window: *GLFWwindow, xpos: c_int, ypos: c_int) {
    unsafe { ::ll::glfwSetWindowPos(window, xpos, ypos); }
}

pub fn get_window_size(window: *GLFWwindow) -> (c_int, c_int) {
    unsafe {
        let mut width = 0, height = 0;
        ::ll::glfwGetWindowSize(window, &width, &height);
        (width, height)
    }
}

pub fn set_window_size(window: *GLFWwindow, width: c_int, height: c_int) {
    unsafe { ::ll::glfwSetWindowSize(window, width, height); }
}

pub fn iconify_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwIconifyWindow(window); }
}

pub fn restore_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwRestoreWindow(window); }
}

pub fn show_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwShowWindow(window); }
}

pub fn hide_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwHideWindow(window); }
}

pub fn get_window_monitor(window: *GLFWwindow) -> *GLFWmonitor {
    unsafe { ::ll::glfwGetWindowMonitor(window) }
}

pub fn get_window_param(window: *GLFWwindow, param: c_int) -> c_int {
    unsafe { ::ll::glfwGetWindowParam(window, param) }
}

pub fn set_window_user_pointer(window: *GLFWwindow, pointer: *c_void) {
    unsafe { ::ll::glfwSetWindowUserPointer(window, pointer); }
}

pub fn get_window_user_pointer(window: *GLFWwindow) -> *c_void {
    unsafe { ::ll::glfwGetWindowUserPointer(window) }
}

pub fn set_window_pos_callback(window: *GLFWwindow, cbfun: GLFWwindowposfun) -> GLFWwindowposfun {
    unsafe { ::ll::glfwSetWindowPosCallback(window, cbfun) }
}

pub fn set_window_size_callback(window: *GLFWwindow, cbfun: GLFWwindowsizefun) -> GLFWwindowsizefun {
    unsafe { ::ll::glfwSetWindowSizeCallback(window, cbfun) }
}

pub fn set_window_close_callback(window: *GLFWwindow, cbfun: GLFWwindowclosefun) -> GLFWwindowclosefun {
    unsafe { ::ll::glfwSetWindowCloseCallback(window, cbfun) }
}

pub fn set_window_refresh_callback(window: *GLFWwindow, cbfun: GLFWwindowrefreshfun) -> GLFWwindowrefreshfun {
    unsafe { ::ll::glfwSetWindowRefreshCallback(window, cbfun) }
}

pub fn set_window_focus_callback(window: *GLFWwindow, cbfun: GLFWwindowfocusfun) -> GLFWwindowfocusfun {
    unsafe { ::ll::glfwSetWindowFocusCallback(window, cbfun) }
}

pub fn set_window_iconify_callback(window: *GLFWwindow, cbfun: GLFWwindowiconifyfun) -> GLFWwindowiconifyfun {
    unsafe { ::ll::glfwSetWindowIconifyCallback(window, cbfun) }
}

pub fn get_input_mode(window: *GLFWwindow, mode: c_int) -> c_int {
    unsafe { ::ll::glfwGetInputMode(window, mode) }
}

pub fn set_input_mode(window: *GLFWwindow, mode: c_int, value: c_int) {
    unsafe { ::ll::glfwSetInputMode(window, mode, value); }
}

pub fn get_key(window: *GLFWwindow, key: c_int) -> c_int {
    unsafe { ::ll::glfwGetKey(window, key) }
}

pub fn get_mouse_button(window: *GLFWwindow, button: c_int) -> c_int {
    unsafe { ::ll::glfwGetMouseButton(window, button) }
}

pub fn get_cursor_pos(window: *GLFWwindow) -> (c_double, c_double) {
    unsafe {
        let mut xpos = 0.0, ypos = 0.0;
        ::ll::glfwGetCursorPos(window, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn set_cursor_pos(window: *GLFWwindow, xpos: c_double, ypos: c_double) {
    unsafe { ::ll::glfwSetCursorPos(window, xpos, ypos); }
}

pub fn set_key_callback(window: *GLFWwindow, cbfun: GLFWkeyfun) -> GLFWkeyfun {
    unsafe { ::ll::glfwSetKeyCallback(window, cbfun) }
}

pub fn set_char_callback(window: *GLFWwindow, cbfun: GLFWcharfun) -> GLFWcharfun {
    unsafe { ::ll::glfwSetCharCallback(window, cbfun) }
}

pub fn set_mouse_button_callback(window: *GLFWwindow, cbfun: GLFWmousebuttonfun) -> GLFWmousebuttonfun {
    unsafe { ::ll::glfwSetMouseButtonCallback(window, cbfun) }
}

pub fn set_cursor_pos_callback(window: *GLFWwindow, cbfun: GLFWcursorposfun) -> GLFWcursorposfun {
    unsafe { ::ll::glfwSetCursorPosCallback(window, cbfun) }
}

pub fn set_cursor_enter_callback(window: *GLFWwindow, cbfun: GLFWcursorenterfun) -> GLFWcursorenterfun {
    unsafe { ::ll::glfwSetCursorEnterCallback(window, cbfun) }
}

pub fn set_scroll_callback(window: *GLFWwindow, cbfun: GLFWscrollfun) -> GLFWscrollfun {
    unsafe { ::ll::glfwSetScrollCallback(window, cbfun) }
}

pub fn set_clipboard_string(window: *GLFWwindow, string: &str) {
    unsafe { ::ll::glfwSetClipboardString(window, str::as_c_str(string, |a| a)); }
}

pub fn get_clipboard_string(window: *GLFWwindow) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetClipboardString(window)) }
}

pub fn make_context_current(window: *GLFWwindow) {
    unsafe { ::ll::glfwMakeContextCurrent(window); }
}

pub fn swap_buffers(window: *GLFWwindow) {
    unsafe { ::ll::glfwSwapBuffers(window); }
}

pub fn poll_events() {
    unsafe { ::ll::glfwPollEvents(); }
}

pub fn wait_events() {
    unsafe { ::ll::glfwWaitEvents(); }
}

pub fn get_joystick_param(joy: c_int, param: c_int) -> c_int {
    unsafe { ::ll::glfwGetJoystickParam(joy, param) }
}

// TODO
// pub fn get_joystick_axes(joy: c_int, axes: *c_float, numaxes: c_int) -> ~[c_int] {
//     unsafe { ::ll::glfwGetJoystickAxes(joy, ...) }
// }

// TODO
// pub fn get_joystick_buttons(joy: c_int, buttons: *c_uchar, numbuttons: c_int) -> ~[c_int] {
//     unsafe { ::ll::glfwGetJoystickButtons(joy, ...) }
// }

pub fn get_joystick_name(joy: c_int) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetJoystickName(joy)) }
}

pub fn get_time() -> c_double {
    unsafe { ::ll::glfwGetTime() }
}

pub fn set_time(time: c_double) {
    unsafe { ::ll::glfwSetTime(time); }
}

pub fn get_current_context() -> *GLFWwindow {
    unsafe { ::ll::glfwGetCurrentContext() }
}

pub fn set_swap_interval(interval: c_int) {
    unsafe { ::ll::glfwSwapInterval(interval); }
}

pub fn extension_supported(extension: &str) -> c_int {
    unsafe { ::ll::glfwExtensionSupported(str::as_c_str(extension, |a| a)) }
}

pub fn get_proc_address(procname: &str) -> GLFWglproc {
    unsafe { ::ll::glfwGetProcAddress(str::as_c_str(procname, |a| a)) }
}<commit_msg>Fix mutability warnings<commit_after>/**
 * Mid-level wrapper functions that provide rust-style funtion names. Includes public exports of
 * core types and constants.
 */

use core::libc::*;

pub use support::consts::*;
pub use support::types::*;

pub fn init() -> c_int {
    unsafe { ::ll::glfwInit() }
}

pub fn terminate() {
    unsafe { ::ll::glfwTerminate(); }
}

pub fn get_version() -> (c_int, c_int, c_int) {
    unsafe {
        let major = 0,
            minor = 0,
            rev   = 0;
        ::ll::glfwGetVersion(&major, &minor, &rev);
        (major, minor, rev)
    }
}

pub fn get_version_string() -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetVersionString()) }
}

pub fn set_error_callback(cbfun: GLFWerrorfun) -> GLFWerrorfun {
    unsafe { ::ll::glfwSetErrorCallback(cbfun) }
}

pub fn get_monitors() -> ~[*GLFWmonitor] {
    unsafe {
        let count = 0;
        let ptr = ::ll::glfwGetMonitors(&count);
        vec::from_buf(ptr, count as uint)
    }
}

pub fn get_primary_monitor() -> *GLFWmonitor {
    unsafe { ::ll::glfwGetPrimaryMonitor() }
}

pub fn get_monitor_pos(monitor: *GLFWmonitor) -> (c_int, c_int) {
    unsafe {
        let xpos = 0,
            ypos = 0;
        ::ll::glfwGetMonitorPos(monitor, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn get_monitor_physical_size(monitor: *GLFWmonitor) -> (c_int, c_int) {
    unsafe {
        let width  = 0,
            height = 0;
        ::ll::glfwGetMonitorPhysicalSize(monitor, &width, &height);
        (width, height)
    }
}

pub fn get_monitor_name(monitor: *GLFWmonitor) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetMonitorName(monitor)) }
}

pub fn get_video_modes(monitor: *GLFWmonitor) -> ~[GLFWvidmode] {
    unsafe {
        let count = 0;
        let ptr = ::ll::glfwGetVideoModes(monitor, &count);
        vec::from_buf(ptr, count as uint)
    }
}

pub fn get_video_mode(monitor: *GLFWmonitor) -> GLFWvidmode {
    unsafe { ::ll::glfwGetVideoMode(monitor) }
}

pub fn set_gamma(monitor: *GLFWmonitor, gamma: c_float) {
    unsafe { ::ll::glfwSetGamma(monitor, gamma); }
}

pub fn get_gamma_ramp(monitor: *GLFWmonitor) -> GLFWgammaramp {
    unsafe {
        let ramp = ::GammaRamp {
            red:   [0, ..GAMMA_RAMP_SIZE],
            green: [0, ..GAMMA_RAMP_SIZE],
            blue:  [0, ..GAMMA_RAMP_SIZE],
        };
        ::ll::glfwGetGammaRamp(monitor, &ramp);
        ramp
    }
}

pub fn set_gamma_ramp(monitor: *GLFWmonitor, ramp: &GLFWgammaramp) {
    unsafe { ::ll::glfwSetGammaRamp(monitor, ramp); }
}

pub fn set_monitor_callback(cbfun: GLFWmonitorfun) -> GLFWmonitorfun {
    unsafe { ::ll::glfwSetMonitorCallback(cbfun) }
}

pub fn default_window_hints() {
    unsafe { ::ll::glfwDefaultWindowHints(); }
}

pub fn window_hint(target: c_int, hint: c_int) {
    unsafe { ::ll::glfwWindowHint(target, hint); }
}

pub fn create_window(width: c_int, height: c_int, title: &str, monitor: *GLFWmonitor, share: *GLFWwindow) -> *GLFWwindow {
    unsafe { ::ll::glfwCreateWindow(width, height, str::as_c_str(title, |a| a), monitor, share) }
}

pub fn destroy_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwDestroyWindow(window); }
}

pub fn window_should_close(window: *GLFWwindow) -> c_int {
    unsafe { ::ll::glfwWindowShouldClose(window) }
}

pub fn set_window_should_close(window: *GLFWwindow, value: c_int) {
    unsafe { ::ll::glfwSetWindowShouldClose(window, value) }
}

pub fn set_window_title(window: *GLFWwindow, title: &str) {
    unsafe { ::ll::glfwSetWindowTitle(window, str::as_c_str(title, |a| a)) }
}

pub fn get_window_pos(window: *GLFWwindow) -> (c_int, c_int) {
    unsafe {
        let xpos = 0,
            ypos = 0;
        ::ll::glfwGetWindowPos(window, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn set_window_pos(window: *GLFWwindow, xpos: c_int, ypos: c_int) {
    unsafe { ::ll::glfwSetWindowPos(window, xpos, ypos); }
}

pub fn get_window_size(window: *GLFWwindow) -> (c_int, c_int) {
    unsafe {
        let width  = 0,
            height = 0;
        ::ll::glfwGetWindowSize(window, &width, &height);
        (width, height)
    }
}

pub fn set_window_size(window: *GLFWwindow, width: c_int, height: c_int) {
    unsafe { ::ll::glfwSetWindowSize(window, width, height); }
}

pub fn iconify_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwIconifyWindow(window); }
}

pub fn restore_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwRestoreWindow(window); }
}

pub fn show_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwShowWindow(window); }
}

pub fn hide_window(window: *GLFWwindow) {
    unsafe { ::ll::glfwHideWindow(window); }
}

pub fn get_window_monitor(window: *GLFWwindow) -> *GLFWmonitor {
    unsafe { ::ll::glfwGetWindowMonitor(window) }
}

pub fn get_window_param(window: *GLFWwindow, param: c_int) -> c_int {
    unsafe { ::ll::glfwGetWindowParam(window, param) }
}

pub fn set_window_user_pointer(window: *GLFWwindow, pointer: *c_void) {
    unsafe { ::ll::glfwSetWindowUserPointer(window, pointer); }
}

pub fn get_window_user_pointer(window: *GLFWwindow) -> *c_void {
    unsafe { ::ll::glfwGetWindowUserPointer(window) }
}

pub fn set_window_pos_callback(window: *GLFWwindow, cbfun: GLFWwindowposfun) -> GLFWwindowposfun {
    unsafe { ::ll::glfwSetWindowPosCallback(window, cbfun) }
}

pub fn set_window_size_callback(window: *GLFWwindow, cbfun: GLFWwindowsizefun) -> GLFWwindowsizefun {
    unsafe { ::ll::glfwSetWindowSizeCallback(window, cbfun) }
}

pub fn set_window_close_callback(window: *GLFWwindow, cbfun: GLFWwindowclosefun) -> GLFWwindowclosefun {
    unsafe { ::ll::glfwSetWindowCloseCallback(window, cbfun) }
}

pub fn set_window_refresh_callback(window: *GLFWwindow, cbfun: GLFWwindowrefreshfun) -> GLFWwindowrefreshfun {
    unsafe { ::ll::glfwSetWindowRefreshCallback(window, cbfun) }
}

pub fn set_window_focus_callback(window: *GLFWwindow, cbfun: GLFWwindowfocusfun) -> GLFWwindowfocusfun {
    unsafe { ::ll::glfwSetWindowFocusCallback(window, cbfun) }
}

pub fn set_window_iconify_callback(window: *GLFWwindow, cbfun: GLFWwindowiconifyfun) -> GLFWwindowiconifyfun {
    unsafe { ::ll::glfwSetWindowIconifyCallback(window, cbfun) }
}

pub fn get_input_mode(window: *GLFWwindow, mode: c_int) -> c_int {
    unsafe { ::ll::glfwGetInputMode(window, mode) }
}

pub fn set_input_mode(window: *GLFWwindow, mode: c_int, value: c_int) {
    unsafe { ::ll::glfwSetInputMode(window, mode, value); }
}

pub fn get_key(window: *GLFWwindow, key: c_int) -> c_int {
    unsafe { ::ll::glfwGetKey(window, key) }
}

pub fn get_mouse_button(window: *GLFWwindow, button: c_int) -> c_int {
    unsafe { ::ll::glfwGetMouseButton(window, button) }
}

pub fn get_cursor_pos(window: *GLFWwindow) -> (c_double, c_double) {
    unsafe {
        let xpos = 0.0,
            ypos = 0.0;
        ::ll::glfwGetCursorPos(window, &xpos, &ypos);
        (xpos, ypos)
    }
}

pub fn set_cursor_pos(window: *GLFWwindow, xpos: c_double, ypos: c_double) {
    unsafe { ::ll::glfwSetCursorPos(window, xpos, ypos); }
}

pub fn set_key_callback(window: *GLFWwindow, cbfun: GLFWkeyfun) -> GLFWkeyfun {
    unsafe { ::ll::glfwSetKeyCallback(window, cbfun) }
}

pub fn set_char_callback(window: *GLFWwindow, cbfun: GLFWcharfun) -> GLFWcharfun {
    unsafe { ::ll::glfwSetCharCallback(window, cbfun) }
}

pub fn set_mouse_button_callback(window: *GLFWwindow, cbfun: GLFWmousebuttonfun) -> GLFWmousebuttonfun {
    unsafe { ::ll::glfwSetMouseButtonCallback(window, cbfun) }
}

pub fn set_cursor_pos_callback(window: *GLFWwindow, cbfun: GLFWcursorposfun) -> GLFWcursorposfun {
    unsafe { ::ll::glfwSetCursorPosCallback(window, cbfun) }
}

pub fn set_cursor_enter_callback(window: *GLFWwindow, cbfun: GLFWcursorenterfun) -> GLFWcursorenterfun {
    unsafe { ::ll::glfwSetCursorEnterCallback(window, cbfun) }
}

pub fn set_scroll_callback(window: *GLFWwindow, cbfun: GLFWscrollfun) -> GLFWscrollfun {
    unsafe { ::ll::glfwSetScrollCallback(window, cbfun) }
}

pub fn set_clipboard_string(window: *GLFWwindow, string: &str) {
    unsafe { ::ll::glfwSetClipboardString(window, str::as_c_str(string, |a| a)); }
}

pub fn get_clipboard_string(window: *GLFWwindow) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetClipboardString(window)) }
}

pub fn make_context_current(window: *GLFWwindow) {
    unsafe { ::ll::glfwMakeContextCurrent(window); }
}

pub fn swap_buffers(window: *GLFWwindow) {
    unsafe { ::ll::glfwSwapBuffers(window); }
}

pub fn poll_events() {
    unsafe { ::ll::glfwPollEvents(); }
}

pub fn wait_events() {
    unsafe { ::ll::glfwWaitEvents(); }
}

pub fn get_joystick_param(joy: c_int, param: c_int) -> c_int {
    unsafe { ::ll::glfwGetJoystickParam(joy, param) }
}

// TODO
// pub fn get_joystick_axes(joy: c_int, axes: *c_float, numaxes: c_int) -> ~[c_int] {
//     unsafe { ::ll::glfwGetJoystickAxes(joy, ...) }
// }

// TODO
// pub fn get_joystick_buttons(joy: c_int, buttons: *c_uchar, numbuttons: c_int) -> ~[c_int] {
//     unsafe { ::ll::glfwGetJoystickButtons(joy, ...) }
// }

pub fn get_joystick_name(joy: c_int) -> ~str {
    unsafe { str::raw::from_c_str(::ll::glfwGetJoystickName(joy)) }
}

pub fn get_time() -> c_double {
    unsafe { ::ll::glfwGetTime() }
}

pub fn set_time(time: c_double) {
    unsafe { ::ll::glfwSetTime(time); }
}

pub fn get_current_context() -> *GLFWwindow {
    unsafe { ::ll::glfwGetCurrentContext() }
}

pub fn set_swap_interval(interval: c_int) {
    unsafe { ::ll::glfwSwapInterval(interval); }
}

pub fn extension_supported(extension: &str) -> c_int {
    unsafe { ::ll::glfwExtensionSupported(str::as_c_str(extension, |a| a)) }
}

pub fn get_proc_address(procname: &str) -> GLFWglproc {
    unsafe { ::ll::glfwGetProcAddress(str::as_c_str(procname, |a| a)) }
}<|endoftext|>


<commit_before><commit_msg>Add implementation of ToTokenTrees for String<commit_after><|endoftext|>


<commit_before><commit_msg>Auto merge of #10847 - johnmatthiggins:master, r=epage<commit_after><|endoftext|>


<commit_before>use core::cmp::min;
use core::intrinsics;
use core::mem::size_of;
use core::ops::{Index, IndexMut};
use core::ptr;

use common::scheduler::*;

pub const PAGE_DIRECTORY: usize = 0x300000;
pub const PAGE_TABLE_SIZE: usize = 1024;
pub const PAGE_TABLES: usize = PAGE_DIRECTORY + PAGE_TABLE_SIZE * 4;
pub const PAGE_SIZE: usize = 4 * 1024;

pub const CLUSTER_ADDRESS: usize = PAGE_TABLES + PAGE_TABLE_SIZE * PAGE_TABLE_SIZE * 4 ;
pub const CLUSTER_COUNT: usize = 1024 * 1024; // 4 GiB
pub const CLUSTER_SIZE: usize = 4 * 1024; // Of 4 K chunks

#[repr(packed)]
struct MemoryMapEntry {
    base: u64,
    len: u64,
    class: u32,
    acpi: u32,
}

pub struct Memory<T> {
    pub ptr: *mut T,
}

impl<T> Memory<T> {
    pub fn new(count: usize) -> Option<Self> {
        let alloc = unsafe { alloc(count * size_of::<T>()) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    pub fn renew(&mut self, count: usize) -> bool {
        let address = unsafe { realloc(self.ptr as usize, count * size_of::<T>()) };
        if address > 0 {
            self.ptr = address as *mut T;
            true
        } else {
            false
        }
    }

    // The size in bytes
    pub fn size(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) }
    }

    // The length in T elements
    pub fn length(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) / size_of::<T>() }
    }

    pub unsafe fn address(&self) -> usize {
        self.ptr as usize
    }

    pub unsafe fn read(&self, i: usize) -> T {
        ptr::read(self.ptr.offset(i as isize))
    }

    pub unsafe fn load(&self, i: usize) -> T {
        intrinsics::atomic_load(self.ptr.offset(i as isize))
    }

    pub unsafe fn write(&mut self, i: usize, value: T) {
        ptr::write(self.ptr.offset(i as isize), value);
    }

    pub unsafe fn store(&mut self, i: usize, value: T) {
        intrinsics::atomic_store(self.ptr.offset(i as isize), value);
    }
}

impl<T> Drop for Memory<T> {
    fn drop(&mut self) {
        unsafe { unalloc(self.ptr as usize) }
    }
}

impl<T> Index<usize> for Memory<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: usize) -> &'a T {
        unsafe { &*self.ptr.offset(_index as isize) }
    }
}

impl<T> IndexMut<usize> for Memory<T> {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut T {
        unsafe { &mut *self.ptr.offset(_index as isize) }
    }
}

const MEMORY_MAP: *const MemoryMapEntry = 0x500 as *const MemoryMapEntry;

pub unsafe fn cluster(number: usize) -> usize {
    if number < CLUSTER_COUNT {
        ptr::read((CLUSTER_ADDRESS + number * size_of::<usize>()) as *const usize)
    } else {
        0
    }
}

pub unsafe fn set_cluster(number: usize, address: usize) {
    if number < CLUSTER_COUNT {
        ptr::write((CLUSTER_ADDRESS + number * size_of::<usize>()) as *mut usize,
                   address);
    }
}

pub unsafe fn address_to_cluster(address: usize) -> usize {
    if address >= CLUSTER_ADDRESS + CLUSTER_COUNT * size_of::<usize>() {
        (address - CLUSTER_ADDRESS - CLUSTER_COUNT * size_of::<usize>()) / CLUSTER_SIZE
    } else {
        0
    }
}

pub unsafe fn cluster_to_address(number: usize) -> usize {
    CLUSTER_ADDRESS + CLUSTER_COUNT * size_of::<usize>() + number * CLUSTER_SIZE
}

pub unsafe fn cluster_init() {
    //First, set all clusters to the not present value
    for cluster in 0..CLUSTER_COUNT {
        set_cluster(cluster, 0xFFFFFFFF);
    }

    //Next, set all valid clusters to the free value
    //TODO: Optimize this function
    for i in 0..((0x5000 - 0x500) / size_of::<MemoryMapEntry>()) {
        let entry = &*MEMORY_MAP.offset(i as isize);
        if entry.len > 0 && entry.class == 1 {
            for cluster in 0..CLUSTER_COUNT {
                let address = cluster_to_address(cluster);
                if address as u64 >= entry.base &&
                   (address as u64 + CLUSTER_SIZE as u64) <= (entry.base + entry.len) {
                    set_cluster(cluster, 0);
                }
            }
        }
    }
}

pub unsafe fn alloc(size: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_aligned(size: usize, align: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 && cluster_to_address(i) % align == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_type<T>() -> *mut T {
    alloc(size_of::<T>()) as *mut T
}

pub unsafe fn alloc_size(ptr: usize) -> usize {
    let mut size = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                size += CLUSTER_SIZE;
            } else {
                break;
            }
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    size
}

pub unsafe fn unalloc(ptr: usize) {
    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                set_cluster(i, 0);
            } else {
                break;
            }
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);
}

pub unsafe fn realloc(ptr: usize, size: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size == 0 {
        if ptr > 0 {
            unalloc(ptr);
        }
    } else {
        let old_size = alloc_size(ptr);
        if size <= old_size {
            ret = ptr;
        } else {
            ret = alloc(size);
            if ptr > 0 {
                if ret > 0 {
                    let copy_size = min(old_size, size);

                    ::memmove(ret as *mut u8, ptr as *const u8, copy_size);
                }
                unalloc(ptr);
            }
        }
    }

    end_no_ints(reenable);

    ret
}

pub unsafe fn realloc_inplace(ptr: usize, size: usize) -> usize {
    let old_size = alloc_size(ptr);
    if size <= old_size {
        size
    } else {
        old_size
    }
}

pub fn memory_used() -> usize {
    let mut ret = 0;
    unsafe {
        //Memory allocation must be atomic
        let reenable = start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) != 0 && cluster(i) != 0xFFFFFFFF {
                ret += CLUSTER_SIZE;
            }
        }

        //Memory allocation must be atomic
        end_no_ints(reenable);
    }
    ret
}

pub fn memory_free() -> usize {
    let mut ret = 0;
    unsafe {
        //Memory allocation must be atomic
        let reenable = start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                ret += CLUSTER_SIZE;
            }
        }

        //Memory allocation must be atomic
        end_no_ints(reenable);
    }
    ret
}
<commit_msg>Use `intrinsics::atomic_singlethreadfence` instead of `atomic_{load,store}`<commit_after>use core::cmp::min;
use core::intrinsics;
use core::mem::size_of;
use core::ops::{Index, IndexMut};
use core::ptr;

use common::scheduler::*;

pub const PAGE_DIRECTORY: usize = 0x300000;
pub const PAGE_TABLE_SIZE: usize = 1024;
pub const PAGE_TABLES: usize = PAGE_DIRECTORY + PAGE_TABLE_SIZE * 4;
pub const PAGE_SIZE: usize = 4 * 1024;

pub const CLUSTER_ADDRESS: usize = PAGE_TABLES + PAGE_TABLE_SIZE * PAGE_TABLE_SIZE * 4 ;
pub const CLUSTER_COUNT: usize = 1024 * 1024; // 4 GiB
pub const CLUSTER_SIZE: usize = 4 * 1024; // Of 4 K chunks

#[repr(packed)]
struct MemoryMapEntry {
    base: u64,
    len: u64,
    class: u32,
    acpi: u32,
}

pub struct Memory<T> {
    pub ptr: *mut T,
}

impl<T> Memory<T> {
    pub fn new(count: usize) -> Option<Self> {
        let alloc = unsafe { alloc(count * size_of::<T>()) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    pub fn renew(&mut self, count: usize) -> bool {
        let address = unsafe { realloc(self.ptr as usize, count * size_of::<T>()) };
        if address > 0 {
            self.ptr = address as *mut T;
            true
        } else {
            false
        }
    }

    // The size in bytes
    pub fn size(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) }
    }

    // The length in T elements
    pub fn length(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) / size_of::<T>() }
    }

    pub unsafe fn address(&self) -> usize {
        self.ptr as usize
    }

    pub unsafe fn read(&self, i: usize) -> T {
        ptr::read(self.ptr.offset(i as isize))
    }

    pub unsafe fn load(&self, i: usize) -> T {
        intrinsics::atomic_singlethreadfence();
        ptr::read(self.ptr.offset(i as isize))
    }

    pub unsafe fn write(&mut self, i: usize, value: T) {
        ptr::write(self.ptr.offset(i as isize), value);
    }

    pub unsafe fn store(&mut self, i: usize, value: T) {
        intrinsics::atomic_singlethreadfence();
        ptr::write(self.ptr.offset(i as isize), value)
    }
}

impl<T> Drop for Memory<T> {
    fn drop(&mut self) {
        unsafe { unalloc(self.ptr as usize) }
    }
}

impl<T> Index<usize> for Memory<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: usize) -> &'a T {
        unsafe { &*self.ptr.offset(_index as isize) }
    }
}

impl<T> IndexMut<usize> for Memory<T> {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut T {
        unsafe { &mut *self.ptr.offset(_index as isize) }
    }
}

const MEMORY_MAP: *const MemoryMapEntry = 0x500 as *const MemoryMapEntry;

pub unsafe fn cluster(number: usize) -> usize {
    if number < CLUSTER_COUNT {
        ptr::read((CLUSTER_ADDRESS + number * size_of::<usize>()) as *const usize)
    } else {
        0
    }
}

pub unsafe fn set_cluster(number: usize, address: usize) {
    if number < CLUSTER_COUNT {
        ptr::write((CLUSTER_ADDRESS + number * size_of::<usize>()) as *mut usize,
                   address);
    }
}

pub unsafe fn address_to_cluster(address: usize) -> usize {
    if address >= CLUSTER_ADDRESS + CLUSTER_COUNT * size_of::<usize>() {
        (address - CLUSTER_ADDRESS - CLUSTER_COUNT * size_of::<usize>()) / CLUSTER_SIZE
    } else {
        0
    }
}

pub unsafe fn cluster_to_address(number: usize) -> usize {
    CLUSTER_ADDRESS + CLUSTER_COUNT * size_of::<usize>() + number * CLUSTER_SIZE
}

pub unsafe fn cluster_init() {
    //First, set all clusters to the not present value
    for cluster in 0..CLUSTER_COUNT {
        set_cluster(cluster, 0xFFFFFFFF);
    }

    //Next, set all valid clusters to the free value
    //TODO: Optimize this function
    for i in 0..((0x5000 - 0x500) / size_of::<MemoryMapEntry>()) {
        let entry = &*MEMORY_MAP.offset(i as isize);
        if entry.len > 0 && entry.class == 1 {
            for cluster in 0..CLUSTER_COUNT {
                let address = cluster_to_address(cluster);
                if address as u64 >= entry.base &&
                   (address as u64 + CLUSTER_SIZE as u64) <= (entry.base + entry.len) {
                    set_cluster(cluster, 0);
                }
            }
        }
    }
}

pub unsafe fn alloc(size: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_aligned(size: usize, align: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 && cluster_to_address(i) % align == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_type<T>() -> *mut T {
    alloc(size_of::<T>()) as *mut T
}

pub unsafe fn alloc_size(ptr: usize) -> usize {
    let mut size = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                size += CLUSTER_SIZE;
            } else {
                break;
            }
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);

    size
}

pub unsafe fn unalloc(ptr: usize) {
    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                set_cluster(i, 0);
            } else {
                break;
            }
        }
    }

    //Memory allocation must be atomic
    end_no_ints(reenable);
}

pub unsafe fn realloc(ptr: usize, size: usize) -> usize {
    let mut ret = 0;

    //Memory allocation must be atomic
    let reenable = start_no_ints();

    if size == 0 {
        if ptr > 0 {
            unalloc(ptr);
        }
    } else {
        let old_size = alloc_size(ptr);
        if size <= old_size {
            ret = ptr;
        } else {
            ret = alloc(size);
            if ptr > 0 {
                if ret > 0 {
                    let copy_size = min(old_size, size);

                    ::memmove(ret as *mut u8, ptr as *const u8, copy_size);
                }
                unalloc(ptr);
            }
        }
    }

    end_no_ints(reenable);

    ret
}

pub unsafe fn realloc_inplace(ptr: usize, size: usize) -> usize {
    let old_size = alloc_size(ptr);
    if size <= old_size {
        size
    } else {
        old_size
    }
}

pub fn memory_used() -> usize {
    let mut ret = 0;
    unsafe {
        //Memory allocation must be atomic
        let reenable = start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) != 0 && cluster(i) != 0xFFFFFFFF {
                ret += CLUSTER_SIZE;
            }
        }

        //Memory allocation must be atomic
        end_no_ints(reenable);
    }
    ret
}

pub fn memory_free() -> usize {
    let mut ret = 0;
    unsafe {
        //Memory allocation must be atomic
        let reenable = start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                ret += CLUSTER_SIZE;
            }
        }

        //Memory allocation must be atomic
        end_no_ints(reenable);
    }
    ret
}
<|endoftext|>


<commit_before><commit_msg>Fix(process_mutex): win stub fix<commit_after><|endoftext|>


<commit_before><commit_msg>led-noblink.rs: Add support for stopping led blinking in Rust.<commit_after>use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::io::Write;

fn main() {
    let path = Path::new("/proc/acpi/ibm/led");
    let pdis = path.display();

    let mut fpo = match File::create(&path) {
        Err(why) => panic!("Can't open {}: {}", pdis, why.description()),
        Ok(fpo) => fpo,
    };

    match fpo.write_all(b"0 on\n") {
        Err(why) => panic!("Can't write {}: {}", pdis, why.description()),
        Ok(_) => (),
    }
    match fpo.flush() {
        Err(why) => panic!("Can't flush {}: {}", pdis, why.description()),
        Ok(_) => (),
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that there are no binaries checked into the source tree
//! by accident.
//!
//! In the past we've accidentally checked in test binaries and such which add a
//! huge amount of bloat to the git history, so it's good to just ensure we
//! don't do that again :)

use std::path::Path;

// All files are executable on Windows, so just check on Unix
#[cfg(windows)]
pub fn check(_path: &Path, _bad: &mut bool) {}

#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
    use std::fs;
    use std::io::Read;
    use std::process::{Command, Stdio};
    use std::os::unix::prelude::*;

    if let Ok(mut file) = fs::File::open("/proc/version") {
        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        // Probably on Windows Linux Subsystem, all files will be marked as
        // executable, so skip checking.
        if contents.contains("Microsoft") {
            return;
        }
    }

    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".py", ".sh"];
        if extensions.iter().any(|e| filename.ends_with(e)) {
            return
        }

        let metadata = t!(fs::symlink_metadata(&file), &file);
        if metadata.mode() & 0o111 != 0 {
            let rel_path = file.strip_prefix(path).unwrap();
            let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
            let ret_code = Command::new("git")
                                        .arg("ls-files")
                                        .arg(&git_friendly_path)
                                        .current_dir(path)
                                        .stdout(Stdio::null())
                                        .stderr(Stdio::null())
                                        .status()
                                        .unwrap_or_else(|e| {
                                            panic!("could not run git ls-files: {}", e);
                                        });
            if ret_code.success() {
                println!("binary checked into source: {}", file.display());
                *bad = true;
            }
        }
    })
}

<commit_msg>tidy/bins: fix false positive on non checked-in binary<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that there are no binaries checked into the source tree
//! by accident.
//!
//! In the past we've accidentally checked in test binaries and such which add a
//! huge amount of bloat to the git history, so it's good to just ensure we
//! don't do that again :)

use std::path::Path;

// All files are executable on Windows, so just check on Unix
#[cfg(windows)]
pub fn check(_path: &Path, _bad: &mut bool) {}

#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
    use std::fs;
    use std::io::Read;
    use std::process::{Command, Stdio};
    use std::os::unix::prelude::*;

    if let Ok(mut file) = fs::File::open("/proc/version") {
        let mut contents = String::new();
        file.read_to_string(&mut contents).unwrap();
        // Probably on Windows Linux Subsystem, all files will be marked as
        // executable, so skip checking.
        if contents.contains("Microsoft") {
            return;
        }
    }

    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".py", ".sh"];
        if extensions.iter().any(|e| filename.ends_with(e)) {
            return;
        }

        let metadata = t!(fs::symlink_metadata(&file), &file);
        if metadata.mode() & 0o111 != 0 {
            let rel_path = file.strip_prefix(path).unwrap();
            let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
            let output = Command::new("git")
                .arg("ls-files")
                .arg(&git_friendly_path)
                .current_dir(path)
                .stderr(Stdio::null())
                .output()
                .unwrap_or_else(|e| {
                    panic!("could not run git ls-files: {}", e);
                });
            let path_bytes = rel_path.as_os_str().as_bytes();
            if output.status.success() && output.stdout.starts_with(path_bytes) {
                println!("binary checked into source: {}", file.display());
                *bad = true;
            }
        }
    })
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
    Crate("aho-corasick"),
    Crate("ar"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cfg-if"),
    Crate("cmake"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("polonius-engine"),
    Crate("quick-error"),
    Crate("rand"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("tempdir"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(" ");
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist
    if must_be_on_whitelist {
        // If this dependency is not on the WHITELIST, add to bad set
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}
<commit_msg>Whitelist datafrog on tidy<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Check license of third-party deps by inspecting src/vendor

use std::collections::{BTreeSet, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use serde_json;

static LICENSES: &'static [&'static str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "MIT",
    "Unlicense/MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std / test).
static EXCEPTIONS: &'static [&'static str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "thread-id",          // Apache-2.0, mdbook
    "toml-query",         // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "cssparser",          // MPL-2.0, rustdoc
    "smallvec",           // MPL-2.0, rustdoc
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "cssparser-macros",   // MPL-2.0, rustdoc
    "selectors",          // MPL-2.0, rustdoc
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
];

/// Which crates to check against the whitelist?
static WHITELIST_CRATES: &'static [CrateVersion] = &[
    CrateVersion("rustc", "0.0.0"),
    CrateVersion("rustc_codegen_llvm", "0.0.0"),
];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
static WHITELIST: &'static [Crate] = &[
    Crate("aho-corasick"),
    Crate("ar"),
    Crate("arrayvec"),
    Crate("atty"),
    Crate("backtrace"),
    Crate("backtrace-sys"),
    Crate("bitflags"),
    Crate("byteorder"),
    Crate("cc"),
    Crate("chalk-engine"),
    Crate("chalk-macros"),
    Crate("cfg-if"),
    Crate("cmake"),
    Crate("crossbeam-deque"),
    Crate("crossbeam-epoch"),
    Crate("crossbeam-utils"),
    Crate("datafrog"),
    Crate("either"),
    Crate("ena"),
    Crate("env_logger"),
    Crate("filetime"),
    Crate("flate2"),
    Crate("fuchsia-zircon"),
    Crate("fuchsia-zircon-sys"),
    Crate("getopts"),
    Crate("humantime"),
    Crate("jobserver"),
    Crate("kernel32-sys"),
    Crate("lazy_static"),
    Crate("libc"),
    Crate("log"),
    Crate("log_settings"),
    Crate("memchr"),
    Crate("memoffset"),
    Crate("miniz-sys"),
    Crate("nodrop"),
    Crate("num_cpus"),
    Crate("owning_ref"),
    Crate("parking_lot"),
    Crate("parking_lot_core"),
    Crate("polonius-engine"),
    Crate("quick-error"),
    Crate("rand"),
    Crate("redox_syscall"),
    Crate("redox_termios"),
    Crate("regex"),
    Crate("regex-syntax"),
    Crate("remove_dir_all"),
    Crate("rustc-demangle"),
    Crate("rustc-hash"),
    Crate("rustc-rayon"),
    Crate("rustc-rayon-core"),
    Crate("scoped-tls"),
    Crate("scopeguard"),
    Crate("smallvec"),
    Crate("stable_deref_trait"),
    Crate("tempdir"),
    Crate("termcolor"),
    Crate("terminon"),
    Crate("termion"),
    Crate("thread_local"),
    Crate("ucd-util"),
    Crate("unicode-width"),
    Crate("unreachable"),
    Crate("utf8-ranges"),
    Crate("void"),
    Crate("winapi"),
    Crate("winapi-build"),
    Crate("winapi-i686-pc-windows-gnu"),
    Crate("winapi-x86_64-pc-windows-gnu"),
    Crate("wincolor"),
];

// Some types for Serde to deserialize the output of `cargo metadata` to...

#[derive(Deserialize)]
struct Output {
    resolve: Resolve,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

/// A unique identifier for a crate
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct Crate<'a>(&'a str); // (name,)

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
struct CrateVersion<'a>(&'a str, &'a str); // (name, version)

impl<'a> Crate<'a> {
    pub fn id_str(&self) -> String {
        format!("{} ", self.0)
    }
}

impl<'a> CrateVersion<'a> {
    /// Returns the struct and whether or not the dep is in-tree
    pub fn from_str(s: &'a str) -> (Self, bool) {
        let mut parts = s.split(" ");
        let name = parts.next().unwrap();
        let version = parts.next().unwrap();
        let path = parts.next().unwrap();

        let is_path_dep = path.starts_with("(path+");

        (CrateVersion(name, version), is_path_dep)
    }

    pub fn id_str(&self) -> String {
        format!("{} {}", self.0, self.1)
    }
}

impl<'a> From<CrateVersion<'a>> for Crate<'a> {
    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
        Crate(cv.0)
    }
}

/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
///
/// Specifically, this checks that the license is correct.
pub fn check(path: &Path, bad: &mut bool) {
    // Check licences
    let path = path.join("vendor");
    assert!(path.exists(), "vendor directory missing");
    let mut saw_dir = false;
    for dir in t!(path.read_dir()) {
        saw_dir = true;
        let dir = t!(dir);

        // skip our exceptions
        if EXCEPTIONS.iter().any(|exception| {
            dir.path()
                .to_str()
                .unwrap()
                .contains(&format!("src/vendor/{}", exception))
        }) {
            continue;
        }

        let toml = dir.path().join("Cargo.toml");
        *bad = *bad || !check_license(&toml);
    }
    assert!(saw_dir, "no vendored source");
}

/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
/// failed.
///
/// Specifically, this checks that the dependencies are on the WHITELIST.
pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
    // Get dependencies from cargo metadata
    let resolve = get_deps(path, cargo);

    // Get the whitelist into a convenient form
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
        unapproved.append(&mut bad);
    }

    if unapproved.len() > 0 {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep.id_str());
        }
        *bad = true;
    }
}

fn check_license(path: &Path) -> bool {
    if !path.exists() {
        panic!("{} does not exist", path.display());
    }
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    let mut found_license = false;
    for line in contents.lines() {
        if !line.starts_with("license") {
            continue;
        }
        let license = extract_license(line);
        if !LICENSES.contains(&&*license) {
            println!("invalid license {} in {}", license, path.display());
            return false;
        }
        found_license = true;
        break;
    }
    if !found_license {
        println!("no license in {}", path.display());
        return false;
    }

    true
}

fn extract_license(line: &str) -> String {
    let first_quote = line.find('"');
    let last_quote = line.rfind('"');
    if let (Some(f), Some(l)) = (first_quote, last_quote) {
        let license = &line[f + 1..l];
        license.into()
    } else {
        "bad-license-parse".into()
    }
}

/// Get the dependencies of the crate at the given path using `cargo metadata`.
fn get_deps(path: &Path, cargo: &Path) -> Resolve {
    // Run `cargo metadata` to get the set of dependencies
    let output = Command::new(cargo)
        .arg("metadata")
        .arg("--format-version")
        .arg("1")
        .arg("--manifest-path")
        .arg(path.join("Cargo.toml"))
        .output()
        .expect("Unable to run `cargo metadata`")
        .stdout;
    let output = String::from_utf8_lossy(&output);
    let output: Output = serde_json::from_str(&output).unwrap();

    output.resolve
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a, 'b>(
    whitelist: &'a HashSet<Crate>,
    resolve: &'a Resolve,
    visited: &'b mut BTreeSet<CrateVersion<'a>>,
    krate: CrateVersion<'a>,
    must_be_on_whitelist: bool,
) -> BTreeSet<Crate<'a>> {
    // Will contain bad deps
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate
    if visited.contains(&krate) {
        return unapproved;
    }

    visited.insert(krate);

    // If this path is in-tree, we don't require it to be on the whitelist
    if must_be_on_whitelist {
        // If this dependency is not on the WHITELIST, add to bad set
        if !whitelist.contains(&krate.into()) {
            unapproved.insert(krate.into());
        }
    }

    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
    let to_check = resolve
        .nodes
        .iter()
        .find(|n| n.id.starts_with(&krate.id_str()))
        .expect("crate does not exist");

    for dep in to_check.dependencies.iter() {
        let (krate, is_path_dep) = CrateVersion::from_str(dep);

        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
        unapproved.append(&mut bad);
    }

    unapproved
}
<|endoftext|>


<commit_before><commit_msg>Simplify some auxiliary functions.<commit_after><|endoftext|>


<commit_before>use nom::{Consumer, FileProducer};
use std::io::{Error, ErrorKind, Result};
use std::u32;

use metadata::{
  Block, BlockData,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};
use metadata::types::MetaDataConsumer;

// Will return true when the unwrapped value of `$option` and `$compare`
// match or `$option` is `Option::None`, otherwise false.
macro_rules! optional_eq (
  ($compare: expr, $option: expr) => (
    $option.map_or(true, |compare| $compare == compare);
  );
);

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Block>> {
  FileProducer::new(filename, 1024).and_then(|mut producer| {
    let mut consumer = MetaDataConsumer::new();

    consumer.run(&mut producer);

    if !consumer.data.is_empty() {
      Ok(consumer.data)
    } else {
      let error_str = "parser: couldn't find any metadata";

      Err(Error::new(ErrorKind::InvalidData, error_str))
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let BlockData::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq!(picture.picture_type, picture_type) &&
           optional_eq!(picture.mime_type, mime_type) &&
           optional_eq!(picture.description, description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

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

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq!(0, Some(1)));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq!(0, None), "Should always return true when None");
    assert!(optional_eq!(0, Some(0)), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<commit_msg>Add examples for `get_vorbis_comment`<commit_after>use nom::{Consumer, FileProducer};
use std::io::{Error, ErrorKind, Result};
use std::u32;

use metadata::{
  Block, BlockData,
  StreamInfo, CueSheet, VorbisComment, Picture,
  PictureType,
};
use metadata::types::MetaDataConsumer;

// Will return true when the unwrapped value of `$option` and `$compare`
// match or `$option` is `Option::None`, otherwise false.
macro_rules! optional_eq (
  ($compare: expr, $option: expr) => (
    $option.map_or(true, |compare| $compare == compare);
  );
);

// With the given filename, return all metadata blocks available.
//
// This function expects a flac file, but will return a proper `Result::Err`
// when things go wrong.
//
// # Failures
//
// * `ErrorKind::NotFound` is returned when the given filename isn't found.
// * `ErrorKind::InvalidData` is returned when the data within the file
//   isn't valid FLAC data.
pub fn get_metadata(filename: &str) -> Result<Vec<Block>> {
  FileProducer::new(filename, 1024).and_then(|mut producer| {
    let mut consumer = MetaDataConsumer::new();

    consumer.run(&mut producer);

    if !consumer.data.is_empty() {
      Ok(consumer.data)
    } else {
      let error_str = "parser: couldn't find any metadata";

      Err(Error::new(ErrorKind::InvalidData, error_str))
    }
  })
}

/// Reads and returns the `StreamInfo` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `StreamInfo` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_stream_info("path/to/file.flac") {
///   Ok(stream_info) => {
///     // Use the stream_info variable...
///   }
///   Err(error)      => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let stream_info = metadata::get_stream_info("path/to/file.flac").unwrap();
/// ```
pub fn get_stream_info(filename: &str) -> Result<StreamInfo> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find StreamInfo";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::StreamInfo(stream_info) = block.data {
        result = Ok(stream_info);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `VorbisComment` metadata block of the given FLAC
/// file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `VorbisComment` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
///
/// # Examples
///
/// Handling errors might look something like this:
///
/// ```
/// use flac::metadata;
///
/// match metadata::get_vorbis_comment("path/to/file.flac") {
///   Ok(vorbis_comment) => {
///     // Use the vorbis_comment variable...
///   }
///   Err(error)         => println!("{}", error),
/// }
/// ```
///
/// Or just ignore the errors:
///
/// ```no_run
/// use flac::metadata;
///
/// let vorbis_comment =
///   metadata::get_vorbis_comment("path/to/file.flac").unwrap();
/// ```
pub fn get_vorbis_comment(filename: &str) -> Result<VorbisComment> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find VorbisComment";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::VorbisComment(vorbis_comment) = block.data {
        result = Ok(vorbis_comment);
        break;
      }
    }

    result
  })
}

/// Reads and returns the `CueSheet` metadata block of the given FLAC file.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found
///   or there is no `CueSheet` within the file.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
pub fn get_cue_sheet(filename: &str) -> Result<CueSheet> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find CueSheet";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    for block in blocks {
      if let BlockData::CueSheet(cue_sheet) = block.data {
        result = Ok(cue_sheet);
        break;
      }
    }

    result
  })
}

/// Reads and returns a `Picture` metadata block of the given FLAC file.
///
/// There can be more than one `Picture` block in a file and this function
/// takes optional, that being `Option<T>`, parameters that act as
/// constraints to search within. The `Picture` with the largest area
/// matching all constraints will be returned.
///
/// Putting `None` into any of the optional constraints conveys that you
/// want any of that parameter. Otherwise it will try to look for the image
/// that matches within the given constraints.
///
/// # Failures
///
/// * `ErrorKind::NotFound` is returned when the given filename isn't found,
///   there is no `Picture` within the file, or no `Picture` that fits the
///   given constraints.
/// * `ErrorKind::InvalidData` is returned when the data within the file
///   isn't valid FLAC data.
pub fn get_picture(filename: &str,
                   picture_type: Option<PictureType>,
                   mime_type: Option<&str>,
                   description: Option<&str>,
                   max_width: Option<u32>,
                   max_height: Option<u32>,
                   max_depth: Option<u32>,
                   max_colors: Option<u32>)
                   -> Result<Picture> {
  get_metadata(filename).and_then(|blocks| {
    let error_str  = "metadata: couldn't find any Picture";
    let mut result = Err(Error::new(ErrorKind::NotFound, error_str));

    let mut max_area_seen  = 0;
    let mut max_depth_seen = 0;

    let max_value      = u32::max_value();
    let max_width_num  = max_width.unwrap_or(max_value);
    let max_height_num = max_height.unwrap_or(max_value);
    let max_depth_num  = max_depth.unwrap_or(max_value);
    let max_colors_num = max_colors.unwrap_or(max_value);

    for block in blocks {
      if let BlockData::Picture(picture) = block.data {
        let area = (picture.width as u64) * (picture.height as u64);

        if optional_eq!(picture.picture_type, picture_type) &&
           optional_eq!(picture.mime_type, mime_type) &&
           optional_eq!(picture.description, description) &&
           picture.width <= max_width_num &&
           picture.height <= max_height_num &&
           picture.depth <= max_depth_num &&
           picture.colors <= max_colors_num &&
           (area > max_area_seen || (area == max_area_seen &&
                                     picture.depth > max_depth_seen)) {
          max_area_seen  = area;
          max_depth_seen = picture.depth;
          result         = Ok(picture);
        }
      }
    }

    result
  })
}

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

  #[test]
  #[should_panic]
  fn test_panic_optional_eq() {
    assert!(optional_eq!(0, Some(1)));
  }

  #[test]
  fn test_optional_eq() {
    assert!(optional_eq!(0, None), "Should always return true when None");
    assert!(optional_eq!(0, Some(0)), "Should return true (Some(0) == 0)");
  }

  #[test]
  fn test_get_metadata() {
    let not_found    = get_metadata("non-existent/file.txt");
    let invalid_data = get_metadata("README.md");
    let result       = get_metadata("tests/assets/input-SVAUP.flac");

    assert_eq!(not_found.unwrap_err().kind(), ErrorKind::NotFound);
    assert_eq!(invalid_data.unwrap_err().kind(), ErrorKind::InvalidData);
    assert!(result.is_ok());
  }
}
<|endoftext|>


<commit_before><commit_msg>Fix tests<commit_after>//! Register commands on the registry.

use std::sync::Arc;
use std::process::Command;
use std::thread;
use std::env;
use std::io::prelude::*;

use registry::{self, RegistryValue, CommandFn};
use layout::tree::try_lock_tree;
use lua::{self, LuaQuery};

/// Register the default commands on the registry.
///
/// Some of this code will be moved to be called after the config,
/// and will be registered dynamically.
pub fn register_defaults() {
    let mut reg = registry::write_lock();

    let mut register = |name: &'static str, val: CommandFn| {
        reg.insert(name.to_string(), RegistryValue::new_command(val));
    };

    // Workspace
    register("quit", Arc::new(quit));
    register("launch_terminal", Arc::new(launch_terminal));
    register("launch_dmenu", Arc::new(launch_dmenu));
    register("print_pointer", Arc::new(print_pointer));

    register("dmenu_eval", Arc::new(dmenu_eval));
    register("dmenu_lua_dofile", Arc::new(dmenu_lua_dofile));

    //register("workspace_left", workspace_left);
    //register("workspace_right", workspace_right);

    /// Generate switch_workspace methods and register them in $map
    macro_rules! gen_switch_workspace {
        ( $($b:ident, $n:expr);+ ) => {
            $(fn $b() {
                trace!("Switching to workspace {}", $n);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.switch_workspace(&$n.to_string());
                }
            }
            register(stringify!($b), Arc::new($b)); )+
        }
    }

    gen_switch_workspace!(switch_workspace_1, "1";
                          switch_workspace_2, "2";
                          switch_workspace_3, "3";
                          switch_workspace_4, "4";
                          switch_workspace_5, "5";
                          switch_workspace_6, "6";
                          switch_workspace_7, "7";
                          switch_workspace_8, "8";
                          switch_workspace_9, "9";
                          switch_workspace_0, "0");

}

// All of the methods defined should be registered.
#[deny(dead_code)]

fn launch_terminal() {
    let term = env::var("WAYLAND_TERMINAL")
        .unwrap_or("weston-terminal".to_string());

    Command::new("sh").arg("-c")
        .arg(term)
        .spawn().expect("Error launching terminal");
}

fn launch_dmenu() {
    Command::new("sh").arg("-c")
        .arg("dmenu_run")
        .spawn().expect("Error launching terminal");
}

fn print_pointer() {
    use lua;
    use lua::LuaQuery;

    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::send(LuaQuery::Execute(code))
        .expect("Error telling Lua to get pointer coords");
}

fn quit() {
    info!("Closing way cooler!!");
    ::rustwlc::terminate();
}

#[allow(unused_variables)]
fn dmenu_lua_dofile() {
    thread::Builder::new().name("dmenu_dofile".to_string()).spawn(|| {
        let child = Command::new("dmenu").arg("-p 'Eval Lua file'")
            .spawn().expect("Unable to launch dmenu!");

        // Write \d to stdin to prevent options from being given
        let stdin = child.stdin.expect("Unable to access stdin");
        //stdin.write_all(b"\d");

        let mut stdout = child.stdout.expect("Unable to access stdout");
        let mut output = String::new();
        stdout.read_to_string(&mut output).expect("Unable to read stdout");

        lua::send(LuaQuery::ExecFile(output)).expect("unable to contact Lua");
    }).expect("Unable to spawn thread");
}

#[allow(unused_variables)]
fn dmenu_eval() {
       thread::Builder::new().name("dmenu_eval".to_string()).spawn(|| {
        let child = Command::new("dmenu").arg("-p 'Eval Lua code'")
            .spawn().expect("Unable to launch dmenu!");

        // Write \d to stdin to prevent options from being given
        let stdin = child.stdin.expect("Unable to access stdin");
        //stdin.write_all(b"\d");

        let mut stdout = child.stdout.expect("Unable to access stdout");
        let mut output = String::new();
        stdout.read_to_string(&mut output).expect("Unable to read stdout");

        lua::send(LuaQuery::Execute(output)).expect("Unable to contact Lua");
    }).expect("Unable to spawn thread");
}
<|endoftext|>


<commit_before><commit_msg>privatize some needlessly public methods<commit_after><|endoftext|>


<commit_before><commit_msg>Reduce macro iterations to 32<commit_after><|endoftext|>