<commit_before>#![cfg(target_os = "windows")]

use std::mem;
use std::ptr;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::os::raw::c_int;
use std::sync::{
    Arc,
    Mutex
};
use std::sync::mpsc::Receiver;
use {CreationError, Event, MouseCursor};
use CursorState;

use WindowAttributes;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub parent: Option<winapi::HWND>,
}

unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};

use winapi;
use user32;
use kernel32;

mod callback;
mod event;
mod init;
mod monitor;

lazy_static! {
    static ref WAKEUP_MSG_ID: u32 = unsafe { user32::RegisterWindowMessageA("Glutin::EventID".as_ptr() as *const i8) };
}

/// Cursor
pub type Cursor = *const winapi::wchar_t;

/// Contains information about states and the window for the callback.
#[derive(Clone)]
pub struct WindowState {
    pub cursor: Cursor,
    pub cursor_state: CursorState,
    pub attributes: WindowAttributes
}

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: WindowWrapper,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// The current window state.
    window_state: Arc<Mutex<WindowState>>,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

/// A simple wrapper that destroys the window when it is destroyed.
#[doc(hidden)]
pub struct WindowWrapper(winapi::HWND, winapi::HDC);

impl Drop for WindowWrapper {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::DestroyWindow(self.0);
        }
    }
}

#[derive(Clone)]
pub struct WindowProxy {
    pub hwnd: winapi::HWND,
}

unsafe impl Send for WindowProxy {}
unsafe impl Sync for WindowProxy {}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unsafe {
            user32::PostMessageA(self.hwnd, *WAKEUP_MSG_ID, 0, 0);
        }
    }
}

impl Window {
    /// See the docs in the crate root file.
    pub fn new(window: &WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window, CreationError>
    {
        init::new_window(window, pl_attribs)
    }

    /// See the docs in the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
                                   .collect::<Vec<_>>();

        unsafe {
            user32::SetWindowTextW(self.window.0, text.as_ptr() as winapi::LPCWSTR);
        }
    }

    #[inline]
    pub fn show(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_SHOW);
        }
    }

    #[inline]
    pub fn hide(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_HIDE);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_position(&self) -> Option<(i32, i32)> {
        use std::mem;

        let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;

        if unsafe { user32::GetWindowPlacement(self.window.0, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as i32, rect.top as i32))
    }

    /// See the docs in the crate root file.
    pub fn set_position(&self, x: i32, y: i32) {
        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), x as c_int, y as c_int,
                                 0, 0, winapi::SWP_NOZORDER | winapi::SWP_NOSIZE);
            user32::UpdateWindow(self.window.0);
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    pub fn set_inner_size(&self, x: u32, y: u32) {
        unsafe {
            // Calculate the outer size based upon the specified inner size
            let mut rect = winapi::RECT { top: 0, left: 0, bottom: y as winapi::LONG, right: x as winapi::LONG };
            let dw_style = user32::GetWindowLongA(self.window.0, winapi::GWL_STYLE) as winapi::DWORD;
            let b_menu = !user32::GetMenu(self.window.0).is_null() as winapi::BOOL;
            let dw_style_ex = user32::GetWindowLongA(self.window.0, winapi::GWL_EXSTYLE) as winapi::DWORD;
            user32::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
            let outer_x = (rect.right - rect.left).abs() as c_int;
            let outer_y = (rect.top - rect.bottom).abs() as c_int;

            user32::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, outer_x, outer_y,
                winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION | winapi::SWP_NOMOVE);
            user32::UpdateWindow(self.window.0);
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy { hwnd: self.window.0 }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut ::libc::c_void {
        // What should this return on win32?
        // It could be GetDC(NULL), but that requires a ReleaseDC()
        // to avoid leaking the DC.
        ptr::null_mut()
    }

    #[inline]
    pub fn platform_window(&self) -> *mut ::libc::c_void {
        self.window.0 as *mut ::libc::c_void
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        let cursor_id = match _cursor {
            MouseCursor::Arrow | MouseCursor::Default => winapi::IDC_ARROW,
            MouseCursor::Hand => winapi::IDC_HAND,
            MouseCursor::Crosshair => winapi::IDC_CROSS,
            MouseCursor::Text | MouseCursor::VerticalText => winapi::IDC_IBEAM,
            MouseCursor::NotAllowed | MouseCursor::NoDrop => winapi::IDC_NO,
            MouseCursor::EResize => winapi::IDC_SIZEWE,
            MouseCursor::NResize => winapi::IDC_SIZENS,
            MouseCursor::WResize => winapi::IDC_SIZEWE,
            MouseCursor::SResize => winapi::IDC_SIZENS,
            MouseCursor::EwResize | MouseCursor::ColResize => winapi::IDC_SIZEWE,
            MouseCursor::NsResize | MouseCursor::RowResize => winapi::IDC_SIZENS,
            MouseCursor::Wait | MouseCursor::Progress => winapi::IDC_WAIT,
            MouseCursor::Help => winapi::IDC_HELP,
            _ => winapi::IDC_ARROW, // use arrow for the missing cases.
        };

        let mut cur = self.window_state.lock().unwrap();
        cur.cursor = cursor_id;
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        let mut current_state = self.window_state.lock().unwrap();

        let foreground_thread_id = unsafe { user32::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) };
        let current_thread_id = unsafe { kernel32::GetCurrentThreadId() };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 1) };

        let res = match (state, current_state.cursor_state) {
            (CursorState::Normal, CursorState::Normal) => Ok(()),
            (CursorState::Hide, CursorState::Hide) => Ok(()),
            (CursorState::Grab, CursorState::Grab) => Ok(()),

            (CursorState::Hide, CursorState::Normal) => {
                current_state.cursor_state = CursorState::Hide;
                Ok(())
            },

            (CursorState::Normal, CursorState::Hide) => {
                current_state.cursor_state = CursorState::Normal;
                Ok(())
            },

            (CursorState::Grab, CursorState::Normal) | (CursorState::Grab, CursorState::Hide) => {
                unsafe {
                    let mut rect = mem::uninitialized();
                    if user32::GetClientRect(self.window.0, &mut rect) == 0 {
                        return Err(format!("GetWindowRect failed"));
                    }
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.left));
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.right));
                    if user32::ClipCursor(&rect) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    current_state.cursor_state = CursorState::Grab;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Grab) => {
                unsafe {
                    if user32::ClipCursor(ptr::null()) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    current_state.cursor_state = CursorState::Normal;
                    Ok(())
                }
            },

            _ => unimplemented!(),
        };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) };

        res
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        let mut point = winapi::POINT {
            x: x,
            y: y,
        };

        unsafe {
            if user32::ClientToScreen(self.window.0, &mut point) == 0 {
                return Err(());
            }

            if user32::SetCursorPos(point.x, point.y) == 0 {
                return Err(());
            }
        }

        Ok(())
    }
}

impl Drop for Window {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::PostMessageW(self.window.0, winapi::WM_DESTROY, 0, 0);
        }
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.try_recv().ok()
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.recv().ok()
    }
}
<commit_msg>remove useless pub<commit_after>#![cfg(target_os = "windows")]

use std::mem;
use std::ptr;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use std::os::raw::c_int;
use std::sync::{
    Arc,
    Mutex
};
use std::sync::mpsc::Receiver;
use {CreationError, Event, MouseCursor};
use CursorState;

use WindowAttributes;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub parent: Option<winapi::HWND>,
}

unsafe impl Send for PlatformSpecificWindowBuilderAttributes {}
unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub use self::monitor::{MonitorId, get_available_monitors, get_primary_monitor};

use winapi;
use user32;
use kernel32;

mod callback;
mod event;
mod init;
mod monitor;

lazy_static! {
    static ref WAKEUP_MSG_ID: u32 = unsafe { user32::RegisterWindowMessageA("Glutin::EventID".as_ptr() as *const i8) };
}

/// Cursor
pub type Cursor = *const winapi::wchar_t;

/// Contains information about states and the window for the callback.
#[derive(Clone)]
pub struct WindowState {
    pub cursor: Cursor,
    pub cursor_state: CursorState,
    pub attributes: WindowAttributes
}

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: WindowWrapper,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// The current window state.
    window_state: Arc<Mutex<WindowState>>,
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

/// A simple wrapper that destroys the window when it is destroyed.
#[doc(hidden)]
pub struct WindowWrapper(winapi::HWND, winapi::HDC);

impl Drop for WindowWrapper {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::DestroyWindow(self.0);
        }
    }
}

#[derive(Clone)]
pub struct WindowProxy {
    hwnd: winapi::HWND,
}

unsafe impl Send for WindowProxy {}
unsafe impl Sync for WindowProxy {}

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unsafe {
            user32::PostMessageA(self.hwnd, *WAKEUP_MSG_ID, 0, 0);
        }
    }
}

impl Window {
    /// See the docs in the crate root file.
    pub fn new(window: &WindowAttributes, pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window, CreationError>
    {
        init::new_window(window, pl_attribs)
    }

    /// See the docs in the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        let text = OsStr::new(text).encode_wide().chain(Some(0).into_iter())
                                   .collect::<Vec<_>>();

        unsafe {
            user32::SetWindowTextW(self.window.0, text.as_ptr() as winapi::LPCWSTR);
        }
    }

    #[inline]
    pub fn show(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_SHOW);
        }
    }

    #[inline]
    pub fn hide(&self) {
        unsafe {
            user32::ShowWindow(self.window.0, winapi::SW_HIDE);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_position(&self) -> Option<(i32, i32)> {
        use std::mem;

        let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;

        if unsafe { user32::GetWindowPlacement(self.window.0, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as i32, rect.top as i32))
    }

    /// See the docs in the crate root file.
    pub fn set_position(&self, x: i32, y: i32) {
        unsafe {
            user32::SetWindowPos(self.window.0, ptr::null_mut(), x as c_int, y as c_int,
                                 0, 0, winapi::SWP_NOZORDER | winapi::SWP_NOSIZE);
            user32::UpdateWindow(self.window.0);
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetClientRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let mut rect: winapi::RECT = unsafe { mem::uninitialized() };

        if unsafe { user32::GetWindowRect(self.window.0, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as u32,
            (rect.bottom - rect.top) as u32
        ))
    }

    /// See the docs in the crate root file.
    pub fn set_inner_size(&self, x: u32, y: u32) {
        unsafe {
            // Calculate the outer size based upon the specified inner size
            let mut rect = winapi::RECT { top: 0, left: 0, bottom: y as winapi::LONG, right: x as winapi::LONG };
            let dw_style = user32::GetWindowLongA(self.window.0, winapi::GWL_STYLE) as winapi::DWORD;
            let b_menu = !user32::GetMenu(self.window.0).is_null() as winapi::BOOL;
            let dw_style_ex = user32::GetWindowLongA(self.window.0, winapi::GWL_EXSTYLE) as winapi::DWORD;
            user32::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
            let outer_x = (rect.right - rect.left).abs() as c_int;
            let outer_y = (rect.top - rect.bottom).abs() as c_int;

            user32::SetWindowPos(self.window.0, ptr::null_mut(), 0, 0, outer_x, outer_y,
                winapi::SWP_NOZORDER | winapi::SWP_NOREPOSITION | winapi::SWP_NOMOVE);
            user32::UpdateWindow(self.window.0);
        }
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy { hwnd: self.window.0 }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self,
        }
    }

    /// See the docs in the crate root file.
    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self,
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut ::libc::c_void {
        // What should this return on win32?
        // It could be GetDC(NULL), but that requires a ReleaseDC()
        // to avoid leaking the DC.
        ptr::null_mut()
    }

    #[inline]
    pub fn platform_window(&self) -> *mut ::libc::c_void {
        self.window.0 as *mut ::libc::c_void
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        let cursor_id = match _cursor {
            MouseCursor::Arrow | MouseCursor::Default => winapi::IDC_ARROW,
            MouseCursor::Hand => winapi::IDC_HAND,
            MouseCursor::Crosshair => winapi::IDC_CROSS,
            MouseCursor::Text | MouseCursor::VerticalText => winapi::IDC_IBEAM,
            MouseCursor::NotAllowed | MouseCursor::NoDrop => winapi::IDC_NO,
            MouseCursor::EResize => winapi::IDC_SIZEWE,
            MouseCursor::NResize => winapi::IDC_SIZENS,
            MouseCursor::WResize => winapi::IDC_SIZEWE,
            MouseCursor::SResize => winapi::IDC_SIZENS,
            MouseCursor::EwResize | MouseCursor::ColResize => winapi::IDC_SIZEWE,
            MouseCursor::NsResize | MouseCursor::RowResize => winapi::IDC_SIZENS,
            MouseCursor::Wait | MouseCursor::Progress => winapi::IDC_WAIT,
            MouseCursor::Help => winapi::IDC_HELP,
            _ => winapi::IDC_ARROW, // use arrow for the missing cases.
        };

        let mut cur = self.window_state.lock().unwrap();
        cur.cursor = cursor_id;
    }

    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        let mut current_state = self.window_state.lock().unwrap();

        let foreground_thread_id = unsafe { user32::GetWindowThreadProcessId(self.window.0, ptr::null_mut()) };
        let current_thread_id = unsafe { kernel32::GetCurrentThreadId() };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 1) };

        let res = match (state, current_state.cursor_state) {
            (CursorState::Normal, CursorState::Normal) => Ok(()),
            (CursorState::Hide, CursorState::Hide) => Ok(()),
            (CursorState::Grab, CursorState::Grab) => Ok(()),

            (CursorState::Hide, CursorState::Normal) => {
                current_state.cursor_state = CursorState::Hide;
                Ok(())
            },

            (CursorState::Normal, CursorState::Hide) => {
                current_state.cursor_state = CursorState::Normal;
                Ok(())
            },

            (CursorState::Grab, CursorState::Normal) | (CursorState::Grab, CursorState::Hide) => {
                unsafe {
                    let mut rect = mem::uninitialized();
                    if user32::GetClientRect(self.window.0, &mut rect) == 0 {
                        return Err(format!("GetWindowRect failed"));
                    }
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.left));
                    user32::ClientToScreen(self.window.0, mem::transmute(&mut rect.right));
                    if user32::ClipCursor(&rect) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    current_state.cursor_state = CursorState::Grab;
                    Ok(())
                }
            },

            (CursorState::Normal, CursorState::Grab) => {
                unsafe {
                    if user32::ClipCursor(ptr::null()) == 0 {
                        return Err(format!("ClipCursor failed"));
                    }
                    current_state.cursor_state = CursorState::Normal;
                    Ok(())
                }
            },

            _ => unimplemented!(),
        };

        unsafe { user32::AttachThreadInput(foreground_thread_id, current_thread_id, 0) };

        res
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        let mut point = winapi::POINT {
            x: x,
            y: y,
        };

        unsafe {
            if user32::ClientToScreen(self.window.0, &mut point) == 0 {
                return Err(());
            }

            if user32::SetCursorPos(point.x, point.y) == 0 {
                return Err(());
            }
        }

        Ok(())
    }
}

impl Drop for Window {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            user32::PostMessageW(self.window.0, winapi::WM_DESTROY, 0, 0);
        }
    }
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.try_recv().ok()
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        self.window.events_receiver.recv().ok()
    }
}
<|endoftext|>


<commit_before>#[test]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let output = std::process::Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["run", "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success());
}
<commit_msg>Improve fmt test failure message<commit_after>#[test]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let output = std::process::Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["run", "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(
        output.status.success(),
        "Formatting check failed. Run `./util/dev fmt` to update formatting."
    );
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate json;
extern crate requests;

// use requests::Codes;
use requests::{delete, get, head, post, put};
use requests::{Request, Response};

fn assert_response_is_ok(response: &Response, url: &str) {
    assert_eq!(response.url(), url);
    assert_eq!(response.status_code(), hyper::Ok);
    assert_eq!(response.reason(), "OK");
}

#[test]
fn simple_get() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    let data = res.json().unwrap();
    println!("{:?}", data);
    assert_eq!(data["url"], URL);
    assert_eq!(data["headers"]["Host"], "httpbin.org");
    assert_eq!(data["headers"]["User-Agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn simple_post() {
    const URL: &'static str = "http://httpbin.org/post";
    let res = post(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_put() {
    const URL: &'static str = "http://httpbin.org/put";
    let res = put(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_head() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = head(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_delete() {
    const URL: &'static str = "http://httpbin.org/delete";
    let res = delete(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn user_agent() {
    let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                            env!("CARGO_PKG_VERSION"),
                            "\"\n}\n");
    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.text(), Some(useragent));
}

#[test]
fn custom_user_agent() {
    const UA: &'static str = concat!("requests-rs-tests/", env!("CARGO_PKG_VERSION"));
    const URL: &'static str = "http://httpbin.org/user-agent";
    let mut request = Request::new();
    request.user_agent(UA);
    let res = request.get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"], UA);
}

#[test]
fn user_agent_json() {

    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn content() {
    const URL: &'static str = "http://httpbin.org/headers";
    let content = concat!("{\n  \"headers\": {\n    \"Host\": \"httpbin.org\",",
                          " \n    \"User-Agent\": \"requests-rs/",
                          env!("CARGO_PKG_VERSION"),
                          "\"\n  }\n}\n");

    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.content(), &content.as_bytes());
}

#[test]
fn headers() {
    use hyper::header::UserAgent;

    const URL: &'static str = "http://httpbin.org/response-headers?User-Agent=requests-rs-test";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    println!("{:?}", res.text());
    println!("{:?}", res.headers());
    println!("{:?}", res.headers().get::<UserAgent>());
    assert_eq!(res.headers().get::<UserAgent>().unwrap(),
               &UserAgent("requests-rs-test".to_owned()));
}

macro_rules! status_code_test {
    ($($name:ident: $numeric:expr,)+) => {
        $(#[test]
        fn $name() {
            let res = get(&format!("http://httpbin.org/status/{}", $numeric)).unwrap();
            println!("{}", res.text().unwrap());
            assert_eq!(res.status_code(), hyper::status::StatusCode::from_u16($numeric));
        })+
    }
}

status_code_test! {
    status_code_100: 100,
    status_code_101: 101,
    status_code_102: 102,
    status_code_200: 200,
    status_code_201: 201,
    status_code_202: 202,
    status_code_203: 203,
    status_code_400: 400,
    status_code_401: 401,
    status_code_402: 402,
    status_code_403: 403,
    status_code_404: 404,
    status_code_500: 500,
}
<commit_msg>Use re-exported type Codes instead of hyper::status::StatusCode<commit_after>extern crate hyper;
extern crate json;
extern crate requests;

// use requests::Codes;
use requests::{delete, get, head, post, put};
use requests::{Codes, Request, Response};

fn assert_response_is_ok(response: &Response, url: &str) {
    assert_eq!(response.url(), url);
    assert_eq!(response.status_code(), hyper::Ok);
    assert_eq!(response.reason(), "OK");
}

#[test]
fn simple_get() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    let data = res.json().unwrap();
    println!("{:?}", data);
    assert_eq!(data["url"], URL);
    assert_eq!(data["headers"]["Host"], "httpbin.org");
    assert_eq!(data["headers"]["User-Agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn simple_post() {
    const URL: &'static str = "http://httpbin.org/post";
    let res = post(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_put() {
    const URL: &'static str = "http://httpbin.org/put";
    let res = put(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_head() {
    const URL: &'static str = "http://httpbin.org/get";
    let res = head(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn simple_delete() {
    const URL: &'static str = "http://httpbin.org/delete";
    let res = delete(URL).unwrap();
    assert_response_is_ok(&res, URL);
}

#[test]
fn user_agent() {
    let useragent = concat!("{\n  \"user-agent\": \"requests-rs/",
                            env!("CARGO_PKG_VERSION"),
                            "\"\n}\n");
    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.text(), Some(useragent));
}

#[test]
fn custom_user_agent() {
    const UA: &'static str = concat!("requests-rs-tests/", env!("CARGO_PKG_VERSION"));
    const URL: &'static str = "http://httpbin.org/user-agent";
    let mut request = Request::new();
    request.user_agent(UA);
    let res = request.get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"], UA);
}

#[test]
fn user_agent_json() {

    const URL: &'static str = "http://httpbin.org/user-agent";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert!(res.is_json());

    let ua = res.json().unwrap();
    assert_eq!(ua["user-agent"],
               concat!("requests-rs/", env!("CARGO_PKG_VERSION")));
}

#[test]
fn content() {
    const URL: &'static str = "http://httpbin.org/headers";
    let content = concat!("{\n  \"headers\": {\n    \"Host\": \"httpbin.org\",",
                          " \n    \"User-Agent\": \"requests-rs/",
                          env!("CARGO_PKG_VERSION"),
                          "\"\n  }\n}\n");

    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    assert_eq!(res.content(), &content.as_bytes());
}

#[test]
fn headers() {
    use hyper::header::UserAgent;

    const URL: &'static str = "http://httpbin.org/response-headers?User-Agent=requests-rs-test";
    let res = get(URL).unwrap();
    assert_response_is_ok(&res, URL);
    println!("{:?}", res.text());
    println!("{:?}", res.headers());
    println!("{:?}", res.headers().get::<UserAgent>());
    assert_eq!(res.headers().get::<UserAgent>().unwrap(),
               &UserAgent("requests-rs-test".to_owned()));
}

macro_rules! status_code_test {
    ($($name:ident: $numeric:expr,)+) => {
        $(#[test]
        fn $name() {
            let res = get(&format!("http://httpbin.org/status/{}", $numeric)).unwrap();
            println!("{}", res.text().unwrap());
            assert_eq!(res.status_code(), Codes::from_u16($numeric));
        })+
    }
}

status_code_test! {
    status_code_100: 100,
    status_code_101: 101,
    status_code_102: 102,
    status_code_200: 200,
    status_code_201: 201,
    status_code_202: 202,
    status_code_203: 203,
    status_code_400: 400,
    status_code_401: 401,
    status_code_402: 402,
    status_code_403: 403,
    status_code_404: 404,
    status_code_500: 500,
}
<|endoftext|>


<commit_before>extern crate oscillator;

use oscillator::Oscillator;

// TODO
<commit_msg>Add tests<commit_after>#![allow(dead_code)]

extern crate oscillator;
extern crate stopwatch;

use oscillator::Oscillator;
use stopwatch::Stopwatch;

fn assert_near(a : f32, b : f32) {
    assert!((a-b).abs() < 0.05)
}

#[test]
fn test_new() {
    let mut osc = Oscillator::new();
    assert_eq!(osc.get_value(), 1.0);
}

#[test]
fn test_null_freq() {
    let mut osc = Oscillator::start_new();
    osc.set_frequency(0.0);
    assert_eq!(osc.get_value(), 1.0);
}

#[test]
fn test_cycle() {
    let mut timer = Stopwatch::start_new();
    let mut osc = Oscillator::start_new();

    assert_near(osc.get_value(), 1.0);

    while timer.elapsed_ms() < 500 { }

    assert_near(osc.get_value(), 0.0);

    while timer.elapsed_ms() < 1000 { }

    assert_near(osc.get_value(), 1.0);
}

#[test]
fn test_freq() {
    let mut timer = Stopwatch::start_new();
    let mut osc = Oscillator::start_new();
    osc.set_frequency(0.5);

    assert_near(osc.get_value(), 1.0);

    while timer.elapsed_ms() < 1000 { }

    assert_near(osc.get_value(), 0.0);

    while timer.elapsed_ms() < 2000 { }

    assert_near(osc.get_value(), 1.0);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#![feature(inclusive_range_syntax)]

extern crate numeral;

use numeral::Cardinal;
use std::fs::File;
use std::io::{BufRead, BufReader};

macro_rules! test_call_on_min_max {
    ($fn_name:ident, $numtype:ty) => (
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().cardinal();
            <$numtype>::min_value().cardinal();
        }
    )
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);
test_call_on_min_max!(call_on_min_max_isize, isize);
test_call_on_min_max!(call_on_min_max_usize, usize);

macro_rules! test_call_on_range {
    ($fn_name:ident, $numtype:ty) => (
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::max_value()) {
                n.cardinal();
            }
        }
    )
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name:ident, $numtype:ty) => (
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::min_value()) + 130 {
                n.cardinal();
            }
            for n in (<$numtype>::max_value()) - 130..=(<$numtype>::max_value()) {
                n.cardinal();
            }
            if <$numtype>::min_value() != 0 {
                for n in -130..=130 {
                    n.cardinal();
                }
            }
        }
    )
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);
test_call_on_critical_ranges!(call_on_critical_ranges_isize, isize);
test_call_on_critical_ranges!(call_on_critical_ranges_usize, usize);

#[test]
fn cardinal_value_m256_256() {
    let file = File::open("tests/cardinal_m256..=256.txt").unwrap();
    assert!(BufReader::new(file).lines()
            .map(|n_str| n_str.unwrap())
            .eq((-256..=256).map(|n: i32| n.cardinal())));
}

#[test]
fn cardinal_value_min_max_int() {
    let file = File::open("tests/cardinal_min_max.txt").unwrap();
    let mut lines = BufReader::new(file).lines().map(|n_str| n_str.unwrap());
    macro_rules! assert_eq_min_max {
        ($signed:ty, $unsigned:ty) => (
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().cardinal());
        )
    }
    assert_eq!(lines.next().unwrap(), 0.cardinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}

#[test]
fn cardinal_value_min_max_ptr() {
    use std::mem::size_of;

    macro_rules! assert_eq_min_max_if_ptr_is {
        ($ptr:ty, $int:ty) => (
            if size_of::<$ptr>() == size_of::<$int>() {
                assert_eq!(<$ptr>::min_value().cardinal(), <$int>::min_value().cardinal());
                assert_eq!(<$ptr>::max_value().cardinal(), <$int>::max_value().cardinal());
            }
        )
    }
    assert_eq_min_max_if_ptr_is!(isize, i8);
    assert_eq_min_max_if_ptr_is!(isize, i16);
    assert_eq_min_max_if_ptr_is!(isize, i32);
    assert_eq_min_max_if_ptr_is!(isize, i64);
    assert_eq_min_max_if_ptr_is!(usize, u8);
    assert_eq_min_max_if_ptr_is!(usize, u16);
    assert_eq_min_max_if_ptr_is!(usize, u32);
    assert_eq_min_max_if_ptr_is!(usize, u64);
}
<commit_msg>rustfmt, use String instead of BufReader<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#![feature(inclusive_range_syntax)]

extern crate numeral;

use numeral::Cardinal;

fn read_file(filename: &str) -> Result<String, std::io::Error> {
    use std::fs::File;
    use std::io::Read;

    let mut file = File::open(filename)?;
    let mut buffer = String::new();
    file.read_to_string(&mut buffer)?;
    Ok(buffer)
}

macro_rules! test_call_on_min_max {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            <$numtype>::max_value().cardinal();
            <$numtype>::min_value().cardinal();
        }
    };
}

test_call_on_min_max!(call_on_min_max_i8, i8);
test_call_on_min_max!(call_on_min_max_u8, u8);
test_call_on_min_max!(call_on_min_max_i16, i16);
test_call_on_min_max!(call_on_min_max_u16, u16);
test_call_on_min_max!(call_on_min_max_i32, i32);
test_call_on_min_max!(call_on_min_max_u32, u32);
test_call_on_min_max!(call_on_min_max_i64, i64);
test_call_on_min_max!(call_on_min_max_u64, u64);
test_call_on_min_max!(call_on_min_max_isize, isize);
test_call_on_min_max!(call_on_min_max_usize, usize);

macro_rules! test_call_on_range {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::max_value()) {
                n.cardinal();
            }
        }
    };
}

test_call_on_range!(call_on_range_i8, i8);
test_call_on_range!(call_on_range_u8, u8);
test_call_on_range!(call_on_range_i16, i16);
test_call_on_range!(call_on_range_u16, u16);

macro_rules! test_call_on_critical_ranges {
    ($fn_name:ident, $numtype:ty) => {
        #[test]
        fn $fn_name() {
            for n in (<$numtype>::min_value())..=(<$numtype>::min_value()) + 130 {
                n.cardinal();
            }
            for n in (<$numtype>::max_value()) - 130..=(<$numtype>::max_value()) {
                n.cardinal();
            }
            if <$numtype>::min_value() != 0 {
                for n in -130..=130 {
                    n.cardinal();
                }
            }
        }
    };
}

test_call_on_critical_ranges!(call_on_critical_ranges_i32, i32);
test_call_on_critical_ranges!(call_on_critical_ranges_u32, u32);
test_call_on_critical_ranges!(call_on_critical_ranges_i64, i64);
test_call_on_critical_ranges!(call_on_critical_ranges_u64, u64);
test_call_on_critical_ranges!(call_on_critical_ranges_isize, isize);
test_call_on_critical_ranges!(call_on_critical_ranges_usize, usize);

#[test]
fn cardinal_value_m256_256() {
    let cardinals = read_file("tests/cardinal_m256..=256.txt").unwrap();
    assert!(
        cardinals
            .lines()
            .eq((-256..=256).map(|n: i32| n.cardinal()))
    );
}

#[test]
fn cardinal_value_min_max_int() {
    let cardinals = read_file("tests/cardinal_min_max.txt").unwrap();
    let mut lines = cardinals.lines();
    macro_rules! assert_eq_min_max {
        ($signed:ty, $unsigned:ty) => {
            assert_eq!(lines.next().unwrap(), <$signed>::min_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$signed>::max_value().cardinal());
            assert_eq!(lines.next().unwrap(), <$unsigned>::max_value().cardinal());
        };
    }
    assert_eq!(lines.next().unwrap(), 0.cardinal());
    assert_eq_min_max!(i8, u8);
    assert_eq_min_max!(i16, u16);
    assert_eq_min_max!(i32, u32);
    assert_eq_min_max!(i64, u64);
}

#[test]
fn cardinal_value_min_max_ptr() {
    use std::mem::size_of;

    macro_rules! assert_eq_min_max_if_ptr_is {
        ($ptr:ty, $int:ty) => {
            if size_of::<$ptr>() == size_of::<$int>() {
                assert_eq!(<$ptr>::min_value().cardinal(), <$int>::min_value().cardinal());
                assert_eq!(<$ptr>::max_value().cardinal(), <$int>::max_value().cardinal());
            }
        };
    }
    assert_eq_min_max_if_ptr_is!(isize, i8);
    assert_eq_min_max_if_ptr_is!(isize, i16);
    assert_eq_min_max_if_ptr_is!(isize, i32);
    assert_eq_min_max_if_ptr_is!(isize, i64);
    assert_eq_min_max_if_ptr_is!(usize, u8);
    assert_eq_min_max_if_ptr_is!(usize, u16);
    assert_eq_min_max_if_ptr_is!(usize, u32);
    assert_eq_min_max_if_ptr_is!(usize, u64);
}
<|endoftext|>


<commit_before>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, macro_rules, quote)]

#![allow(unused_imports)]

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use docopt::{DEFAULT_CONFIG, Config, Docopt, ValueMap};
use docopt::parse::{
    Options,
    Atom, Short, Long, Command, Positional,
    Argument, Zero, One,
};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_name: ast::Ident,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, Gc<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_name;
        let full_doc = self.doc.parser().full_doc.as_slice();
        its.push(quote_item!(cx,
            impl docopt::FlagParser for $struct_name {
                #[allow(dead_code)]
                fn parse_args(conf: docopt::Config, args: &[&str])
                             -> Result<$struct_name, docopt::Error> {
                    docopt::docopt_args(conf, args, $full_doc).and_then(|v| {
                        v.decode()
                    })
                }
            }
        ).unwrap());
        MacItems::new(its)
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> Gc<ast::Item> {
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None,
            super_struct: None,
            is_virtual: false,
        };
        let sp = codemap::DUMMY_SP;
        let traits = vec![meta_item(cx, "Decodable"), meta_item(cx, "Show")];
        let deriving = cx.meta_list(sp, intern("deriving"), traits);
        let attrs = vec![cx.attribute(codemap::DUMMY_SP, deriving)];
        let st = cx.item_struct(sp, self.struct_name.clone(), def);
        cx.item(sp, self.struct_name.clone(), attrs, st.node.clone())
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ValueMap::key_to_struct_field(atom.to_string().as_slice());
            let ty = match self.types.find(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(name.as_slice(), ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> Gc<ast::Ty> {
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, String),
                    _ => quote_ty!(cx, bool),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, Vec<String>),
                    _ => quote_ty!(cx, uint),
                }
            }
            (false, &One(_)) => quote_ty!(cx, String),
            (true, &One(_)) => quote_ty!(cx, Vec<String>),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: Gc<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::EOF {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_name = self.p.parse_ident();
        self.p.expect(&token::COMMA);
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::COMMA),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::EOF, sep, |p| MacParser::parse_type_annotation(p)
        ).move_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ValueMap::struct_field_to_key(field_name.as_slice());
             (Atom::new(key.as_slice()), ty)
          })
         .collect::<HashMap<Atom, Gc<ast::Ty>>>();
        self.p.expect(&token::EOF);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(DEFAULT_CONFIG.clone(), docstr.as_slice()) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 format!("Invalid Docopt usage: {}",
                                         err).as_slice());
                return Err(());
            }
        };
        Ok(Parsed {
            struct_name: struct_name,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: Gc<ast::Lit>) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: Gc<ast::Lit>) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => fail!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(lit) if lit_is_str(lit) => lit_to_string(lit),
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, err.as_slice());
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, Gc<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::COLON);
        let ty = p.parse_ty(false);
        (ident, ty)
    }
}

/// MacItems is just like `syntax::ext::base::MacItem`, except it supports
/// writing multiple items.
struct MacItems {
    its: Vec<Gc<ast::Item>>,
}

impl MacResult for MacItems {
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        let mut small = SmallVector::zero();
        for it in self.its.iter() {
            small.push(it.clone());
        }
        Some(small)
    }
}

impl MacItems {
    fn new(its: Vec<Gc<ast::Item>>) -> Box<MacResult+'static> {
        box MacItems { its: its } as Box<MacResult+'static>
    }
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn meta_item(cx: &ExtCtxt, s: &str) -> Gc<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}
<commit_msg>Update to master<commit_after>#![crate_name = "docopt_macros"]
#![crate_type = "dylib"]
#![feature(plugin_registrar, macro_rules, quote)]

#![allow(unused_imports)]

extern crate syntax;
extern crate rustc;
extern crate docopt;

use std::collections::HashMap;

use rustc::plugin::Registry;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::common::SeqSep;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use docopt::{DEFAULT_CONFIG, Config, Docopt, ValueMap};
use docopt::parse::{
    Options,
    Atom, Short, Long, Command, Positional,
    Argument, Zero, One,
};

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("docopt", expand);
}

fn expand(cx: &mut ExtCtxt, span: codemap::Span, tts: &[ast::TokenTree])
         -> Box<MacResult+'static> {
    let parsed = match MacParser::new(cx, tts).parse() {
        Ok(parsed) => parsed,
        Err(_) => return DummyResult::any(span),
    };
    parsed.items(cx)
}

/// Parsed corresponds to the result of parsing a `docopt` macro call.
/// It can be used to write a corresponding struct.
struct Parsed {
    struct_name: ast::Ident,
    doc: Docopt,
    /// Overrided type annotations for struct members. May be empty.
    /// When a type annotation for an atom doesn't exist, then one is
    /// inferred automatically. It is one of: `bool`, `uint`, `String` or
    /// `Vec<String>`.
    types: HashMap<Atom, P<ast::Ty>>,
}

impl Parsed {
    /// Returns a macro result suitable for expansion.
    /// Contains two items: one for the struct and one for the struct impls.
    fn items(&self, cx: &ExtCtxt) -> Box<MacResult+'static> {
        let mut its = vec!();
        its.push(self.struct_decl(cx));

        let struct_name = self.struct_name;
        let full_doc = self.doc.parser().full_doc.as_slice();
        its.push(quote_item!(cx,
            impl docopt::FlagParser for $struct_name {
                #[allow(dead_code)]
                fn parse_args(conf: docopt::Config, args: &[&str])
                             -> Result<$struct_name, docopt::Error> {
                    docopt::docopt_args(conf, args, $full_doc).and_then(|v| {
                        v.decode()
                    })
                }
            }
        ).unwrap());
        MacItems::new(its)
    }

    /// Returns an item for the struct definition.
    fn struct_decl(&self, cx: &ExtCtxt) -> P<ast::Item> {
        let def = ast::StructDef {
            fields: self.struct_fields(cx),
            ctor_id: None,
            super_struct: None,
            is_virtual: false,
        };
        let sp = codemap::DUMMY_SP;
        let traits = vec![meta_item(cx, "Decodable"), meta_item(cx, "Show")];
        let deriving = cx.meta_list(sp, intern("deriving"), traits);
        let attrs = vec![cx.attribute(codemap::DUMMY_SP, deriving)];
        let st = cx.item_struct(sp, self.struct_name.clone(), def);
        cx.item(sp, self.struct_name.clone(), attrs, st.node.clone())
    }

    /// Returns a list of fields for the struct definition.
    /// Handles type annotations.
    fn struct_fields(&self, cx: &ExtCtxt) -> Vec<ast::StructField> {
        let mut fields: Vec<ast::StructField> = vec!();
        for (atom, opts) in self.doc.parser().descs.iter() {
            let name = ValueMap::key_to_struct_field(atom.to_string().as_slice());
            let ty = match self.types.find(atom) {
                None => self.pat_type(cx, atom, opts),
                Some(ty) => ty.clone(),
            };
            fields.push(self.mk_struct_field(name.as_slice(), ty));
        }
        fields
    }

    /// Returns an inferred type for a usage pattern.
    /// This is only invoked when a type annotation is not present.
    fn pat_type(&self, cx: &ExtCtxt, atom: &Atom, opts: &Options) -> P<ast::Ty> {
        match (opts.repeats, &opts.arg) {
            (false, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, String),
                    _ => quote_ty!(cx, bool),
                }
            }
            (true, &Zero) => {
                match atom {
                    &Positional(_) => quote_ty!(cx, Vec<String>),
                    _ => quote_ty!(cx, uint),
                }
            }
            (false, &One(_)) => quote_ty!(cx, String),
            (true, &One(_)) => quote_ty!(cx, Vec<String>),
        }
    }

    /// Creates a struct field from a member name and type.
    fn mk_struct_field(&self, name: &str, ty: P<ast::Ty>) -> ast::StructField {
        codemap::dummy_spanned(ast::StructField_ {
            kind: ast::NamedField(ident(name), ast::Public),
            id: ast::DUMMY_NODE_ID,
            ty: ty,
            attrs: vec!(),
        })
    }
}

/// State for parsing a `docopt` macro invocation.
struct MacParser<'a, 'b:'a> {
    cx: &'a mut ExtCtxt<'b>,
    p: Parser<'b>,
}

impl<'a, 'b> MacParser<'a, 'b> {
    fn new(cx: &'a mut ExtCtxt<'b>, tts: &[ast::TokenTree]) -> MacParser<'a, 'b> {
        let p = cx.new_parser_from_tts(tts);
        MacParser { cx: cx, p: p }
    }

    /// Main entry point for parsing arguments to `docopt` macro.
    /// First looks for an identifier for the struct name.
    /// Second, a string containing the docopt usage patterns.
    /// Third, an optional list of type annotations.
    fn parse(&mut self) -> Result<Parsed, ()> {
        if self.p.token == token::EOF {
            self.cx.span_err(self.cx.call_site(), "macro expects arguments");
            return Err(());
        }
        let struct_name = self.p.parse_ident();
        self.p.expect(&token::COMMA);
        let docstr = try!(self.parse_str());

        let sep = SeqSep {
            sep: Some(token::COMMA),
            trailing_sep_allowed: true,
        };
        let types = self.p.parse_seq_to_end(
            &token::EOF, sep, |p| MacParser::parse_type_annotation(p)
        ).move_iter()
         .map(|(ident, ty)| {
             let field_name = token::get_ident(ident).to_string();
             let key = ValueMap::struct_field_to_key(field_name.as_slice());
             (Atom::new(key.as_slice()), ty)
          })
         .collect::<HashMap<Atom, P<ast::Ty>>>();
        self.p.expect(&token::EOF);

        // This config does not matter because we're only asking for the
        // usage patterns in the Docopt string. The configuration does not
        // affect the retrieval of usage patterns.
        let doc = match Docopt::new(DEFAULT_CONFIG.clone(), docstr.as_slice()) {
            Ok(doc) => doc,
            Err(err) => {
                self.cx.span_err(self.cx.call_site(),
                                 format!("Invalid Docopt usage: {}",
                                         err).as_slice());
                return Err(());
            }
        };
        Ok(Parsed {
            struct_name: struct_name,
            doc: doc,
            types: types,
        })
    }

    /// Parses a single string literal. On failure, an error is logged and
    /// unit is returned.
    fn parse_str(&mut self) -> Result<String, ()> {
        fn lit_is_str(lit: &ast::Lit) -> bool {
            match lit.node {
                ast::LitStr(_, _) => true,
                _ => false,
            }
        }
        fn lit_to_string(lit: &ast::Lit) -> String {
            match lit.node {
                ast::LitStr(ref s, _) => s.to_string(),
                _ => fail!("BUG: expected string literal"),
            }
        }
        let exp = self.cx.expander().fold_expr(self.p.parse_expr());
        let s = match exp.node {
            ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
                lit_to_string(&**lit)
            }
            _ => {
                let err = format!("Expected string literal but got {}",
                                  pprust::expr_to_string(&*exp));
                self.cx.span_err(exp.span, err.as_slice());
                return Err(());
            }
        };
        self.p.bump();
        Ok(s)
    }

    /// Parses a type annotation in a `docopt` invocation of the form
    /// `ident: Ty`.
    /// Note that this is a static method as it is used as a HOF.
    fn parse_type_annotation(p: &mut Parser) -> (ast::Ident, P<ast::Ty>) {
        let ident = p.parse_ident();
        p.expect(&token::COLON);
        let ty = p.parse_ty(false);
        (ident, ty)
    }
}

/// MacItems is just like `syntax::ext::base::MacItem`, except it supports
/// writing multiple items.
struct MacItems {
    its: Vec<P<ast::Item>>,
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.its.move_iter().collect())
    }
}

impl MacItems {
    fn new(its: Vec<P<ast::Item>>) -> Box<MacResult+'static> {
        box MacItems { its: its } as Box<MacResult+'static>
    }
}

// Convenience functions for building intermediate values.

fn ident(s: &str) -> ast::Ident {
    ast::Ident::new(token::intern(s))
}

fn meta_item(cx: &ExtCtxt, s: &str) -> P<ast::MetaItem> {
    cx.meta_word(codemap::DUMMY_SP, intern(s))
}

fn intern(s: &str) -> token::InternedString {
    token::intern_and_get_ident(s)
}
<|endoftext|>


<commit_before>use std;
use std::io;
use std::path::Path;
use std::fs::File;
use std::fs::metadata;
use std::io::prelude::*;
use ansi_term;
use unic_char_range::CharRange;

use term_painter::{ToStyle, Color, Painted};
use term_painter::Attr::*;

use std::sync::mpsc::SyncSender;
use clean;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum InfoLevel {
    Quiet,
    Normal,
    Verbose,
}

static UTF8_ALLOWED_RANGES: &'static [CharRange] = &[
    // Basic Latin
    CharRange { low: '\u{0000}', high: '\u{007f}' },
    // Latin supplement -- without control characters and no-break space
    CharRange { low: '\u{00a1}', high: '\u{00ff}' },
    // Latin extended A
    CharRange { low: '\u{0100}', high: '\u{017f}' },
    // Latin extended B
    CharRange { low: '\u{0180}', high: '\u{024f}' },
    // Box drawing
    CharRange { low: '\u{2500}', high: '\u{257f}' },
    // Block elements
    CharRange { low: '\u{2580}', high: '\u{259f}' },
    // Geometric shapes
    CharRange { low: '\u{25a0}', high: '\u{25ff}' },
];

pub const HAS_TABS: u8 = 1 << 0;
pub const TRAILING_SPACES: u8 = 1 << 1;
pub const HAS_ILLEGAL_CHARACTERS: u8 = 1 << 2;
pub const LINE_TOO_LONG: u8 = 1 << 3;

fn check_content<'a>(input: &'a str,
                     filename: &str,
                     info_level: InfoLevel,
                     max_line_length: Option<usize>,
                     s: clean::TabStrategy,
                     logger: SyncSender<Option<String>>)
-> io::Result<u8> {
    let mut result = 0;
    let mut i: u32 = 0;
    for line in input.lines() {
        i += 1;
        max_line_length.map(|max_len| if line.len() > max_len {
            result |= LINE_TOO_LONG;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: LINE_TOO_LONG\n", filename, i)));
            }
        });
        if line.ends_with(' ') || line.ends_with('\t') {
            result |= TRAILING_SPACES;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: TRAILING_SPACES\n", filename, i)));
            }
        }
        if s == clean::TabStrategy::Untabify && line.contains("\t") {
            result |= HAS_TABS;
            if info_level == InfoLevel::Verbose {
                let _ = logger.send(Some(format!("{}, line {}: error: HAS_TABS\n", filename, i)));
            }
        }
        if !line.chars().all(|c| {
            UTF8_ALLOWED_RANGES.iter().any(|range| range.contains(c))
        }) {
            result |= HAS_ILLEGAL_CHARACTERS;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: non ASCII line\n", filename, i)));
            }
        }
    }
    if info_level == InfoLevel::Normal {
        if (result & LINE_TOO_LONG) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with LINE_TOO_LONG\n", filename)));
        }
        if (result & TRAILING_SPACES) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with TRAILING_SPACES\n", filename)));
        }
        if (result & HAS_TABS) > 0 {
            let _ = logger.send(Some(format!("{}, some lines with HAS_TABS\n", filename)));
        }
        if (result & HAS_ILLEGAL_CHARACTERS) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with non ASCII line\n", filename)));
        }
    }
    Ok(result)
}

pub fn is_dir(path: &Path) -> bool {
    if let Ok(result) = metadata(&path) {
        result.is_dir()
    } else {
        false
    }
}

fn report_offending_line(path: &Path, logger: SyncSender<Option<String>>) -> std::io::Result<()> {
    use std::io::BufReader;
    let mut i: u32 = 1;
    let f = File::open(path)?;
    let file = BufReader::new(f);
    for line in file.lines() {
        match line.ok() {
            Some(_) => i = i + 1,
            None => {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: non UTF-8 character in line\n",
                                             path.display(),
                                             i)));
            }
        }
    }
    Ok(())
}

pub fn check_path(path: &Path,
                  buf: &Vec<u8>,
                  clean: bool,
                  info_level: InfoLevel,
                  max_line_length: Option<usize>,
                  s: clean::TabStrategy,
                  logger: SyncSender<Option<String>>)
    -> io::Result<u8> {
        let mut check = 0;
        match std::str::from_utf8(buf) {
            Err(_) => {
                check = check | HAS_ILLEGAL_CHARACTERS;
                if info_level == InfoLevel::Verbose {
                    let _ = report_offending_line(path, logger);
                }
                return Ok(check);
            }
            Ok(buffer) => {
                if check == 0 {
                    check = check_content(&buffer,
                                          path.to_str().expect("not available"),
                                          info_level,
                                          max_line_length,
                                          s,
                                          logger.clone())?;
                }
                let no_trailing_ws = if (check & TRAILING_SPACES) > 0 && clean {
                    if info_level == InfoLevel::Verbose {
                        let _ =
                            logger.send(Some(format!("TRAILING_SPACES:[{}] -> removing\n",
                                                     path.display())));
                    }
                    clean::remove_trailing_whitespaces(buffer)
                } else {
                    buffer.to_string()
                };
                let res_string = if (check & HAS_TABS) > 0 && clean {
                    if info_level == InfoLevel::Verbose {
                        let _ = logger.send(Some(format!("HAS_TABS:[{}] -> converting to spaces\n",
                                                         path.display())));
                    }
                    clean::space_tabs_conversion(no_trailing_ws, clean::TabStrategy::Untabify)
                } else {
                    no_trailing_ws
                };
                if clean {
                    let mut file = File::create(path)?;
                    file.write_all(res_string.as_bytes())?;
                }
            }
        };
        // only check content if we could read the file
        Ok(check)
    }

#[allow(dead_code)]
#[cfg (not(target_os = "windows"))]
pub fn red(s: &str) -> ansi_term::ANSIString {
    ansi_term::Colour::Red.bold().paint(s)
}
#[allow(dead_code)]
#[cfg (not(target_os = "windows"))]
pub fn yellow(s: &str) -> ansi_term::ANSIString {
    ansi_term::Colour::Yellow.bold().paint(s)
}
#[cfg (not(target_os = "windows"))]
pub fn green(s: &str) -> Painted<&str> {
    Color::Green.paint(s)
}
#[cfg (not(target_os = "windows"))]
pub fn bold(s: &str) -> Painted<&str> {
    Bold.paint(s)
}
#[cfg (target_os = "windows")]
pub fn red(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn yellow(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn green(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn bold(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}

#[cfg(test)]
mod tests {
    use super::check_content;
    use super::TRAILING_SPACES;
    use super::HAS_TABS;
    use super::HAS_ILLEGAL_CHARACTERS;
    use super::LINE_TOO_LONG;
    use super::InfoLevel;
    use clean::TabStrategy::Untabify;
    use clean::TabStrategy::Tabify;
    use std::sync::mpsc::sync_channel;

    #[test]
    fn test_check_good_content() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = " 1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_good_content_with_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "\t1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_good_content_with_box_drawing() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = r#"
                     ▲
                     │
                     ▼
            ┌────────S────────┐
            │░░░░░░░░░░░░░░░░░│
            │░Internal memory░│
            │░░░░░░░░░░░░░░░░░│
            └─────────────────┘
            "#;

        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();

        // There are trailing spaces in the string literal, but otherwise it's good
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_bad_content_with_illegal_characters() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = r#"
            Бл҃же́нъ мꙋ́жъ, и҆́же не и҆́де на совѣ́тъ нечести́выхъ,
            и҆ на пꙋтѝ грѣ́шныхъ не ста̀, и҆ на сѣда́лищи гꙋби́телей
            не сѣ́де: но въ зако́нѣ гдⷭ҇ни во́лѧ є҆гѡ̀, и҆ въ зако́нѣ
            є҆гѡ̀ поꙋчи́тсѧ де́нь и҆ но́щь."#;

        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();

        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) != 0);
    }
    #[test]
    fn test_check_bad_content_with_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "\t1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 1);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_content_trailing_ws() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1 \n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) > 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_content_trailing_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1\t\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) > 0);
        assert!((check & HAS_TABS) > 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_line_too_long() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1234567890\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, Some(5), Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
        assert!((check & LINE_TOO_LONG) > 0);
    }
    #[test]
    fn test_line_not_too_long() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1234567890\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, Some(10), Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
        assert!((check & LINE_TOO_LONG) == 0);
    }
}
<commit_msg>Change info level for encoding errors<commit_after>use std;
use std::io;
use std::path::Path;
use std::fs::File;
use std::fs::metadata;
use std::io::prelude::*;
use ansi_term;
use unic_char_range::CharRange;

use term_painter::{ToStyle, Color, Painted};
use term_painter::Attr::*;

use std::sync::mpsc::SyncSender;
use clean;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum InfoLevel {
    Quiet,
    Normal,
    Verbose,
}

static UTF8_ALLOWED_RANGES: &'static [CharRange] = &[
    // Basic Latin
    CharRange { low: '\u{0000}', high: '\u{007f}' },
    // Latin supplement -- without control characters and no-break space
    CharRange { low: '\u{00a1}', high: '\u{00ff}' },
    // Latin extended A
    CharRange { low: '\u{0100}', high: '\u{017f}' },
    // Latin extended B
    CharRange { low: '\u{0180}', high: '\u{024f}' },
    // Box drawing
    CharRange { low: '\u{2500}', high: '\u{257f}' },
    // Block elements
    CharRange { low: '\u{2580}', high: '\u{259f}' },
    // Geometric shapes
    CharRange { low: '\u{25a0}', high: '\u{25ff}' },
];

pub const HAS_TABS: u8 = 1 << 0;
pub const TRAILING_SPACES: u8 = 1 << 1;
pub const HAS_ILLEGAL_CHARACTERS: u8 = 1 << 2;
pub const LINE_TOO_LONG: u8 = 1 << 3;

fn check_content<'a>(input: &'a str,
                     filename: &str,
                     info_level: InfoLevel,
                     max_line_length: Option<usize>,
                     s: clean::TabStrategy,
                     logger: SyncSender<Option<String>>)
-> io::Result<u8> {
    let mut result = 0;
    let mut i: u32 = 0;
    for line in input.lines() {
        i += 1;
        max_line_length.map(|max_len| if line.len() > max_len {
            result |= LINE_TOO_LONG;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: LINE_TOO_LONG\n", filename, i)));
            }
        });
        if line.ends_with(' ') || line.ends_with('\t') {
            result |= TRAILING_SPACES;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: TRAILING_SPACES\n", filename, i)));
            }
        }
        if s == clean::TabStrategy::Untabify && line.contains("\t") {
            result |= HAS_TABS;
            if info_level == InfoLevel::Verbose {
                let _ = logger.send(Some(format!("{}, line {}: error: HAS_TABS\n", filename, i)));
            }
        }
        if !line.chars().all(|c| {
            UTF8_ALLOWED_RANGES.iter().any(|range| range.contains(c))
        }) {
            result |= HAS_ILLEGAL_CHARACTERS;
            if info_level == InfoLevel::Verbose {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: non ASCII line\n", filename, i)));
            }
        }
    }
    if info_level == InfoLevel::Normal {
        if (result & LINE_TOO_LONG) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with LINE_TOO_LONG\n", filename)));
        }
        if (result & TRAILING_SPACES) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with TRAILING_SPACES\n", filename)));
        }
        if (result & HAS_TABS) > 0 {
            let _ = logger.send(Some(format!("{}, some lines with HAS_TABS\n", filename)));
        }
        if (result & HAS_ILLEGAL_CHARACTERS) > 0 {
            let _ =
                logger.send(Some(format!("{}, some lines with non ASCII line\n", filename)));
        }
    }
    Ok(result)
}

pub fn is_dir(path: &Path) -> bool {
    if let Ok(result) = metadata(&path) {
        result.is_dir()
    } else {
        false
    }
}

fn report_offending_line(path: &Path, logger: SyncSender<Option<String>>) -> std::io::Result<()> {
    use std::io::BufReader;
    let mut i: u32 = 1;
    let f = File::open(path)?;
    let file = BufReader::new(f);
    for line in file.lines() {
        match line.ok() {
            Some(_) => i = i + 1,
            None => {
                let _ =
                    logger.send(Some(format!("{}, line {}: error: non UTF-8 character in line\n",
                                             path.display(),
                                             i)));
            }
        }
    }
    Ok(())
}

pub fn check_path(path: &Path,
                  buf: &Vec<u8>,
                  clean: bool,
                  info_level: InfoLevel,
                  max_line_length: Option<usize>,
                  s: clean::TabStrategy,
                  logger: SyncSender<Option<String>>)
    -> io::Result<u8> {
        let mut check = 0;
        match std::str::from_utf8(buf) {
            Err(_) => {
                check = check | HAS_ILLEGAL_CHARACTERS;
                if info_level == InfoLevel::Normal {
                    let _ = report_offending_line(path, logger);
                }
                return Ok(check);
            }
            Ok(buffer) => {
                if check == 0 {
                    check = check_content(&buffer,
                                          path.to_str().expect("not available"),
                                          info_level,
                                          max_line_length,
                                          s,
                                          logger.clone())?;
                }
                let no_trailing_ws = if (check & TRAILING_SPACES) > 0 && clean {
                    if info_level == InfoLevel::Verbose {
                        let _ =
                            logger.send(Some(format!("TRAILING_SPACES:[{}] -> removing\n",
                                                     path.display())));
                    }
                    clean::remove_trailing_whitespaces(buffer)
                } else {
                    buffer.to_string()
                };
                let res_string = if (check & HAS_TABS) > 0 && clean {
                    if info_level == InfoLevel::Verbose {
                        let _ = logger.send(Some(format!("HAS_TABS:[{}] -> converting to spaces\n",
                                                         path.display())));
                    }
                    clean::space_tabs_conversion(no_trailing_ws, clean::TabStrategy::Untabify)
                } else {
                    no_trailing_ws
                };
                if clean {
                    let mut file = File::create(path)?;
                    file.write_all(res_string.as_bytes())?;
                }
            }
        };
        // only check content if we could read the file
        Ok(check)
    }

#[allow(dead_code)]
#[cfg (not(target_os = "windows"))]
pub fn red(s: &str) -> ansi_term::ANSIString {
    ansi_term::Colour::Red.bold().paint(s)
}
#[allow(dead_code)]
#[cfg (not(target_os = "windows"))]
pub fn yellow(s: &str) -> ansi_term::ANSIString {
    ansi_term::Colour::Yellow.bold().paint(s)
}
#[cfg (not(target_os = "windows"))]
pub fn green(s: &str) -> Painted<&str> {
    Color::Green.paint(s)
}
#[cfg (not(target_os = "windows"))]
pub fn bold(s: &str) -> Painted<&str> {
    Bold.paint(s)
}
#[cfg (target_os = "windows")]
pub fn red(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn yellow(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn green(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}
#[cfg (target_os = "windows")]
pub fn bold(s: &str) -> ansi_term::ANSIString {
    ansi_term::Style::new().paint(s)
}

#[cfg(test)]
mod tests {
    use super::check_content;
    use super::TRAILING_SPACES;
    use super::HAS_TABS;
    use super::HAS_ILLEGAL_CHARACTERS;
    use super::LINE_TOO_LONG;
    use super::InfoLevel;
    use clean::TabStrategy::Untabify;
    use clean::TabStrategy::Tabify;
    use std::sync::mpsc::sync_channel;

    #[test]
    fn test_check_good_content() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = " 1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_good_content_with_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "\t1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_good_content_with_box_drawing() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = r#"
                     ▲
                     │
                     ▼
            ┌────────S────────┐
            │░░░░░░░░░░░░░░░░░│
            │░Internal memory░│
            │░░░░░░░░░░░░░░░░░│
            └─────────────────┘
            "#;

        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();

        // There are trailing spaces in the string literal, but otherwise it's good
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_bad_content_with_illegal_characters() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = r#"
            Бл҃же́нъ мꙋ́жъ, и҆́же не и҆́де на совѣ́тъ нечести́выхъ,
            и҆ на пꙋтѝ грѣ́шныхъ не ста̀, и҆ на сѣда́лищи гꙋби́телей
            не сѣ́де: но въ зако́нѣ гдⷭ҇ни во́лѧ є҆гѡ̀, и҆ въ зако́нѣ
            є҆гѡ̀ поꙋчи́тсѧ де́нь и҆ но́щь."#;

        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();

        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) != 0);
    }
    #[test]
    fn test_check_bad_content_with_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "\t1\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 1);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_content_trailing_ws() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1 \n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) > 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_check_content_trailing_tabs() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1\t\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, None, Untabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) > 0);
        assert!((check & HAS_TABS) > 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
    }
    #[test]
    fn test_line_too_long() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1234567890\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, Some(5), Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
        assert!((check & LINE_TOO_LONG) > 0);
    }
    #[test]
    fn test_line_not_too_long() {
        let (logging_tx, _) = sync_channel::<Option<String>>(0);
        let content = "1234567890\n";
        let res = check_content(content, "foo.h", InfoLevel::Quiet, Some(10), Tabify, logging_tx);
        assert!(res.is_ok());
        let check = res.unwrap();
        assert!((check & TRAILING_SPACES) == 0);
        assert!((check & HAS_TABS) == 0);
        assert!((check & HAS_ILLEGAL_CHARACTERS) == 0);
        assert!((check & LINE_TOO_LONG) == 0);
    }
}
<|endoftext|>


<commit_before>use alloc::borrow::ToOwned;
use alloc::string::String;

bitflags::bitflags! {
    pub struct FlagsECX: u32 {
        const SSE3         = 1 << 0;
        const PCLMUL       = 1 << 1;
        const DTES64       = 1 << 2;
        const MONITOR      = 1 << 3;
        const DS_CPL       = 1 << 4;
        const VMX          = 1 << 5;
        const SMX          = 1 << 6;
        const EST          = 1 << 7;
        const TM2          = 1 << 8;
        const SSSE3        = 1 << 9;
        const CID          = 1 << 10;
        const FMA          = 1 << 12;
        const CX16         = 1 << 13;
        const ETPRD        = 1 << 14;
        const PDCM         = 1 << 15;
        const PCIDE        = 1 << 17;
        const DCA          = 1 << 18;
        const SSE4_1       = 1 << 19;
        const SSE4_2       = 1 << 20;
        const X2APIC       = 1 << 21;
        const MOVBE        = 1 << 22;
        const POPCNT       = 1 << 23;
        const AES          = 1 << 25;
        const XSAVE        = 1 << 26;
        const OSXSAVE      = 1 << 27;
        const AVX          = 1 << 28;
    }
}

bitflags::bitflags! {
    pub struct FlagsEDX: u32 {
        const FPU          = 1 << 0;
        const VME          = 1 << 1;
        const DE           = 1 << 2;
        const PSE          = 1 << 3;
        const TSC          = 1 << 4;
        const MSR          = 1 << 5;
        const PAE          = 1 << 6;
        const MCE          = 1 << 7;
        const CX8          = 1 << 8;
        const APIC         = 1 << 9;
        const SEP          = 1 << 11;
        const MTRR         = 1 << 12;
        const PGE          = 1 << 13;
        const MCA          = 1 << 14;
        const CMOV         = 1 << 15;
        const PAT          = 1 << 16;
        const PSE36        = 1 << 17;
        const PSN          = 1 << 18;
        const CLF          = 1 << 19;
        const DTES         = 1 << 21;
        const ACPI         = 1 << 22;
        const MMX          = 1 << 23;
        const FXSR         = 1 << 24;
        const SSE          = 1 << 25;
        const SSE2         = 1 << 26;
        const SS           = 1 << 27;
        const HTT          = 1 << 28;
        const TM1          = 1 << 29;
        const IA64         = 1 << 30;
        const PBE          = 1 << 31;
    }
}

pub fn cpu_brand() -> String {
    let mut result = String::new();

    'outer: for index in 0x80000002u32..=0x80000004u32 {
        let eax: u32;
        let ebx: u32;
        let ecx: u32;
        let edx: u32;
        unsafe {
            llvm_asm!(
                "xor ecx, ecx; xor edx, edx; cpuid"
                :
                    "={eax}"(eax), "={ebx}"(ebx),
                    "={ecx}"(ecx), "={edx}"(edx)
                : "{eax}"(index)
                :
                : "intel", "volatile"
            );
            let values = [eax, ebx, ecx, edx];
            for v in values.iter() {
                for i in 0..=3 {
                    let bytepos = i * 8;
                    let byte = ((v & (0xFF << bytepos)) >> bytepos) as u8;
                    if byte == 0 {
                        break 'outer;
                    }
                    result.push(byte as char);
                }
            }
        }
    }
    result.trim().to_owned()
}

fn run_feature_checks(_ecx: u32, _edx: u32) {
    // TODO
}

pub fn init() {
    let ecx: u32;
    let edx: u32;
    unsafe {
        // CPUID_GETFEATURES
        llvm_asm!(
            "xor ecx, ecx; xor edx, edx; mov eax, 1; cpuid"
            : "={ecx}"(ecx), "={edx}"(edx)
            :
            : "eax", "ebx"
            : "intel", "volatile"
        );
    }
    log::debug!("CPU: {}", cpu_brand());
    log::debug!("CPU: FEATURE BITS: {:b} {:b}", ecx, edx);
    run_feature_checks(ecx, edx);
}
<commit_msg>Check that required cpu features are available<commit_after>use alloc::borrow::ToOwned;
use alloc::string::String;

bitflags::bitflags! {
    pub struct FlagsECX: u32 {
        const SSE3         = 1 << 0;
        const PCLMUL       = 1 << 1;
        const DTES64       = 1 << 2;
        const MONITOR      = 1 << 3;
        const DS_CPL       = 1 << 4;
        const VMX          = 1 << 5;
        const SMX          = 1 << 6;
        const EST          = 1 << 7;
        const TM2          = 1 << 8;
        const SSSE3        = 1 << 9;
        const CID          = 1 << 10;
        const FMA          = 1 << 12;
        const CX16         = 1 << 13;
        const ETPRD        = 1 << 14;
        const PDCM         = 1 << 15;
        const PCIDE        = 1 << 17;
        const DCA          = 1 << 18;
        const SSE4_1       = 1 << 19;
        const SSE4_2       = 1 << 20;
        const X2APIC       = 1 << 21;
        const MOVBE        = 1 << 22;
        const POPCNT       = 1 << 23;
        const AES          = 1 << 25;
        const XSAVE        = 1 << 26;
        const OSXSAVE      = 1 << 27;
        const AVX          = 1 << 28;
    }
}

bitflags::bitflags! {
    pub struct FlagsEDX: u32 {
        const FPU          = 1 << 0;
        const VME          = 1 << 1;
        const DE           = 1 << 2;
        const PSE          = 1 << 3;
        const TSC          = 1 << 4;
        const MSR          = 1 << 5;
        const PAE          = 1 << 6;
        const MCE          = 1 << 7;
        const CX8          = 1 << 8;
        const APIC         = 1 << 9;
        const SEP          = 1 << 11;
        const MTRR         = 1 << 12;
        const PGE          = 1 << 13;
        const MCA          = 1 << 14;
        const CMOV         = 1 << 15;
        const PAT          = 1 << 16;
        const PSE36        = 1 << 17;
        const PSN          = 1 << 18;
        const CLF          = 1 << 19;
        const DTES         = 1 << 21;
        const ACPI         = 1 << 22;
        const MMX          = 1 << 23;
        const FXSR         = 1 << 24;
        const SSE          = 1 << 25;
        const SSE2         = 1 << 26;
        const SS           = 1 << 27;
        const HTT          = 1 << 28;
        const TM1          = 1 << 29;
        const IA64         = 1 << 30;
        const PBE          = 1 << 31;
    }
}

pub fn cpu_brand() -> String {
    let mut result = String::new();

    'outer: for index in 0x80000002u32..=0x80000004u32 {
        let eax: u32;
        let ebx: u32;
        let ecx: u32;
        let edx: u32;
        unsafe {
            llvm_asm!(
                "xor ecx, ecx; xor edx, edx; cpuid"
                :
                    "={eax}"(eax), "={ebx}"(ebx),
                    "={ecx}"(ecx), "={edx}"(edx)
                : "{eax}"(index)
                :
                : "intel", "volatile"
            );
            let values = [eax, ebx, ecx, edx];
            for v in values.iter() {
                for i in 0..=3 {
                    let bytepos = i * 8;
                    let byte = ((v & (0xFF << bytepos)) >> bytepos) as u8;
                    if byte == 0 {
                        break 'outer;
                    }
                    result.push(byte as char);
                }
            }
        }
    }
    result.trim().to_owned()
}

macro_rules! assert_feature {
    ($register:expr, $feature:expr) => {
        assert!(
            $register.contains($feature),
            "Unsupported CPU: Feature {:?} missing",
            $feature
        );
    };
}

fn run_feature_checks(ecx: u32, edx: u32) {
    let f_ecx = FlagsECX::from_bits_truncate(ecx);
    let f_edx = FlagsEDX::from_bits_truncate(edx);

    assert_feature!(f_edx, FlagsEDX::SSE);
    assert_feature!(f_edx, FlagsEDX::APIC);
}

pub fn init() {
    let ecx: u32;
    let edx: u32;
    unsafe {
        // CPUID_GETFEATURES
        llvm_asm!(
            "xor ecx, ecx; xor edx, edx; mov eax, 1; cpuid"
            : "={ecx}"(ecx), "={edx}"(edx)
            :
            : "eax", "ebx"
            : "intel", "volatile"
        );
    }
    log::debug!("CPU: {}", cpu_brand());
    log::debug!("CPU: FEATURE BITS: {:b} {:b}", ecx, edx);
    run_feature_checks(ecx, edx);
}
<|endoftext|>